news 2026/9/27 23:39:42

铁路轨道缺陷数据集:VOC标注转YOLO格式的裂缝与间隙检测指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
铁路轨道缺陷数据集:VOC标注转YOLO格式的裂缝与间隙检测指南

简介:铁路轨道缺陷检测数据集,面向计算机视觉目标检测研究者与智慧铁路维护工程师,旨在训练可自动识别轨道裂缝、间隙等缺陷的模型。压缩包为zip格式,内共2000个文件,全部为PASCAL VOC XML格式的标注数据,包体约273.84MB。该格式通用性强,可被LabelImg等标注工具直接打开验证,XML内记录目标类别与边界框位置,能直接引入YOLO、Faster R-CNN、SSD等主流检测框架训练与评估,省去标注环节。文件名中的aug_prefix等前缀表明包含大量数据增强样本的对应标注,可有效扩充正负样本,增强模型泛化性;同时可配合配套博文获取原始图片,完成完整数据集构建。目前已有1688人学习下载,适用于工业质检、轨道交通巡检、桥梁隧道结构监测等场景,也可作为目标检测课程设计或算法对比实验的基础数据。

1. 铁路轨道缺陷数据集到底是什么:4278张原始图能支撑什么样的裂缝与间隙检测

拿到这份铁路轨道缺陷数据集,建议先别为4278张原始图的数量高兴得太早。轨道缺陷检测真正耗时间的从来不是有没有数据,而是标注能不能信、能不能顺利喂进模型。这套数据的特点是每张轨道图都带一份PASCAL VOC格式的XML标注(标题里的PASICAL是笔误,文件结构就是标准VOC),标注目标有两类:裂缝(crack)和间隙缺陷(gap)。拿到手就把最苦的数据标注阶段跨过去了,可以直接做目标检测训练、验证和二次补标。

它适合钢轨表面裂缝识别、轨道结构巡检的算法工程师与在读研究生。可以用它训练YOLO系、Faster R-CNN或SSD,也可以拿它当基座,叠加自己采集的夜轨、隧道图继续扩充。先按标题给出的出处下载核对,解压后第一件事是数文件。好不好用,取决于你能不能把VOC XML干净地转成训练框架要的格式,以及能不能绕开小目标裂缝后面那一串坑。

2. 认识数据集:VOC XML标注结构、两类缺陷的标注边界与类别分布

2.1 PASCAL VOC XML的标注字段:一张轨道图对应一个XML文件

VOC数据集的目录约定非常固定,常见的是JPEGImages放原图,Annotations放同名XML。这套轨道缺陷数据集如果沿用同样约定,你会看到类似下面的结构:

rail-track-defect/ ├── JPEGImages/ │ ├── img_00001.jpg │ ├── img_00002.jpg │ └── ... ├── Annotations/ │ ├── img_00001.xml │ ├── img_00002.xml │ └── ... └── ImageSets/ └── Main/

我一般拿到手第一件事就是核对JPEGImages里jpg数量和Annotations里xml数量是否一致,都是4278最好。缺一个,训练时就会在某个epoch报KeyError,让你误以为代码写错了,实际上是数据文件没对齐。

打开任意一个XML,典型的VOC结构长这样:

<annotation> <folder>JPEGImages</folder> <filename>img_00001.jpg</filename> <size> <width>1920</width> <height>1080</height> <depth>3</depth> </size> <object> <name>crack</name> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>512</xmin> <ymin>400</ymin> <xmax>580</xmax> <ymax>448</ymax> </bndbox> </object> </annotation>

训练脚本里一般只用name、bndbox和size,但truncated和difficult会影响你要不要把某个框计入训练。关键字段的处置方式参考下表:

字段含义训练时处置
filename图片文件名拼接图片路径的依据,注意Windows反斜杠
size.width/height/depth原图尺寸与通道数归一化坐标时要用
name类别名,crack或gap必须与类别映射表严格一致
truncated目标是否被图像边界截断轨道场景里可保留,也可过滤
difficult难例标记,1表示很难判别推荐保留但单独评估,别直接删
bndboxxmin/ymin/xmax/ymax整数像素转YOLO时唯一要换算的坐标

提示:VOC和YOLO的坐标都是像素值,但VOC给的是绝对像素,YOLO要的是相对于宽高的比例,具体换算放在第4章细说。

2.2 裂缝与间隙缺陷的界定:标注框长什么样,容易混的框是哪类

两类缺陷的形态差别很大,理解它,后续做增广和调anchor才有依据。裂缝(crack)标注框几乎都是细长条,短边可能只有十几像素,长边却有几十上百像素,长宽比常常大于5,甚至超过10。它对应的是轨面或轨腰上的疲劳裂纹,放大看是一条不规则的线,框往往是斜着包的,所以XY轴对齐框里会带不少背景。

间隙缺陷(gap)在轨道上通常指轨缝异常、接头错位或扣件区段的非正常间距。它和裂缝最大的区别是:裂缝是“材料裂了”,间隙是“结构分开了”。间隙的框一般面积更大、形状更接近方块或横向长条,不会像裂缝那样瘦。

最容易混淆的是“裂缝末端伴有间隙”的复合缺陷。如果你在补标阶段拿不准,我的习惯是把这类框的difficult置1,让模型学习,但评估时单独算,别混在干净类里拉低均值。标注的难点在于:裂缝是小目标,间隙是大目标,两类在同一个尺度下训练,天然有尺度冲突。这直接决定了后期要么用原分辨率训练,要么做切片。

2.3 用Python统计4278张图的类别分布与框尺寸

不要直接开训。先写一个统计脚本,搞清楚类别数量、每张图的框数分布、框宽高的中位数。这个脚本十分钟能写完,却能帮你避免后面好几个小时的定位排错。

import os import xml.etree.ElementTree as ET from collections import Counter xml_dir = "rail-track-defect/Annotations" files = sorted(os.listdir(xml_dir)) cls_counter = Counter() box_per_image = [] widths, heights = [], [] for f in files: if not f.endswith(".xml"): continue tree = ET.parse(os.path.join(xml_dir, f)) root = tree.getroot() objs = root.findall("object") box_per_image.append(len(objs)) for obj in objs: name = obj.find("name").text.strip().lower() cls_counter[name] += 1 bndbox = obj.find("bndbox") xmin = float(bndbox.find("xmin").text) ymin = float(bndbox.find("ymin").text) xmax = float(bndbox.find("xmax").text) ymax = float(bndbox.find("ymax").text) widths.append(xmax - xmin) heights.append(ymax - ymin) print("xml数量:", len(files)) print("类别分布:", dict(cls_counter)) print("单图框数 均值/中位数:", sum(box_per_image) / len(box_per_image), sorted(box_per_image)[len(box_per_image) // 2]) print("框宽中位数:", sorted(widths)[len(widths) // 2]) print("框高中位数:", sorted(heights)[len(heights) // 2])

这段脚本做的事情:遍历Annotations下所有XML,逐个解析出object的name和bndbox,把类别名统一转小写后计数,同时记录每张图的框数以及每个框的宽高。输出结果基本决定了后续策略。如果裂缝框宽中位数只有15像素,输入尺寸小于640就是灾难;如果gap和crack的框数比例超过3比1,就要在采样上下功夫。

参数说明:xml_dir换成你解压后的实际路径;统计粒度最好按训练集和验证集分两次跑,别混在一起。遇到某个XML没有object,这段脚本不会报错,会计入0框,这种“空XML”在转换阶段要单独处理。假定统计结果是crack有6000框、gap有2000框,单张图平均2.1个框、最大9个框,这种偏态分布就该做类别重采样。如果反过来gap远多于crack,说明数据集侧重轨缝巡检,训练时要注意别让gap主导loss。

3. 标注工具回看与二次标注:LabelImg、CVAT和labelme哪个能直接吃VOC XML

3.1 目标检测常用标注工具对VOC的支持程度

很多人拿到标好的数据集就直接训练了,这是浪费。你应该先抽20到50张在标注工具里肉眼过一遍,看有没有错框、漏框和越界框。目标检测常用标注工具里,能直接吃VOC XML的有三个梯队:

工具打开VOC方式导出格式适合场景
LabelImg直接Open XML DirVOC XML / YOLO txt本地单机快速回看、补标
CVAT导入VOC XML任务VOC / YOLO / COCO团队协作、分人质检
labelme原生只认json,需要转JSON / 可转VOC做多边形标注、实例分割时

CVAT标注工具和LabelImg在轨道场景里的地位很难互相替代:LabelImg胜在轻量、打开目录即用;CVAT胜在能按类别筛选、能多人标注、能导出时过滤difficult。如果只为了复查4278张图,我一般用LabelImg;如果要让两个实习生一起补标注,就上CVAT。

3.2 用LabelImg回看和补标:打开XML目录的操作

LabelImg的用法关键词是“Open Dir”和“Open XML Dir”配对。具体步骤:

  1. 打开LabelImg,左侧工具栏点击Open Dir,选择JPEGImages目录。
  2. 点击Open XML Dir,选择Annotations目录,保证XML文件名与jpg文件名一一对应。
  3. 顶部PascalVOC按钮要处于选中态,这样保存时默认写VOC XML。
  4. 翻图检查。看到明显框错的用Edit Rect拖动;看到漏检的用Create Rect画新框,类别从右侧列表选crack或gap。
  5. 保存时LabelImg会写回XML。

这里有个常见坑:LabelImg对中文路径支持不好。如果你把数据集放在“D:\轨道缺陷\”这种带中文的路径下,保存时可能报“could not open annotation file”。解决很简单,数据集目录一律用英文、不要带空格。这也是数据标注的通用规矩,目录命名里出现中文,后面任何脚本都可能翻车。

3.3 用CVAT做批量质检:导入VOC XML后按类别筛选

如果数据集要交给多人复核,CVAT比LabelImg合适。我不细讲服务器部署,只说导入、导出和质检这两条链路。

导入时在CVAT里创建新任务,数据选择JPEGImages里的图片,下方Label列表填crack、gap。创建后在任务列表点Open,再通过Upload annotations把某个VOC XML传进去,CVAT会按filename把框对回图片。质检时最该用的是Filter功能:在标注画布右侧按name字段筛选出crack,快速翻一遍,确认没有把钢轨扣件阴影误标成裂缝;再筛选gap,确认正常轨缝没有被标成缺陷。导出时选择Pascal VOC 1.1格式,CVAT会把所有任务里的标注合并导出一份大XML,回到第2章的脚本重建Annotations目录即可。

3.4 从labelme标注到VOC再到YOLO的链路

经常有人问labelme标注用于yolov8怎么弄。labelme原生保存的是JSON,每个JSON里有shape_type(rect或polygon)和points。如果你的新数据是用labelme画的矩形框,要进这个轨道数据集的VOC体系,得先把JSON转成VOC XML;如果直接进YOLO,第一次用labelme标注用于yolov8时容易卡在“坐标没归一化”上。

我一般这样做转换:读labelme JSON里的points,矩形框取第一个点和第二个点组成对角,除以JSON里的imageWidth和imageHeight,得到归一化的cx、cy、w、h,再按类别编号写txt。如果你想保持VOC统一管理,就先转XML再走第4章的脚本,好处是后面想换框架时数据源统一,不用再返工。

到这里你就知道,第3章这些工具不是给你从零标4278张图用的,而是用来“回看、补标、复核”。做完这一步,才轮到最核心的动作:格式转换。

4. 把VOC转成YOLO格式:转换脚本与四个边界坑

4.1 转换脚本:用xml.etree.ElementTree解析并生成归一化txt

YOLO的标注格式是每张图一个txt,每行代表一个目标:class_index cx cy w h,四个坐标都归一化到[0,1]。下面是我常用的转换脚本,兼容Python 3.6以上,不需要额外依赖:

import os import glob import xml.etree.ElementTree as ET # 参数区:只改这里 voc_xml_dir = "rail-track-defect/Annotations" jpg_dir = "rail-track-defect/JPEGImages" yolo_txt_dir = "rail-track-defect/labels" class_names = ["crack", "gap"] # 顺序就是类别编号,别随意换 min_side_pixel = 8 # 过滤太小的框,轨道裂缝常见极端细条 def voc2yolo(xml_file, jpg_dir, yolo_txt_dir, class_names): tree = ET.parse(xml_file) root = tree.getroot() filename = root.find("filename").text img_width = int(root.find("size").find("width").text) img_height = int(root.find("size").find("height").text) txt_name = os.path.splitext(filename)[0] + ".txt" txt_path = os.path.join(yolo_txt_dir, txt_name) if os.path.exists(txt_path): os.remove(txt_path) lines = [] for obj in root.findall("object"): name = obj.find("name").text.strip().lower() if name not in class_names: print("未知类别:", filename, name) continue cls_id = class_names.index(name) bndbox = obj.find("bndbox") xmin = float(bndbox.find("xmin").text) ymin = float(bndbox.find("ymin").text) xmax = float(bndbox.find("xmax").text) ymax = float(bndbox.find("ymax").text) # 过滤极端小框,防止归一化后数值小到被下采样吃掉 if (xmax - xmin) < min_side_pixel or (ymax - ymin) < min_side_pixel: continue # 裁剪越界坐标到图像边界 xmin = max(0.0, min(xmin, img_width - 1)) ymin = max(0.0, min(ymin, img_height - 1)) xmax = max(0.0, min(xmax, img_width - 1)) ymax = max(0.0, min(ymax, img_height - 1)) # YOLO:框中心 + 宽高,全部归一化 cx = ((xmin + xmax) / 2.0) / img_width cy = ((ymin + ymax) / 2.0) / img_height w = (xmax - xmin) / img_width h = (ymax - ymin) / img_height # 浮点保留位数:6位足够,多了徒增文件体积 lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") if lines: with open(txt_path, "w", encoding="utf-8") as f: f.write("\n".join(lines)) xml_files = glob.glob(os.path.join(voc_xml_dir, "*.xml")) os.makedirs(yolo_txt_dir, exist_ok=True) for xmlf in xml_files: voc2yolo(xmlf, jpg_dir, yolo_txt_dir, class_names) print("转换完成,共处理", len(xml_files), "个XML")

转换完成后,随便打开一个生成的txt看,格式应该是“0 0.2543 0.4012 0.0312 0.0521”这样一行。

4.2 逻辑说明与参数:类别映射、图像路径、min_size过滤

上面代码里最值得你调的是class_names的顺序。YOLO的类别编号不是字符串,而是列表下标,crack对应0,gap对应1,这个顺序要原样带进训练配置data.yaml里,否则模型学到的类别和你的认知对不上。jpg_dir参数在脚本里目前只用于占位,实际目录统一管理时可以拿它拼绝对路径,替换掉XML里的相对路径。

min_side_pixel默认8,指像素,不是归一化值。轨道裂缝很多标注框短边只有几像素,过滤太狠会直接丢掉真样本,太松又会产生大量训练噪音。我的经验是先跑一遍第2章的统计脚本,看短边分布,低于P5百分位的才设成阈值。如果你用的图分辨率是1920x1080,8到12像素是合理起点。

另外脚本里“未知类别”分支只打印不中断,这个设计是有意的。很多VOC XML里会出现类别名大小写混写、或者多一个空格,比如“ Crack”。如果直接报错退出,你就要在4278个XML里人肉找脏数据;先打印出来,集中看一遍,再回头统一清洗。我实际跑下来,最脏的往往不是crack和gap本身,而是标漏的gap被写成了gaps或final_gap。

提示:转换完成后不要急着删Annotations。YOLO txt一旦丢了几列,原始XML还在,可以从头再转。XML是后悔药,txt不是。

4.3 四个边界坑:标签大小写、difficult框、坐标越界、空XML

这四个坑,依次说现象、原因和解决。

第一个是标签大小写不统一。现象:训练时类别总数莫名变成4个,精度一路玄学波动。原因:部分XML里写Crack,部分写crack,框架把大小写当成两个不同类。解决:转换脚本里强制name.strip().lower(),同时在统计脚本里把类别名打印出来核对一遍。统一用全小写是数据标注环节就该遵守的约定。

第二个是difficult与truncated框的去留。现象:验证集mAP比预期高,但实际场景推理时全是误检。原因:训练框里混着一堆不完整目标,模型学会了“不完整的钢轨也判缺陷”。解决:把difficult=1的框单独复制一份,训练集可用,但验证集过滤掉。做研究要比数,就把difficult框单拎出来做一个hard_set。

第三个是坐标越界。现象:转换后出现负数cx或大于1的w。原因:标注时框拖出画布边缘,或是从其他软件导出的坐标本身就超了。解决:用上面代码的clip逻辑,把xmin/xmax/ymin/ymax夹到图像边界内;clip后如果w或h变成0,这个框直接丢弃。别只在YOLO里夹,训练框架很可能直接报AssertionError。

第四个是空XML和完全无目标的背景图。现象:某一张jpg在labels目录找不到对应的txt,训练时图像和标签对不齐。原因:XML里一个object都没有,脚本的lines为空就不写文件。解决:空XML也生成一个空txt文件,文件大小为0,这能让YOLO按背景图参与训练,学习“这张图没有缺陷”,对抑制误检有帮助。很多铁路图是净空的轨枕和道床,这恰恰是模型最需要的负样本。

5. 训练前的避坑清单:标注质量、类别不平衡与小目标漏检

5.1 裂缝框过细导致训练翻车:不要直接用640输入

现象:训练loss正常下降,验证集上gap的mAP到了0.85,crack只有0.4。把预测结果可视化出来,大片裂缝没被框上。

原因:裂缝的框瘦长,短边经常不足10像素。在YOLO的输入尺寸缩放里,短边被压缩到1到2个像素,特征图上的细节基本消失。这不是模型问题,是输入分辨率配不上目标尺度。

解决:先把输入尺寸从640提到1280甚至原图尺寸。用ultralytics训练时就是imgsz=1280;显存不够就调小batch。仍然漏检的,用SAHI做切片推理,把原图切成512x512的重叠patch,每个patch单独预测再合并。轨道场景我验证下来,切片的收益远比换更大模型明显。

5.2 两个类别的框数差距太大:按类别重采样

现象:统计脚本显示crack有6000框,gap只有1800框,训练后gap类的召回率一直拉不上去。

原因:类别不平衡让loss被多数类主导,少数的gap即使预测错也对总体loss贡献不大。

解决:常见做法是给训练集按类别做重采样,随机复制gap较多的图片,或者用copy-paste增广把gap框贴到无缺陷背景图上。不要只追求目录文件数量一致,目标检测里“框数平衡”比“张数平衡”更重要。只复制图片不打乱,容易让同一条钢轨在训练集里反复出现造成过拟合,记得配合平移、翻转一起做。

5.3 间隙缺陷的尺度横跨太大:固定anchor不如无anchor

现象:gap框从几十像素到几百像素都有,用YOLOv5固定anchor,训练日志里最佳召回率始终到不了理想值。

原因:anchor预设聚不到跨度这么大的分布。轨道上的gap既可能是扣件段的小缝隙,也可能是接头处的大错位。

解决:优先用anchor-free的检测头,这样能省掉anchor聚类这一步;如果非要用带anchor的版本,先用数据集的框宽高做k-means聚类生成anchor,别用COCO预设。聚类结果会和COCO预设相差很远,因为轨道缺陷的框普遍比自然图像小。

5.4 直接随机split让验证集失真:按序列分层划分

现象:随机把4278张图按8比2分成训练和验证,验证集mAP虚高0.06以上,换一次随机种子结果波动特别大。

原因:轨道图是连续巡线拍摄的,相邻图高度相似。随机划分会把同一段钢轨的相似图同时塞进训练和验证,验证等于开卷考试。

解决:先按文件名前缀或拍摄时间把图分成若干序列,同一个序列的所有图必须落在同一个集合里。再做按类别分层,保证验证集里crack和gap的框数比例和全量一致。这个操作写进数据划分脚本,不要每次训练手动拖。

6. 从4278张图到可用模型:最小训练配置与验收技巧

6.1 最小训练配置:rail.yaml与train命令

先写数据集配置文件,以ultralytics YOLO系为例,版本号以你本地pip装好的为准:

path: D:/rail-track-defect train: images/train val: images/val nc: 2 names: 0: crack 1: gap

这里train和val指向整理好的子目录,把第4章转换出来的txt按同样的子目录结构放好:images/train/xxx.jpg和labels/train/xxx.txt一一对应。之前转换脚本输出的是扁平labels目录,训练前要按8比2重新分目录,划分时用第5章的分层逻辑。训练命令我一般写成:

yolo detect train data=rail.yaml model=yolov8s.pt imgsz=1280 epochs=150 batch=8 lr0=0.01

逐项看参数:imgsz=1280是轨道小目标的关键,不要怕慢,先用小模型验证pipeline;batch=8按显存调,12G显存够跑,不够就减到4;epochs=150对这种四五千张的中等规模数据集足够,前50轮看loss如果明显过拟合,优先降epoch而不是升batch。

6.2 验收技巧:在原始分辨率上做切片检查

训练完先别急着交差。我的验收动作固定在三个:第一,用训练好的模型对原图直接预测,imgsz设成原图最接近的1280,保存预测图,人工看裂缝多不多漏检。第二,把漏检样本的框短边尺寸统计出来,看是不是集中在15像素以下。如果是,说明模型尺度学到位了,是分辨率不够,直接上SAHI切片。第三,挑20张完全无缺陷的净空轨枕图,数误报框,这决定模型能不能上线。

最后说一个我的个人习惯:这类缺陷数据集最大的价值不是原始图片数量,而是XML标注里沉淀下来的缺陷形态。我会把转换后的txt和XML都留档,每次调参失败不删数据,只改配置重跑。做过三轮就知道,轨道裂缝检测的瓶颈百分之八十在分辨率,不在网络结构。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 23:39:28

wordpress图片变大图解步骤与避坑指南

wordpress图片变大图解步骤与避坑指南 找建站公司怕被坑高价?别急,很多看似复杂的服务器问题,其实自己花半小时就能搞定,省下那几千块外包费。今天专门拆解【wordpress图片变大】这个高频痛点,配合清晰的【图解步骤】,让你像老手一样掌控服务器细节,不再为虚高报价买单。…

作者头像 李华
网站建设 2026/9/27 23:39:21

外贸做消防的网站实战案例:避坑指南与前端规范

外贸做消防的网站实战案例:避坑指南与前端规范 上周刚帮一个做出口消防设备的客户紧急处理完一场危机。他们的新站刚上线三天,后台突然收到大量垃圾询盘,首页还莫名其妙挂上了境外博彩链接。老板急得在群里喊救命,问网站被黑挂马不知道怎么办。这种场景在外贸建站圈太常见了,尤其是刚起步的小微企业。…

作者头像 李华
网站建设 2026/9/27 23:39:13

搞定wordpressmd主题:5个图解步骤让官网流量翻倍

搞定wordpressmd主题:5个图解步骤让官网流量翻倍 网站做好了没人访问,这是建站圈最扎心的现实。很多老板花几万块做完了官网,上线三个月后台全是零,问就是“百度不收录”。其实问题往往出在最基础的主题配置上,尤其是WordPress…

作者头像 李华
网站建设 2026/9/27 23:38:49

中国有几家网络公司?用3个免费工具拆解流量真相

中国有几家网络公司?用3个免费工具拆解流量真相 域名服务器搞不懂,是很多刚入行或接手新盘子的运营最头疼的事。明明网站上线了,后台数据却一片惨淡,或者刚花大价钱买的域名,第二天因为备案问题直接打不开。这时候,盲目去问那些所谓的“大牛”往往得不到实在答案,反而容易踩坑。其实,搞清楚“中国有几家网络公司”…

作者头像 李华
网站建设 2026/9/27 23:38:34

电商app开发定制大概多少钱?老手拆解建站报价内幕

电商app开发定制大概多少钱?老手拆解建站报价内幕 自己不会代码想做网站,是不是打开搜索引擎查到的全是“几千块”或者“几万块”,看得人心里发毛?别慌,这行水确实深,但底牌其实就摆在那儿。今天咱们不整虚的,直接掰开了揉碎了,聊聊 电商app开发定制大概多少钱 ,顺便把那份让人头大的 建站报价…

作者头像 李华