
简介这份火车轨道检测数据集面向计算机视觉开发者、轨道交通智能化研究者及深度学习实践者用于训练和验证轨道区域与障碍物识别模型可支撑列车前方障碍预警、轨道巡检自动化等场景。资源以COCO标注格式组织包含3900张原始图片官方给出的识别准确率达93.7%适合作为目标检测模型的训练与评估基础。压缩包共2000个文件其中1995个jpg图像为实际样本3个json文件承载COCO标注信息另有2个txt说明文件整体约471.42MB目录结构便于直接接入主流检测框架。目前已有2063人学习下载说明其在轨道检测方向具备一定参考价值。读者可据此获得成规模的标注数据用于模型训练、精度对比与算法调优也能结合标注文件快速完成数据加载与类别映射减少自行采集和标注的成本。1. 火车轨道检测数据集3900 张 COCO 标注图能撑起 93.7% 准确率吗铁路巡检这个场景真正难的不是把轨道框出来而是把轨道和侵限障碍物同时框对。轨道是细长目标障碍物可能是落石、异物、行人、倒伏树枝尺度差异极大背景又高度重复。你拿一个通用 COCO 预训练模型直接推轨道框会断成一段一段障碍物小目标基本漏检。这个标题里的数据集3900 张原始图片、COCO 标注、可识别火车轨道和障碍物、准确率 93.7%本质上是在回答一个很实际的问题有没有一份标注质量够用、类别定义清晰、能直接喂给 YOLO 系列或 MMDetection 的轨道场景数据让一线做巡检算法的人不用从零标几千张图。它适合三类人做铁路/地铁巡检视觉算法的工程师、想拿一个细长目标加小目标混合场景练手检测模型的人、以及需要评估「自建标注 vs 直接用现成数据集」成本的人。不适合指望开箱即用就能上线的场景93.7% 这个数字背后一定绑定了特定验证集和 IoU 阈值脱离评测协议谈准确率没有意义。下面按「数据长什么样 → 怎么转成训练格式 → 怎么训 → 坑在哪 → 怎么把指标做扎实」推一遍。2. 拆开这份 COCO 标注类别定义、标注粒度与 93.7% 的评测口径2.1 轨道和障碍物在 COCO 里到底怎么标COCO 格式的核心是三个 JSONimages、annotations、categories。轨道检测这类场景类别通常不会只有两个。常见做法是把轨道拆成「轨道」一类障碍物按来源拆成「落石/异物/人员/车辆」若干类也可能只给一个粗粒度的「障碍物」类。3900 张图如果只标两个类标注成本低但模型学不到障碍物内部差异如果拆到五六类每类样本量会被摊薄小类别容易欠拟合。判断这份数据能不能用第一件事是统计每个类别的实例数而不是看图片数。轨道是长条目标一张图里可能只有 1 到 2 个轨道实例但障碍物实例数波动很大。下面这段脚本直接读 COCO JSON 做类别分布统计跑一遍就知道数据是否均衡。import json from collections import Counter # 换成你的标注文件路径 ann_path annotations/instances_train.json with open(ann_path, r, encodingutf-8) as f: coco json.load(f) # 类别 id - 名称 cat_map {c[id]: c[name] for c in coco[categories]} # 统计每个类别的标注框数量 inst_counter Counter(ann[category_id] for ann in coco[annotations]) # 统计每个类别的图片覆盖数去重 img_counter Counter() for ann in coco[annotations]: img_counter[ann[category_id]] 0 # 占位下面用集合去重 cat_imgs {} for ann in coco[annotations]: cat_imgs.setdefault(ann[category_id], set()).add(ann[image_id]) print(f图片总数: {len(coco[images])}) print(f标注框总数: {len(coco[annotations])}) for cid, name in cat_map.items(): print(f{name:12s} 框数{inst_counter.get(cid,0):6d} 覆盖图片{len(cat_imgs.get(cid,set())):5d})逻辑说明inst_counter统计的是标注框数量反映模型能学到的正样本量cat_imgs统计的是类别覆盖的图片数反映类别在场景中的出现频率。参数上唯一要改的是ann_path训练集和验证集各跑一次。如果某个障碍物类覆盖图片不到 100 张训练时就要考虑过采样或类别加权否则 93.7% 的准确率大概率是被轨道大类拉上去的。2.2 93.7% 准确率对应的指标到底是什么检测任务里说「准确率」是不严谨的。COCO 评测体系用的是 APAverage Precision按 IoU 从 0.5 到 0.95 步长 0.05 取平均得到 AP[.5:.95]另外单独报 AP50、AP75。93.7% 如果指的是 AP50那是一个偏乐观但常见的数字如果指的是 AP[.5:.95]在轨道这种细长目标上非常难需要标注框贴合度极高。轨道目标的 IoU 对框的偏移极其敏感。一条宽 20 像素的轨道框上下各偏 5 像素IoU 就掉到 0.6 以下。所以看这份数据的指标必须确认三件事IoU 阈值是多少、是按类别平均还是按全体平均、验证集是不是和训练集同分布。常见做法是要求提供方给出 per-class AP 表而不是一个总数。下面这张表是我评估任何检测数据集时会填的核对表。核对项为什么重要合格线参考IoU 阈值决定指标乐观程度至少给 AP50 和 AP75per-class AP防止大类掩盖小类每个类都要有验证集来源判断是否同分布最好独立于训练采集批次小目标占比轨道障碍物多为小目标统计 area32² 的比例标注一致性细长目标框贴合度抽查 50 张看框是否贴边提示拿到任何声称高准确率的数据集先跑一遍类别分布和 per-class AP再决定要不要投入训练。一个总数说明不了问题。3. 把 COCO 标注转成 YOLO 格式转换脚本与四个边界坑3.1 COCO 转 YOLO 的坐标换算YOLO 格式要求每行class_id x_center y_center width height全部归一化到 0 到 1。COCO 给的是[x_min, y_min, width, height]绝对像素。换算本身简单但轨道这种细长目标在转换时最容易出问题的是框超出图像边界和宽高为 0。下面脚本做了边界裁剪和合法性校验。import json import os from PIL import Image def coco_to_yolo(coco_json, img_dir, out_dir): with open(coco_json, r, encodingutf-8) as f: coco json.load(f) # COCO category_id 可能不连续重映射成 0 起始 cats sorted(coco[categories], keylambda x: x[id]) cat_id_map {c[id]: i for i, c in enumerate(cats)} img_info {img[id]: img for img in coco[images]} # 按 image_id 聚合标注 ann_by_img {} for ann in coco[annotations]: ann_by_img.setdefault(ann[image_id], []).append(ann) os.makedirs(out_dir, exist_okTrue) for img_id, anns in ann_by_img.items(): info img_info[img_id] w, h info[width], info[height] # 用真实图片尺寸兜底防止 JSON 里尺寸写错 real_path os.path.join(img_dir, info[file_name]) if os.path.exists(real_path): with Image.open(real_path) as im: w, h im.size lines [] for ann in anns: x, y, bw, bh ann[bbox] # 裁剪到图像范围内避免负坐标和越界 x1 max(0, x) y1 max(0, y) x2 min(w, x bw) y2 min(h, y bh) bw, bh x2 - x1, y2 - y1 if bw 1 or bh 1: continue # 丢弃退化框 xc (x1 bw / 2) / w yc (y1 bh / 2) / h nw bw / w nh bh / h cls cat_id_map[ann[category_id]] lines.append(f{cls} {xc:.6f} {yc:.6f} {nw:.6f} {nh:.6f}) txt_name os.path.splitext(info[file_name])[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines)) coco_to_yolo(annotations/instances_train.json, images/train, labels/train)逻辑说明cat_id_map把 COCO 里可能跳号的 category_id 压成从 0 开始的连续整数这是 YOLO 训练必须的否则类别索引对不上。real_path那段用 PIL 重新读图片尺寸是因为不少数据集 JSON 里的 width/height 和实际图片不一致直接信 JSON 会导致归一化坐标整体偏移。bw 1 or bh 1过滤掉裁剪后退化的框轨道细长目标偶尔会出现这种脏标注。参数说明coco_json是标注文件img_dir是原图目录out_dir是输出的 labels 目录。训练集和验证集分别调用一次。转换完必须抽查不能直接开训。3.2 转换后必须做的三项校验转换脚本跑完不代表数据就对了。我一般会做三件事一是用可视化脚本把 YOLO 框画回原图看轨道框有没有整体偏移二是统计每张图的标注行数找出空标签文件三是检查类别索引分布是否和 COCO 统计一致。空标签文件在 YOLO 训练里会被当成纯背景图如果数量多会明显拉低召回率。# 统计空标签文件数量 find labels/train -name *.txt -empty | wc -l # 统计标签文件总数和图片数对比 ls labels/train/*.txt | wc -l ls images/train/*.jpg | wc -l如果空标签数量超过图片总数的 5%要么是转换漏了要么是原数据里确实有大量无目标图。前者回去查ann_by_img聚合逻辑后者考虑把这些图单独拿出来做背景负样本而不是混在正样本里。3.3 数据集划分别让同一段轨道同时出现在训练和验证里3900 张图如果是从连续视频抽帧来的相邻帧高度相似。随机按 8:2 划分训练集和验证集会存在大量近重复样本验证指标虚高93.7% 很可能就是这么来的。正确做法是按采集批次、线路区段或时间划分。常见做法是同一段轨道、同一趟巡检的图片只进训练集或只进验证集绝不跨集。判断是否存在近重复可以用感知哈希快速筛一遍。下面这段用 imagehash 找相似图把相似度高的图归到同一组再按组划分。import imagehash from PIL import Image import os from collections import defaultdict groups defaultdict(list) hashes {} for fn in os.listdir(images/all): if not fn.lower().endswith((.jpg, .png)): continue with Image.open(os.path.join(images/all, fn)) as im: h imagehash.phash(im) hashes[fn] h # 汉明距离小于 5 视为近重复 files list(hashes.keys()) visited set() group_id 0 for i, f1 in enumerate(files): if f1 in visited: continue group [f1] visited.add(f1) for f2 in files[i1:]: if f2 in visited: continue if hashes[f1] - hashes[f2] 5: group.append(f2) visited.add(f2) groups[group_id] group group_id 1 print(f总图片 {len(files)}聚成 {len(groups)} 组)逻辑说明phash对缩放和轻微压缩鲁棒适合找抽帧近重复。汉明距离阈值 5 是经验值轨道场景背景重复度高可以适当放宽到 8。划分时以组为单位整体进训练或验证避免泄漏。这一步做完验证指标会掉一些但那个数字才是可信的。4. 用 YOLOv8 训练这份数据配置、参数与指标解读4.1 数据配置文件与最小训练命令YOLO 系列训练需要一份 YAML 描述数据路径和类别。轨道检测类别少配置文件很短但路径写错是最常见的翻车点。# rail_data.yaml path: /data/rail_dataset # 数据集根目录 train: images/train val: images/val names: 0: rail 1: obstacleyolo detect train \ datarail_data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz1024 \ batch8 \ patience30 \ projectruns/rail \ nameexp1逻辑说明imgsz1024是关键选择。轨道是细长目标640 分辨率下轨道宽度可能只剩几个像素特征提取会丢。1024 能明显改善细长目标召回代价是显存和训练时间上升。batch8是 1024 分辨率下 8G 显存的保守值显存够可以往上加。patience30表示 30 轮验证指标不升就早停防止过拟合。参数说明model从 yolov8n 到 yolov8x 按精度递增轨道场景建议至少 yolov8sn 版对小目标偏弱。epochs150是起点看验证曲线决定是否加。如果障碍物小目标多可以开mosaic1.0增强但轨道是长条目标mosaic 拼接会切断轨道连续性建议后期关掉 mosaic 再微调几十轮。4.2 训练后必须看的四条曲线训练完不能只看一个 mAP。我固定看四条train/box_loss和val/box_loss是否同步下降、metrics/mAP50和metrics/mAP50-95的差距、每个类别的 AP、以及混淆矩阵。轨道和障碍物如果混淆矩阵里互相误判说明类别定义本身有歧义比如「轨道上的异物」到底算轨道还是障碍物。# 用验证集跑一次详细评估输出 per-class 指标 yolo detect val \ modelruns/rail/exp1/weights/best.pt \ datarail_data.yaml \ imgsz1024 \ plotsTrueplotsTrue会在输出目录生成混淆矩阵和 PR 曲线。重点看障碍物类的召回轨道类通常 AP 很高如果障碍物召回低于 0.7说明小目标或样本量不够需要针对性补数据或调 anchor。4.3 93.7% 这个数字怎么复现和验证要复现一个接近 93.7% 的指标前提是评测协议一致。如果原数据报的是 AP50你也要在 AP50 口径下比。如果原数据用了 TTA测试时增强或高分辨率推理你也要对齐。下面命令开启 TTA 推理通常能涨 1 到 2 个点但推理速度会成倍下降。yolo detect val \ modelruns/rail/exp1/weights/best.pt \ datarail_data.yaml \ imgsz1280 \ augmentTrue \ conf0.001 \ iou0.6逻辑说明augmentTrue开启 TTAconf0.001是 COCO 评测的标准低置信度阈值保证 PR 曲线完整iou0.6是 NMS 的 IoU 阈值。这三个参数和 COCO 官方评测对齐后得到的数字才有可比性。如果这样跑出来和 93.7% 差很多先怀疑验证集划分泄漏再怀疑标注质量。5. 避坑与排查轨道检测数据集落地时最容易翻车的五件事5.1 现象训练 mAP 很高实际推理轨道断断续续原因训练时用了 mosaic 增强轨道被拼接切断模型学到的是局部片段或者验证集和训练集同源指标虚高。解决后期关闭 mosaic 微调推理时降低 conf 阈值到 0.2 左右让断开的轨道段连起来再考虑后处理做线段拟合。5.2 现象障碍物小目标几乎全漏原因输入分辨率太低小目标在特征图上不足一个像素或者障碍物样本量太少被轨道大类压制。解决把 imgsz 提到 1024 以上检查障碍物类覆盖图片数低于 200 张就做过采样并在 loss 里给障碍物类更高权重。5.3 现象COCO 转 YOLO 后框整体偏移原因JSON 里的 width/height 和实际图片尺寸不一致归一化基准错了。解决转换时用 PIL 重新读真实尺寸不要信 JSON 字段转换后可视化抽查至少 50 张。5.4 现象验证指标忽高忽低每次划分结果差很多原因连续帧近重复导致数据泄漏随机划分不稳定。解决用感知哈希聚类按组划分保证同一段轨道的图不跨集。这一步做完指标会降但稳定。5.5 现象轨道和障碍物互相误判原因类别定义边界模糊比如轨道上的小异物标注时一会儿标轨道一会儿标障碍物。解决回到标注规范明确「障碍物」只标侵限且独立于轨道的目标轨道上的附着物归轨道类重新清洗标注后再训。6. 把 93.7% 变成可复现的工程指标验证集构建与推理后处理技巧数据集的价值不在于那个数字而在于你能不能在自己的场景里复现并超过它。我一般会做两件事一是自建一个「困难验证集」专门收集漏检和误检的图每次模型迭代都在这上面跑二是针对轨道细长特性做推理后处理把断开的检测框合并成完整轨道线。困难验证集的构建不需要重新标注从现有验证集里挑出模型置信度在 0.3 到 0.6 之间的样本人工复核一遍这些就是边界样本。每次训练完先在这个子集上看指标比看全体 mAP 更能反映真实进步。下面这段脚本从验证结果里筛出低置信度样本方便你快速定位困难图。import json # YOLO val 保存的预测结果 JSON with open(runs/rail/exp1/predictions.json, r) as f: preds json.load(f) # 按图片聚合找平均置信度低的图 from collections import defaultdict img_confs defaultdict(list) for p in preds: img_confs[p[image_id]].append(p[score]) hard [(img, sum(c)/len(c)) for img, c in img_confs.items() if c] hard.sort(keylambda x: x[1]) print(最难的 20 张图) for img, avg in hard[:20]: print(fimage_id{img} avg_conf{avg:.3f})逻辑说明平均置信度低的图要么是目标模糊要么是模型没学好。把这些图挑出来人工看一遍能快速判断是数据问题还是模型问题。参数上predictions.json是 YOLO val 保存的预测文件不同版本路径略有差异找不到就开save_jsonTrue。推理后处理方面轨道检测可以加一步线段拟合把同一类别的检测框按长宽比筛出细长框用最小二乘拟合直线再把断开的段按距离和角度合并。这一步能把轨道连续性指标拉高不少但要注意别把弯道拟合直了。我的习惯是弯道区段单独处理直线段才做合并。最后说个血泪经验任何声称 93.7% 的数据集拿到手第一件事不是训模型而是花半天做数据审计——类别分布、近重复、标注贴合度、验证集独立性。这半天能省掉后面两周的玄学调参。希望帮到你。本文还有配套的精品资源点击获取