铁路巡检缺陷检测数据集构建全复盘:从标注规则到格式转换

发布时间:2026/10/20 18:09:46
铁路巡检缺陷检测数据集构建全复盘:从标注规则到格式转换 做目标检测项目的朋友常问我一件事模型选哪个性价比最高。放在铁路巡检这个场景里我反而觉得这不是先该考虑的问题。铁轨轨道上的腐蚀、断裂、压痕要是没见过大量真实样本再强的骨干网络也白搭。最近我刚整理完一套智慧交通场景下的铁路巡检缺陷检测数据集2324张图像、15个类别标注格式同时导出了VOC和YOLO两种版本覆盖了缺陷类型以及对应的严重程度分级。这篇文章就是一次完整的复盘从采集清洗、打标规则到格式转换再到训练后反推标注质量把我踩过的坑都摊开讲。写这套数据集的时候我最大的感受是整理数据的功夫一点不比调模型少。尤其像轨道缺陷这种小目标、长尾分布、类别边界又模糊的场景标注规范稍微松一点后面训练出来的模型就会在验证集上给你颜色看。我会从数据源头一步步拆解尽量把每个决策背后的理由也说清楚方便你以后自己造类似数据集时直接照抄思路。1. 铁轨缺陷数据从哪来一次巡检影像的清洗与建档经历1.1 为什么AI巡检的第一道坎是数据而不是模型铁路钢轨是典型的线状结构目标和路面坑槽、桥梁裂缝还不一样。钢轨上的腐蚀、断裂、压痕往往只占画面的很少一部分背景里的石砟、扣件、道床纹理又特别杂乱对比度还不高。人工巡检靠的是老师傅经验同一个锈蚀点在晴天和阴天拍出来可能就被判成两个等级。这种先天模糊性决定了如果数据集本身没有把什么是轻、什么是重严格定义清楚后面训练出来的模型只会更糊涂。2324张图在纯目标检测数据集里不算多但在工业场景里属于很正常的小样本规模。我始终觉得这类数据集的竞争力不在数量而在采集端的质量控制和标注端的标准统一。同样的缺陷一张高分辨率对焦准确的图顶得上十张模糊图这句话在铁轨场景里尤其成立。1.2 采集之后原始图库怎么筛成净样本现场采集设备一般是装在巡检小车或者手持设备上的工业相机帧率一高相邻帧大量重复。我的流程分四步去重按帧间相似度做一次粗筛结构相似度高于阈值的连续帧只保留一张。去模糊计算每张图的拉普拉斯方差低于阈值直接丢。去过曝/欠曝统计灰度直方图两端像素占比高光溢出或死黑的帧不要。保留场景多样性确保同一段钢轨有不同角度、不同光照、不同砟肩背景的变体不让模型过拟合到固定拍摄位。我自己还会额外做一个自动检查统计全图边缘响应密度。轨道缺陷本身就是边缘特征如果一张图边缘响应过低基本就是没拍到有效内容这类样本留着只会稀释训练信号。这套流程走完原始素材可能剩下三四千张最后根据类别均衡性二次挑选才定下2324张作为正式版本。整个过程最耗时的不是自动脚本而是人工过一遍边界帧——比如轻微锈蚀和正常轨面氧化之间的过渡样本删掉觉得可惜留下又怕污染训练集。我的经验是先保留靠标注规则去约束而不是在清洗阶段就一刀切。1.3 2324张的构成说明最终留下来的2324张大部分以轨面区域主导同时包含扣件、道床、焊缝、轨腰等部位样本。图像尺寸在数据集内部做了统一规范没有混杂多套分辨率。和很多公开数据集不同我在整理时特别强调了一点VOC和YOLO两个版本共享同一套图像文件只是标注文件的格式不同。图像目录保持唯一互转只发生在标注层这样后续做格式迁移时永远不会出现图对不上标签的尴尬。训练集和验证集的划分我没有用简单的随机切分而是按场景切。同一个拍摄段位的连续帧会全部划到同一侧避免几乎一模一样的图像同时出现在训练集和验证集里造成精度虚高。这个细节如果你用过巡检连续帧就会发现随机切分下模型验证集AP轻松上0.9一上现场就掉到0.6原因就是两边重复样本太多、模型相当于开卷考试。2. 15个类别怎么定出来的缺陷分级体系背后的打标规则2.1 有没有问题和问题多严重要分开说很多初次做缺陷检测的同学会直接把类别设计成腐蚀断裂压痕三个大类然后让模型同时预测位置和类别。这么做不是不能用但在铁轨场景下会很快遇到瓶颈轻度腐蚀和中度腐蚀在像素形态上可能只差一点点模型学到的特征边界会非常不稳定。而压痕本身又是一类总称轨头压溃、波磨、擦伤形态完全不同混在一个类别里会让回归框忽大忽小。所以我在设计15类的时候采用了一个复合结构缺陷大类决定这是什么东西严重程度决定这个东西多严重再配合发生部位把同一大类拆成不同子类。这样类别之间既保持了语义区分度又方便后续在业务侧做不同处理。2.2 一份可复用的15类清单示例这套数据集的具体类别命名在整理时做过微调但大致可以归纳为下面这种结构你在自己项目里也可以按同样思路设计缺陷大类细分类别典型特征说明严重程度腐蚀轻度腐蚀表面浮锈、局部变色未见剥落低腐蚀中度腐蚀锈蚀成片、表面粗糙、有起皮趋势中腐蚀重度腐蚀大面积剥落掉块、截面明显减薄高断裂轨面裂纹轨头表面线性裂纹需要补光才能看清高断裂轨腰裂纹轨腰部位横向或斜向裂纹高断裂螺栓孔裂纹接头螺栓孔附近放射状裂纹危险度极高高断裂完全断裂轨道彻底断开错位样本极其稀有极高压痕轨头压溃轨头塑性变形、下塌压宽中压痕波磨接触面周期性波浪状磨耗中压痕擦伤轨面局部擦伤发白呈鱼鳞状中扣件扣件缺失弹条/扣件丢失高扣件扣件断裂弹条断裂失效高背景参考正常轨面无明显缺陷用于减少误报无背景参考异物侵入轨面异物、杂草覆盖低背景参考焊缝异常焊缝部位凸起或凹陷异常中这个清单能凑够15类不是随手拍的。背景参考这几类很多人会忽略我强烈建议一定要加。它们让模型学到什么才算正常能让误检率明显降下来。异物侵入和焊缝异常在实际巡检里出现频繁单列出来也方便后续单独做决策。2.3 标注一致性的核心等级边界不能靠感觉类别清单定了只是第一步更难的是让标注员在轻度和中度之间做出一致判断。如果只给一句描述锈蚀较重三个人能标出三种结果。我给每个等级都配了量化的界定标准腐蚀类按锈蚀区域占目标面比例覆盖小于10%为轻度10%到30%为中度超过30%为重度。裂纹类按裂纹长度50毫米以内为轻度50到200毫米为中度超过200毫米或疑似贯通为重度和断裂。压痕类重点看形变量给出框时参考轨头基准线明显低于基准线才算压溃。量化标准还有一个附带好处标注框的边界更容易统一。比如腐蚀区域覆盖30%框就框住整个腐蚀斑块不会出现有人框大斑、有人框核心斑的情况。我在标注规范文档开头就写了一句先判断等级再画边界框。等级判断依据的是面积占比、裂纹长度或形变量不是主观印象。这句话能减少大量返工。标注完成后我还让两个标注员分别在互不可见的情况下标了一遍同批次抽样图然后计算一致性。框的交并比大于等于0.5且类别一致才算命中一致率低于0.8的类别要重新开培训会把典型误判案例拉出来逐张讲清楚。3. 2324张样本的真实分布小目标长尾问题的训练对策3.1 长尾分布下平均精度被谁拖垮2324张图按15类去分表面看平均每类一百多张实际上分布很不均匀。轻度腐蚀、正常轨面这类样本量大重度腐蚀、完全断裂、螺栓孔裂纹这类样本极其稀少。模型在训练时会天然偏向高频类别稀疏类别学不到足够的特征最终表现就是平均mAP被几个稀有类拖得很惨。我在训练初版模型时深有体会完全断裂类别的AP基本为零不是因为模型结构不行是因为整个训练集里这类框太少。所以第一件要做的事不是调参而是统计类别分布用柱状图把每个类别的实例数拉出来看。看到分布曲线是长尾的就老老实实针对尾部设计策略。3.2 增强策略先保缺陷可见再做多样性铁轨缺陷是小目标增强策略和通用目标检测不太一样。先做像素级增强再做几何增强。硬度排序大概是这样的亮度/对比度/HSV扰动对光照变化很有效而且不会改变框位置。随机水平翻转和小角度旋转铁轨方向基本是横向或纵向翻转不会破坏语义。随机裁剪和缩放对小目标非常危险裁剪区域稍微偏一点就把缺陷切掉了必须控制范围。Mosaic类增强YOLO系常用但对缺陷占比小的图效果不稳定我建议谨慎。这里有个很反直觉的经验把增强开得很猛训练loss降得很快验证集AP却不升反降。原因多半是增强把本来就小的缺陷区域破坏掉了。我的做法是先只开像素级增强跑一个基线确认没问题之后逐步加几何增强每加一项就看一次验证集AP。另外高分辨率图像和模型输入尺寸不匹配是一个隐藏杀手。原始巡检图像可能有两三千万像素直接下采样到640×640缺陷区域可能就剩下几个像素。这种情况下我建议用分块推理或者先做ROI区域裁剪再入模型不要让训练样本在预处理阶段就丢掉关键信息。3.3 损失函数与采样策略的配合小样本长尾场景里损失函数调整比盲目加数据更可控。常见做法是给稀有类提高分类损失权重权重可以按类别频率倒数的对数做归一化避免某个稀有类权重过大导致普通类完全学不进去。更推荐的做法是先不调损失函数跑一个最普通的基线然后统计混淆矩阵。看看到底是哪些类别之间在互相打架。我在实际项目里发现腐蚀的轻度和中度的混淆跟压痕类之间的混淆原因完全不同。前者是标注边界问题后者是形态相似问题。针对混淆最严重的类别单独调权重比均匀调权重有效得多。还可以在dataloader里做类别敏感采样每个batch保证稀有类别至少出现固定次数。这一点对批次规模小的训练任务尤其重要不然一个batch里全是背景样本梯度方向就被普通类别主导了。4. VOC转YOLO的四个坑坐标、类别表、文件名与二次尺寸校验4.1 XML与TXT的坐标换算差异VOC格式的标注文件是XML框坐标通常写成绝对像素值的xmin、ymin、xmax、ymax。YOLO格式则是每个目标一行文本内容为类别序号加归一化的中心点坐标和宽高。两套坐标体系的换算公式不复杂但细节错了会让你的模型损失一路走低还不知道错在哪import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, img_width, img_height, class_map): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_map: continue cls_id class_map[name] box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center ((xmin xmax) / 2) / img_width y_center ((ymin ymax) / 2) / img_height w (xmax - xmin) / img_width h (ymax - ymin) / img_height lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return \n.join(lines)注意几个容易写错的位置一是除以的是图像的宽和高别把宽高对调二是x_center的计算用的是两个x坐标和的一半不要写成xmin加宽度一半以外的形式虽然数学上等价但写错括号的概率更高三是YOLO文本行的顺序是class、x_center、y_center、width、height有些框架内部用xywh表示别搞混。4.2 类别映射表追加可以重排是大忌VOC里类别名是字符串转成YOLO之后就是整数索引。索引对应关系保存在一个classes.txt文件里这个文件的顺序一旦定下来就不能随意重排。我做数据集的时候吃过一次亏前期类别定义调整把波磨和擦伤在列表里的顺序交换了然后所有已生成的YOLO标签整体错位。训练时loss表现正常但预测结果完全是乱的排查了半天才发现是类别映射表变了。从那以后我给自己定了一条铁律classes.txt只允许在末尾追加新类别中间位置永远冻结。如果需要调整类别必须重新生成全部标签而不是在原文件上改排序。还要提醒一点类别名最好不要包含空格和中文尤其是在多平台流转的场景下空格很容易造成解析错位。建议统一使用英文加下划线的命名方式例如Corrosion_Light、Crack_RailSurface。4.3 文件名匹配和图片二次尺寸校验看起来最基础的事情往往最坑。图像在整理过程中可能被压缩软件重存过尺寸悄悄发生了变化但XML里记录的width和height还是旧值。这时做归一化时用的是图片实际宽高坐标就会整体偏移用XML里声明的宽高又会和图像文件对不上。所以转换前必须做一次图片尺寸校验from PIL import Image # 遍历xml读取size下的width/height与PIL实际读取的宽高比对 # 不一致的需要重新标注或从数据集中剔除文件名匹配也是个细节。我习惯用图像文件的basename作为XML和TXT文件的basename三套文件完全同名的前提下训练代码只管通过basename找对应文件不需要额外维护一份映射表。很多半自动标注工具导出时会自动加后缀比如image1.jpg对应image1.xml和image1_1.txt这类不一致会让训练过程莫名其妙地缺样本。数据文件命名规范在项目第一天就要定死。5. 训练结果反过来揪出标注问题一次漏标事故的排查复盘5.1 症状稀有两类AP低、轻中度互相混淆模型训练到中期的时候我发现验证集表现很反常完全断裂类别的AP值低可以理解但重度腐蚀的AP居然比完全断裂还低中度压痕和重度压痕经常互相误判。一开始我怀疑是模型容量不够换了更大的模型mAP有提升但这两类问题依旧。这时候才意识到问题可能出在数据侧而不是模型侧。于是我开始人工抽查原始标注。随便挑了几十张带有重度腐蚀框的图发现至少有三分之一的重度腐蚀样本其实包含了大量中度区域框把一片锈迹全部包进去严重程度标得很随意。模型学到的不是重度腐蚀长什么样而是大片锈迹都被称作重度腐蚀。这类问题从loss曲线看不出来因为单个框的噪声被batch内的多数样本平均掉了只有按类别分拆指标才能暴露。5.2 逐层排查模型参数、增强策略还是标注本身排查顺序我建议固定下来避免上来就动模型固定随机种子重跑一次训练如果两次结果AP抖动明显大概率是数据集合里噪声太大。把增强策略全部关掉只用原图训练一个小模型。如果精度反而上升说明增强方法破坏了缺陷目标。看每类独立AP而不是只看汇总mAP。这一步能直接定位拖后腿的类别。人工可视化预测结果把置信度中等的预测框和真实框叠加到图像上肉眼扫一遍马上能发现问题。整套流程走完我们最终把锅扣在标注质量上。然后针对重度腐蚀、擦伤和压痕三类做了二次标注复核把不合格框全部重标了一遍。模型的mAP提升非常明显尤其是重度腐蚀这一项AP从0.38涨到0.56。5.3 自动化复核脚本怎么写人工复核费眼睛我写了一个简单脚本帮助缩小范围。思路是统计每个类别内bbox的宽度、高度和长宽比分布同类缺陷的框大小应该相对集中出现大量长宽比离谱的框就是标注时拖拽过头。# 统计每个类别的bbox宽高分布输出异常值候选 # 规则偏离该类中位数3倍IQR的框或长宽比3:1的框单独导出供人工查看另外我还对同类别框做了IoU重叠度分析。如果同一张图里同类别的两个框IoU大于0.6且中心距离很小基本可以判定是同一目标被重复标注。这类重复框会让模型把单一目标预测成两个紧挨的框NMS后剩一个但置信度被拉低影响也不好。自动化脚本不用多复杂能把人工复核的范围缩小到十分之一就足够了。每次标注版本更新后跑一遍这个脚本把输出清单交给标注员自查既省时间又让标准执行更稳定。6. 数据集后续还能怎么用半监督、难例挖掘与域迁移6.1 用现有模型做预标注人工只改错2324张图训练完的模型已经能识别大部分常见缺陷这时候可以把模型当作预标注工具。遇到新采集的图像让模型先出一个预测结果人工只对置信度低于阈值或类别边界模糊的目标进行修正。这套流程在标注人力有限的情况下特别有效原本一个人一天标一百张图预标注之后能轻松标到两百张以上。预标注需要特别注意一点模型预测的框会有系统性偏差比如倾向于把框画得偏大。如果不修正这个偏差新标注数据的框风格就和旧数据不一致最后再训练时会把模型的定位能力带偏。所以预标注结果人工修正时框的边界一定要再看一遍不能因为置信度高就直接放过。6.2 从钢轨迁移到桥梁与管道的可行性钢轨、桥梁拉索、输油管道这类线状结构在缺陷形态上有不少共通点比如都存在表面腐蚀、裂纹和压痕变形。用钢轨数据集预训练的模型经过小幅微调迁移过去效果通常比从ImageNet预训练模型开始要好因为底层特征更接近工业材质表面。但迁移的时候要注意拍摄角度和尺度差异钢轨巡检多为俯拍近景桥梁管道可能是长焦远景直接在原分辨率上迁移效果有限。建议先做风格归一化把不同域的图像亮度、对比度拉到同一水平再微调。6.3 我的几条实操建议看完这篇文章如果你正打算整理类似的数据集我有几条掏心窝的建议第一花半天时间做完整的统计再动手训练。类别数量、框大小分布、场景分布、长尾程度这些数字比模型选型更能决定你的上线效果。第二改标注一定要留版本。我见过有人把原始标注覆盖掉之后想恢复结果回不去了。VOC和YOLO两套标注文件放到不同的目录用简单的版本号隔开。第三先跑小模型全流程验证再上大模型精调。小模型跑通数据管线只要几十分钟能帮你提前发现格式、路径、映射表的问题省下来的时间远大于训练大模型的等待时间。数据集的整理从来不是一次性工作它是一个持续迭代的闭环采集、清洗、标注、训练、误差分析再回到标注修正。这套2324张15类的钢轨缺陷数据集只是一个起点后续完全可以靠半监督接力、难例挖掘和域迁移不断往外扩。希望这篇复盘能帮你少走几步弯路特别是那些在格式转换和标注标准上绕来绕去的坑提前避开比事后补救省心得多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询