ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

铁路轨道缺陷数据集:COCO标注转YOLO训练全攻略

铁路轨道缺陷数据集:COCO标注转YOLO训练全攻略 简介面向铁路轨道缺陷检测任务的数据集原始图片规模4278张采用COCO JSON格式标注可识别轨道裂缝、间隙等缺陷适合计算机视觉、基础设施巡检方向的研究者与算法工程师开展模型训练及效果验证。压缩包共2000个文件其中1997张jpg图像和3个JSON标注文件整体大小约271.95MBjpg包含原始现场图像及增强样本JSON标注与COCO格式对齐可直接导入主流目标检测框架。已有1366人学习下载资源包内容聚焦除图片与标注外无冗余脚本拿到后即可进行数据划分、模型微调与缺陷识别实验。对于需要公开轨道缺陷数据或验证裂缝、间隙检测算法的团队能有效节省数据采集与人工标注时间。1. 铁路轨道缺陷数据集4278张图里藏着裂缝与间隙的标注密码铁路巡检的缺陷识别一直是目标检测里比较尴尬的场景说难是因为裂缝这类目标细长、对比度低说容易是因为场景固定数据一旦到位模型效果立竿见影。这份4278张原始图片的铁路轨道缺陷数据集直接省掉了最磨人的标注环节——COCO JSON格式的标注文件已经把裂缝和间隙两类缺陷框好图片与标注信息可参考CSDN那篇144853970的说明。适合正在跑轨道缺陷检测、被数据格式卡住的工程师也适合拿真实工业数据练手的学生团队。2. 数据长什么样从RF命名到COCO JSON的逐字段拆解2.1 图片文件名里的信息量拿到数据集先看文件名别急着解压训练。这份数据里的文件名明显是Roboflow导出后重命名的格式比如aug_prefix_0_161_jpg.rf.d7a356013bac55b6f6365330b178aad3.jpg去掉.rf.和后面的哈希串剩下aug_prefix_0_161_jpg说明这张图来自增强流水线是第161号样本。再比如IMG_20201211_121541_jpg.rf.28ccb6ff36f5171ae77792d80103b29c.jpg原始文件名是IMG_20201211_121541这是2020年12月11日12点15分41秒拍摄的相机原图文件名自带拍摄时间戳。还有Image-123_jpg.rf.*这种是人工整理过一轮的样本。rf后缀是Roboflow导出的标志不是拍摄信息。Roboflow在导出数据集时会统一重命名把原始文件名、文件名后缀、哈希串拼接在一起。看到这个后缀基本可以确定数据经过Roboflow平台处理这对接下来的格式转换有参考价值——部分标注框坐标可能已经过Roboflow的预处理变换。文件名的前缀对数据划分举足轻重。IMG_开头的图片代表按时间序列连拍同一时段内同一个缺陷会被拍到多帧Image-开头的图片多半是人工挑出来的关键帧aug_prefix开头的则是增强后的派生样本。这三种来源如果混在一起随机划分极易造成数据泄漏具体解决方式放在3.2节。2.2 COCO JSON的五个核心块这份标注文件遵循标准COCO格式包含info、licenses、images、annotations、categories五个核心块。images块记录每张图的id、width、height、file_name四个字段。注意width和height是图片的原始像素尺寸不是增强后的尺寸。取尺寸时以images块为准自己用PIL去读图很容易出错因为Roboflow可能已经对图片做过resize文件系统里的实际尺寸和标注文件里记录的尺寸不一致。annotations块是核心中的核心。每一条记录包含image_id、category_id、bbox、segmentation、area、iscrowd六个字段。bbox是[x, y, width, height]绝对像素坐标x、y是左上角坐标。对裂缝这种细长目标bbox会被拉得特别长宽高比夸张是正常现象。segmentation如果是polygon格式表示用一组点围出缺陷的精确轮廓如果标注工具导出了RLE格式还需要额外解码才能转成点坐标。categories块是类别表。这份数据类别数是2对应摘要里的裂缝和间隙两个缺陷类别所以这是一个二分类目标检测任务。三个块的协作逻辑是images定义像素空间annotations给目标位置categories给语义标签。字段关系整理如下数据块关键字段在本数据集中的作用imagesid, width, height, file_name建立图像ID与文件路径、尺寸的映射annotationsimage_id, category_id, bbox, segmentation, area定位每个缺陷实例的位置与轮廓categoriesid, name定义crack和gap两个类别名称表面上是三个块实际坑藏在area字段。COCO官方要求area是分割区域的真实面积不是bbox宽乘高。Roboflow导出的JSON有时直接按bbox宽乘高填area这在用COCO API计算mAP时会导致小目标权重失真。拿到数据后第一件事是校验area与segmentation多边形实际面积是否一致不一致就重算。2.3 五分钟统计数据集分布训练之前先摸清数据分布这能帮你在后续配置里做出合理决策。import json import collections with open(annotations/instances_train.json, r, encodingutf-8) as f: coco json.load(f) # 类别统计 cat_name {cat[id]: cat[name] for cat in coco[categories]} ann_count collections.Counter() img_sizes {} for ann in coco[annotations]: cat_id ann[category_id] ann_count[cat_name[cat_id]] 1 img_id ann[image_id] if img_id not in img_sizes: # 从images块取宽高避免重复读文件 for img in coco[images]: if img[id] img_id: img_sizes[img_id] (img[width], img[height]) break # 输出类别统计 for name, cnt in ann_count.most_common(): print(f{name}: {cnt} 个实例) # 抽查bbox与area的一致性 ann coco[annotations][0] bbox ann[bbox] print(bbox: , bbox, area字段: , ann[area]) print(bbox宽乘高: , bbox[2] * bbox[3])这段脚本分三步先做类别计数再用image_id反查图片尺寸最后抽查一条记录的area字段是否等于bbox宽乘高。cat_name是从categories块建立id到名称的映射ann_count做无序计数适合快速看分布img_sizes字典用来缓存尺寸避免在循环里反复遍历images列表4278张图全跑下来也就多几毫秒但养成缓存习惯对十万级数据集能省下不少时间。如果输出显示间隙类实例数远少于裂缝类就是类别不平衡解决方式在3.3节。如果area和bbox宽乘高差异超过几个像素说明标注工具流程不统一后续训练时建议按segmentation重新计算面积或用bbox面积参与损失计算。统计的价值还在于预估训练时长总实例数除以图片数能得到平均实例密度轨道场景大多是低密度每张图一到两个缺陷这种数据分布下batch size调得过大反而容易过拟合。3. 把COCO JSON接进YOLO训练流程转换脚本与三个关键参数3.1 COCO转YOLO的归一化逻辑YOLO系列训练用的是txt标注每行一个目标格式是class cx cy w h所有值都是相对图片宽高的0到1浮点数。COCO JSON里存的是绝对像素坐标转换的核心就是做一次归一化。常见做法是遍历annotations通过image_id找到对应的图片尺寸利用bbox计算出中心点和宽高再除以图片宽高。下面这段脚本是完整的转换过程。import json import os def coco_to_yolo(coco_json, img_dir, out_dir): with open(coco_json, r, encodingutf-8) as f: coco json.load(f) # 建立 id - 图片信息 的映射 img_info {img[id]: img for img in coco[images]} # 类别编号按categories的id排序后从0开始 cats sorted(coco[categories], keylambda x: x[id]) cat2yolo {cat[id]: i for i, cat in enumerate(cats)} # 按图片分组annotations anns_by_img {} for ann in coco[annotations]: anns_by_img.setdefault(ann[image_id], []).append(ann) os.makedirs(out_dir, exist_okTrue) for img_id, anns in anns_by_img.items(): info img_info[img_id] w info[width] h info[height] base os.path.splitext(info[file_name])[0] txt_path os.path.join(out_dir, base .txt) lines [] for ann in anns: x, y, bw, bh ann[bbox] # 中心点加宽高归一化 cx (x bw / 2) / w cy (y bh / 2) / h nw bw / w nh bh / h # 防御归一化结果超出[0,1]时做裁剪 cx min(max(cx, 0.0), 1.0) cy min(max(cy, 0.0), 1.0) nw min(max(nw, 0.0), 1.0) nh min(max(nh, 0.0), 1.0) lines.append(f{cat2yolo[ann[category_id]]} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) print(f转换完成产出 {len(anns_by_img)} 个txt文件)脚本执行逻辑是这样先把categories按id排序建立COCO类别id到YOLO目标编号的映射。因为COCO JSON里的category_id不一定是0、1不能直接拿原始id当YOLO类别号。再按image_id把annotations分组确保每个图片只生成一个txt。最后对每个bbox做归一化并把结果裁剪到[0,1]区间。参数说明coco_json是标注文件路径img_dir在这里其实是备用的因为宽高取的是JSON里的值不再从img_dir读图out_dir是输出的txt目录。cat2yolo决定类别顺序训练时配置文件的names必须和这里完全一致否则会出现裂缝标成间隙的错位。防御性裁剪那段是血泪经验Roboflow导出的bbox偶发越界目标贴边时xwidth可能大于图片宽度归一化后会变成1.0几。YOLO训练遇到超界标注不会报错但梯度会变得不稳定表现出来就是loss掉了又涨。3.2 数据划分不能随机按拍摄来源分治文件名前缀不同的图片来源不同直接随机划分会让验证集失真。轨道缺陷会被连续多帧拍到这些帧高度相似假如散落进了train和val两份验证集精度会高得离谱现场一测就露馅。推荐按文件名前缀分组把同一来源的所有图片放进同一个集合。import os import random img_files [f for f in os.listdir(images) if f.endswith(.jpg)] # 提取来源前缀IMG_20201211 / Image-123 等 def source_key(fname): if fname.startswith(IMG_): parts fname.split(_) return parts[0] _ parts[1] if fname.startswith(Image): return fname.split(_)[0] return fname.split(_)[0] groups {} for f in img_files: key source_key(f) groups.setdefault(key, []).append(f) all_keys list(groups.keys()) random.seed(42) random.shuffle(all_keys) val_keys set(all_keys[: int(len(all_keys) * 0.15)]) train_files, val_files [], [] for key, files in groups.items(): if key in val_keys: val_files.extend(files) else: train_files.extend(files) print(ftrain: {len(train_files)}, val: {len(val_files)})source_key的规则是关键IMG_20201211_121541取出前两段得到IMG_20201211代表一次拍摄批次Image-123取第一段代表单张人工样本aug_prefix开头的保留前缀因为增强样本是派生的归为一组避免与原始图串集。划分比例我一般用15%做验证按这份数据算train大约3600多张val大约600多张。分组划分的代价是训练集的分布偏离了随机划分的分布但换来的是验证指标可信。如果类别不平衡按组划分后还要检查val里两个类别的比例是否失调必要时调整seed或用分组抽样。3.3 类别不平衡重复采样还是换损失函数上一节统计完你会发现裂缝类的标注框数量通常远超间隙类。轨道上裂缝高频出现间隙缺陷相对稀有模型为了把整体loss压下来会倾向于把所有疑似区域都预测成裂缝。处理不平衡有两条路数据层面重复采样或者损失函数层面调整。数据层面最直接。import collections # 统计每张图包含的类别 def count_classes(coco): img_anns collections.defaultdict(list) for ann in coco[annotations]: img_anns[ann[image_id]].append(ann[category_id]) return img_anns img_anns count_classes(coco) # 找出包含间隙缺陷的图片id gap_cat_ids [cat[id] for cat in coco[categories] if cat[name] gap] gap_imgs [img_id for img_id, cat_ids in img_anns.items() if any(cid in gap_cat_ids for cid in cat_ids)] # 复制这些图片的标注到额外训练列表 extra_weight 2.0 # 间隙样本权重这段逻辑是找出所有包含间隙缺陷的图片给它们在训练列表里的权重乘2相当于每轮epoch里间隙样本被多读一次。extra_weight是经验值间隙样本本来就少权重调太高会造成模型对间隙过拟合反而把裂缝误判成间隙。实操中我习惯从1.5开始试观察验证集两类的AP曲线找到两条曲线都不掉的平衡点。4. YOLOv8与MMDetection怎么选配置文件与训练启动4.1 两个框架的真实差异拿到COCO格式标注后面临第一个选择训练框架用YOLOv8还是MMDetection。这个选择直接决定后续调优成本。两个框架的对比整理如下维度YOLOv8MMDetection上手成本低一个yaml加一条命令启动高需要维护完整config模型结构anchor free单阶段支持Faster R-CNN、RetinaNet、DETR等部署生态ONNX、TensorRT导出顺畅需要mmdeploy配合自定义能力超参数封装较深每个模块都能改配置轨道巡检这类边界清晰、目标密度低的场景YOLOv8在默认设计下已经能拿到不错的mAP部署链路也短。MMDetection的价值在于可复现学术模型、可细调anchor和loss适合做对比实验。从这份数据的实际需求看先跑YOLOv8出基线再用MMDetection复验是性价比最高的路径。4.2 YOLOv8的yaml文件要点YOLOv8用yaml文件定义数据集路径和类别名称配置极其简洁。# dataset.yaml path: ./ train: train/images val: val/images # 两个类别名称与COCO的categories保持一致 names: 0: crack 1: gap三个要点。第一train和val指向的目录里放的是图片模型不会自动扫描标注文件它在相同路径下找同名txt。第二names里的顺序必须和3.1节转换脚本里cat2yolo的编号一致这里0对应crack、1对应gap。第三path字段是根目录train和val用相对路径换机器不用改yaml。训练命令yolo detect train datadataset.yaml modelyolov8s.pt epochs100 imgsz640 batch16 patience10epochs先设100配合patience10做早停验证集mAP连续10轮不涨就停。imgsz640对轨道图片够用裂缝这类目标在图像里占的像素不多640分辨率下还能保持足够细节。想让模型更聚焦小目标可以试imgsz960代价是训练时间增加约1.5倍。轨道图像长宽比离散YOLOv8默认letterbox填充改imgsz不会丢太多信息。4.3 MMDetection的config差异与Anchor调整如果用MMDetection做基线config的写法是另一个体系。以Faster R-CNN为例需要定义数据集路径、预处理pipeline、模型结构、训练参数四块。相比YOLOv8的极简yamlMMDetection确实繁琐但可调项也更细。锚框参数在model.roi_head.bbox_head里anchor_generator dict( typeAnchorGenerator, scales[8, 16, 32], ratios[0.5, 1.0, 2.0], strides[4, 8, 16, 32, 64])关键调整点是ratios。裂缝这种细长目标的长宽比经常超过2.0默认ratios覆盖不到。有经验的做法是把ratios改成[0.2, 0.5, 1.0, 2.0]包含更扁平的锚框。修改后裂缝的召回率通常能上涨几个点。训练启动命令是python tools/train.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py注意MMDetection的默认config针对COCO 80类需要修改num_classes2和data配置。如果只改检测头不改数据集训练开始后会发现ground truth的类别id超出范围直接报错。建议改config后做一次模拟训练跑一个step确认dataloader正常再放长训练。5. 避坑与常见问题裂缝检测踩过的五个坑5.1 细长裂缝丢检anchor与长宽比不匹配现象训练完mAP看起来不错但实际推理时细长的、几乎水平的裂缝经常漏检短粗的缺陷都能检出来。原因anchor或采样点没覆盖极端长宽比。裂缝bbox的长宽比可以到5比1甚至10比1默认锚框最多覆盖2比1预测出来的框先天无法贴合细长目标。解决在MMDetection里把ratios扩到[0.2, 0.5, 1.0, 2.0]用YOLOv8则加大输入尺寸imgsz960配合图片分块检测。另一个有效手段是数据增强里的随机旋转让裂缝出现不同朝向迫使模型学习方向不变性。5.2 裂缝和间隙边界混淆标注规则不统一现象模型在裂缝附近同时预测出间隙类两个框叠在一起置信度都超过0.5。原因裂缝和间隙在视觉上本来就模糊标注标准不统一时同一个缺陷有的标识成裂缝、有的标识成间隙模型学到的类间边界是混乱的。这份数据经过Roboflow导出标注来自多个批次出现标准漂移并不奇怪。解决训练前人工抽查50张含间隙的图确认标注标准必要时合并类别。如果间隙类实在分不清先合并成一类缺陷跑通流程再细化。我更建议统一标准把间距超过既有宽度的剥离层归为间隙剩余细线归为裂缝。5.3 COCO转YOLO后框偏移segmentation与bbox不一致现象转出的txt在可视化脚本里画出来框的位置和缺陷实际位置偏移明显有时框到缺陷旁边。原因COCO JSON里segmentation是人工勾勒的多边形bbox有时是标注工具按外接矩形计算有时是人工微调的矩形两者边缘不完全对齐。转换脚本如果优先取segmentation的外接矩形而手工bbox才是给模型看的标准就会偏移。解决转换时以手工bbox为准丢弃segmentation生成的外接矩形。如果bbox明显超出segmentation边界再用polygon的外接矩形覆盖。这个判断用shapely几行代码就能做。5.4 数据泄漏同源连拍帧串进两个集合现象验证集mAP高达0.9以上新拍的现场图片mAP掉到0.5以下。原因随机划分导致同源连拍帧同时出现在train和val模型提前见到了答案。排查时按文件名统计才发现IMG_20201211_121541和IMG_20201211_121540在train和val各占一张这两张图拍的几乎是同一个位置。解决按source_key分组划分。检查方法是写脚本扫一遍val集里是否存在和train集文件名前缀相同的图片出现就直接替换划分结果。5.5 逆光与阴影下的裂缝漏检现象白天顺光图片检测效果很好阴天或逆光时裂缝漏检率明显上升。原因轨道表面的裂缝在阴影或逆光条件下对比度大幅降低模型学到的边缘特征依赖局部对比度光照一变特征就失效。这是工业场景的经典问题不是模型结构能单独解决的。解决训练pipeline里加随机亮度、对比度、灰度化增强项。更直接的做法是推理时对输入图像做CLAHE对比度增强实际效果一般能提升阴影场景3到5个点的召回率。6. 进阶验证集阈值扫描与缺陷分级模型训练完后直接把默认0.5置信度阈值用于部署是常见的翻车点。裂缝检测里漏检和误检的代价不同漏检意味着巡检失效误检意味着人工复查成本上升。我把阈值扫描写成了固定动作。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) # 在验证集上跑低阈值推理拿到所有候选框 results model.val(datadataset.yaml, conf0.001) # 遍历阈值计算F1选择最优 best_threshold 0.5 best_f1 0.0 for conf in [0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6]: # 用验证结果重新计算精确率和召回率 precision, recall evaluate_at_threshold(results, conf) f1 2 * precision * recall / (precision recall) if f1 best_f1: best_f1 f1 best_threshold conf print(f最佳阈值: {best_threshold}, F1: {best_f1:.3f})阈值选择的实际逻辑还要结合业务需求。缺陷数量偏少就选召回率优先把阈值调低代价是误检多一点缺陷数量偏多则提高阈值减少复查量。另一种更有价值的进阶是缺陷分级。轨道缺陷不是有或没有就能决策的往往需要区分轻微和严重。借助这份数据我一般把单条裂缝的像素长度和宽度提取出来配合实地标准做对照用长度阈值自动区分严重程度。不需要重新标注只把推理结果里的bbox宽高换算成实际尺寸——前提是先标定每个像素对应的物理距离。从那以后跑轨道缺陷检测我每次都会把数据分布统计、分组划分、阈值扫描这三件事强制走一遍再考虑调模型结构。数据决定的上下限远比模型结构本身大。希望帮到你。本文还有配套的精品资源点击获取
返回列表