资讯详情

资讯详情

基于YOLOv10的铁轨轨道缺陷检测系统:从数据集构建到UI界面落地全流程

搞轨检项目这些年我最大的一个感受是真正拦住你的往往不是模型选型而是从“能跑通的Demo”到“现场能用的铁轨轨道缺陷检测系统”之间那一段没人明说的路。YOLOv10确实强推理快、精度高但如果没有一套干净可用的YOLO数据集没有把模型封装成带UI界面的完整Python项目源码再好的权重文件也只能躺在训练日志里吃灰。这篇内容是我自己从零搭建这样一套系统的完整复盘覆盖数据准备、YOLOv10训练、界面封装到现场落地的全流程适合正在做目标检测项目、尤其是工业检测方向的同学参考。1. 先想清楚铁轨缺陷检测为什么必须走目标检测这条路1.1 传统图像处理在钢轨场景里的致命短板我刚接触这个需求时第一反应还不是上深度学习而是先试了一圈传统图像处理。钢轨表面缺陷在视觉上确实有特征裂纹是细长的暗线剥落是块状区域擦伤是亮白色的条带。用Canny边缘检测加形态学闭运算理论上能把暗线提出来再按长度和方向筛一筛好像就能出结果。实际跑下来完全不是那么回事。户外轨检图像里的干扰比想象中多太多阳光直射会产生强反光轨面有油污、水渍、锈斑钢轨轧制纹路本身在灰度上就接近裂纹特征。传统算法最怕的就是这类“似然非然”的纹理经常把一条普通压痕当成裂纹又把真正在扩展的裂纹漏过去。更麻烦的是钢轨型号不一样、打磨状态不一样灰度阈值就得重新调。现场测试一天下来调参的时间比写逻辑的时间还多。深度学习目标检测模型之所以适合做这件事是因为它把特征提取交给了标注样本去驱动。模型见过足够多的“裂纹在什么光照下长什么样”之后对新场景的泛化能力远强于手工特征。它可以输出缺陷的位置框顺着框去裁剪、复核、记录整个流程完全可以工业化。1.2 缺陷类别如何映射成检测框确定走目标检测路线之后第一个问题是检测框到底标什么铁轨缺陷在专业运维里有一套细分标准做系统时不能直接照搬因为检测模型需要的是“图像上能稳定区分、现场处理时有实际意义”的类别。我这次归下来主要分四类轨面裂纹细长、曲折反射率与周边差异大是风险最高的一类。轨头剥离/剥落块状不规则缺损边界明显面积有大有小。擦伤/压溃轨面出现亮白色或暗色条带形状偏长条。扣件异常弹条断裂、缺失或明显移位这类目标小但形态稳定。给细长裂纹画矩形框会包进大量背景所以早期我把裂纹单独做成一个类别接受框比目标大这一事实靠内部特征区分。后期数据多了之后也可以考虑旋转框但YOLOv10原生是水平框先跑通流程更重要。分类原则记住一条按“现场能不能直接处置”来分而不是按专业检测标准细分。比如轻微磨损和严重磨损如果维修动作都是“报修”那干脆归成一类否则样本均衡会让你哭。1.3 在YOLOv10和旧版之间做选择时我在意什么选YOLOv10不是赶时髦。对我来说最关键是它在保证精度的同时砍掉了NMS后处理。YOLOv8以前的模型训练完部署推理时要跑NMS去掉重复框检测头也会输出大量冗余框。YOLOv10的端到端设计让推理链路更短对后面做视频流逐帧检测很有帮助。另外它的网络结构在Backbone和Neck部分继续沿用并优化了C2f模块训练收敛速度比同量级的旧版快一些对小目标也有专门的改进。铁轨缺陷里裂纹、扣件缺失这种小目标占比高这个点命中要害。当然也不是说无脑选YOLOv10就完事。如果你的数据集只有几百张旧版的小模型可能会更稳因为新版模型的容量更大数据太少反而容易过拟合。我是把数据攒到两千张以上才开始正式训练YOLOv10量不足之前都在做数据准备。模型规模我先用n和s做对比最终线上用s后面会详细说参数取舍。2. 数据集的土办法与硬功夫攒出一份YOLO格式轨检数据2.1 现场图像采集、初筛与清洗准则目标检测项目最花时间的永远是数据铁轨方向尤其如此。公开的轨面缺陷数据集很少要么场景不匹配要么标注不规范所以得靠现场积累和反复筛选。数据来源主要是轨检车在白天作业时拍摄的轨面图像以及便携设备沿线路手持拍摄的图片。视频流抽帧是我的主力方式因为一次巡检能跑出大量连续帧效率高。抽帧不是简单每隔几帧取一张如果巡检车速度变化要按时间间隔加位移间隔混合抽避免连续帧过于相似。初筛环节有三条硬标准模糊图像不要。相机抖动、对焦不准会让裂纹边缘糊成一片标了也没法学。严重过曝和欠曝不要。纯白或纯黑的图像里没有可用于学习的纹理信息。无轨面无意义区域不要。比如大量天空、绿化带的路段帧直接删掉减少清洗时间。去重也容易被忽略。视频相邻帧相似度极高如果不做去重相当于某些样本被重复了几十倍验证集又和训练集挤在一起最后的指标全是虚高。我按感知哈希算相似度相似度超过0.98的帧只保留一张效果立竿见影。数据量的底线我个人经验是至少2000张有效轨面图每个类别的实例数不少于300。裂纹这种形态变化大的类别实例数能到800以上最好。低于这个规模训练出来的模型很可能只记住了少数几条裂纹的纹理模式。2.2 类别标签设计别按专业分类按“可操作缺陷”分类第一次做标注的时候我很容易陷入专业细节里把“横向裂纹”和“纵向裂纹”分成两类又把“轻度剥落”和“重度剥落”分开。训练完发现横向和纵向样本数量差得远剥落的严重程度边界本身就在争议。后来全部合并系统性能反而上去了。最终类别标签我用英文小写命名和YOLO配置文件保持一致crack spalling scratch fastener对应YOLO格式的标注文件每行是五个数值class_id x_center y_center width height这些坐标都是归一化后的相对值范围0到1用LabelImg或者Label Studio标注后自动生成。注意标注框要贴合目标的可辨识部分。比如扣件目标很小框就紧紧包住弹条不要带上下面的轨枕背景裂纹长度很长可以整条画一个大框但如果裂纹跨度过大画框反而把大量背景框进来这时我倾向于只标注裂纹核心段。2.3 切图、增强与train/val划分的实操细节轨检相机拍出来的原图经常是4096×2160这种大尺寸直接喂给YOLOv10会把显存吃穿而且模型缩放到640x640之后小目标会被严重压缩。我的做法是切图。切图参数在工程里统一配置切块尺寸640×640重叠率0.2。重叠的作用是防止目标恰好骑在切块边界上被切断。切出来的子图如果包含目标就保留全背景的丢弃这样既省显存又变相扩容了数据。给出一个切图逻辑片段import cv2 def crop_image(image, crop_size640, overlap0.2): h, w image.shape[:2] step int(crop_size * (1 - overlap)) crops [] for y in range(0, h, step): for x in range(0, w, step): y_end min(y crop_size, h) x_end min(x crop_size, w) crop image[max(0, y_end - crop_size):y_end, max(0, x_end - crop_size):x_end] crops.append(crop) return crops切图之后对应标注框的坐标也要换算切图工具里要同步处理标签。数据增强我用了翻转、随机旋转、亮度和对比度调整、高斯模糊和少量噪声。但要注意关掉垂直翻转因为铁轨图像里轨面方向固定垂直翻转会让模型学到错误的方向信息。Mosaic增强对提升小目标检测很有效建议开启但训练后期可以逐步关闭让模型适应真实分布。Ultralytics仓库自带的增强参数只要不刻意去动默认策略在轨面场景下表现就还可以。最后是数据集划分。这一步最容易埋雷不要随机划分视频帧。同一个视频段里相邻帧高度相似随机划分会把相近样本同时送进训练集和验证集验证指标虚高到不可思议一到现场立刻露馅。正确做法是先按采集视频分组同一组的所有帧要么全进训练集要么全进验证集。3. YOLOv10训练实操从命令到权重文件的完整链路3.1 环境与工程代码的组成训练环境我用的Python版本3.10PyTorch 2.x配合CUDA 11.8显卡是24G显存的一张卡。实际上YOLOv10s用8G显存也能跑起来关键是要把batch_size调到合适范围。工程目录结构尽量固定方便后面模型迭代rail_defect_detection/ ├── dataset/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ ├── rail_defect.yaml ├── train.py ├── detect.py └── ui_app/数据集的配置文件是关键yaml里写清路径和类别path: ./dataset train: images/train val: images/val nc: 4 names: [crack, spalling, scratch, fastener]一个常见的坑是yaml文件里的路径写的是绝对路径换机器就要改。规范化做法是path用相对路径或启动时动态生成保证源码拷贝到任何机器都能直接跑。3.2 训练参数如何根据显卡和数据集调整训练命令我直接基于YOLOv10官方仓库的CLI来跑yolo detect train \ modelyolov10s.yaml \ datarail_defect.yaml \ imgsz640 \ batch16 \ epochs200 \ lr00.01 \ patience30 \ projectrail_runs \ nametrain_s几个参数的选择逻辑值得展开说。batch_size由显存决定。24G显存跑YOLOv10sbatch16很稳8G显存建议8以下。batch不是越大越好太大的batch会让模型收敛不稳定尤其是工业小数据集上容易过早过拟合。epochs我设200但实际不会傻跑完。patience30代表验证集指标连续30轮不提升就自动早停。铁轨缺陷数据集规模中等通常70到100轮就能收敛到平台期。lr0用默认0.01就够了如果发现loss抖动明显降到0.005。imgsz我固定在640。切图本来就是640如果训练时再放大到960小目标细节更丰富但对显存压力大推理速度下降。现场对速度有要求时640是平衡点。3.3 用混淆矩阵和PR曲线判断模型该不该继续练训练结束之后不要只盯着mAP值我会按顺序看四个东西results.png、confusion_matrix.png、PR曲线、单类验证结果。results.png里重点看两个Loss曲线和验证集的mAP50、mAP50-95。如果训练loss持续下降但验证mAP开始横盘甚至下滑说明过拟合开始了早停触发是对的。混淆矩阵能暴露出最实际的问题。比如fastener这个类容易和背景混淆那说明扣件的负样本不够需要补充更多无扣件的轨枕图crack和scratch互相混大概率是标注边界太模糊该回头统一标注口径。PR曲线看每类召回率的上限。铁轨缺陷漏检比误报风险更大所以我不强求precision到0.98而是看recall能不能到0.9以上。如果某类recall明显低先别调模型回到数据补样本更有效。3.4 权重导出、尺寸压缩与推理脚本验证训练完得到best.pt下一步是导出适合部署的格式。我这里导出两种ONNX和TensorRT的engine格式。ONNX方便在不开源的推理引擎里二次开发engine格式在NVIDIA显卡上推理速度最快。yolo export modelruns/train_s/weights/best.pt formatonnx halfTrue加上halfTrue是把模型转成FP16半精度精度损失很小推理速度提升明显。铁轨检测这种交互式场景完全够用。导出之后不能直接部署我习惯先跑一段验证脚本用几张完全没参与训练的真实轨面图测看置信度分布。用默认0.25置信度测一遍再把0.5测一遍观察漏检情况。现场用0.4左右比较折中。这一步能提前发现“训练指标挺好但实际框乱跳”的假阳性问题。4. UI界面把模型包成一个普通人能用的检测系统4.1 选桌面UI还是Web UI我为什么选PySide6模型训练好只是第一步用户不可能去敲命令行。包装UI界面的时候我对比过Gradio、Flask、PySide6三套方案。Gradio确实省事几行代码就能出拖拽上传和实时显示但现场电脑经常没有浏览器环境而且Gradio界面风格和工业软件差距大批量图片处理效率低。Flask需要起服务、管端口离线场景下维护成本高。最后选了PySide6。理由很实际桌面应用双击即用能直接读本地视频流和文件夹界面交互灵活还能用Python源码直接组织整个工程。PySide6基于Qt稳定性经得起长时间运行测试。打包成exe后现场同事不需要装Python环境。4.2 界面交互与后台推理如何避免卡死UI开发里最容易犯的错误是让推理直接跑在主线程里。视频流逐帧推理很重往界面线程里一塞窗口立刻“未响应”用户第一反应就是软件坏了。正确做法是QThread后台推理加信号槽刷新结果。我工程里的结构大致是这样class DetectThread(QThread): frame_ready Signal(object, object) # 原图 检测结果 def run(self): cap cv2.VideoCapture(self.video_path) while self.running: ret, frame cap.read() if not ret: break results self.model(frame, confself.conf_thres) rendered results[0].plot() self.frame_ready.emit(frame, rendered) cap.release()界面主线程只负责接收信号、把渲染完的画面显示到QLabel上。即使某帧推理特别慢窗口依然能拖动、能点按钮体验完全不一样。还有两个细节视频读取和模型推理放在同一个线程里不能分开否则画面播放速度和推理速度不在同一节奏上很容易造成内存积压用户切换视频文件时要先停止当前线程再启动新线程直接start会崩溃。4.3 从“出框”到“出报告”检测结果的工程化呈现只画框是不够的现场人员需要留档、统计、上报。我做了三种结果输出方式第一种是单张图片检测打开一张图左侧原图右侧标注结果下方列出每个缺陷的类别、置信度和框坐标可以一键保存为带标注的图片。第二种是视频文件检测逐帧跑完把命中帧的缩略图保存到结果目录同时在表格里记录帧号、类别、置信度方便事后快速定位到视频里的具体位置。第三种是汇总报告输出CSV或者Excel按缺陷类别统计数量同时附上每张截图命名规则。命名规则我用“原文件名_帧编号_类别_置信度”这种格式比纯时间戳好用很多人工复核时一目了然。界面里置信度阈值做成滑块范围0.1到0.9现场人员可以根据天气和光线随时调节。轨道表面有水、有油时阈值需要往高调阴暗环境下阈值往低调。这种“让用户自己掌握尺度”的设计比把所有参数写死在代码里实用得多。5. 真正落地的必经之坎速度、误报与模型迭代5.1 推理耗时与硬件选型之间的平衡做桌面检测系统还好帧率要求不苛刻但做实时视频巡检时推理速度直接决定硬件选型。我们测试过低端集成显卡跑YOLOv10s的engine格式时640×640单帧推理大约要90毫秒勉强能到10FPS多一点。换主流独立显卡的话单帧可以压到10毫秒量级接近实时处理轨道车视频流。如果硬件条件有限一个直接的方案是用YOLOv10n替代s。n模型参数更少推理更快精度大约低几个点。在轨道缺陷这个任务里n对小裂纹的召回率下降比较明显不太推荐当主力。我最终线上用的s部署机选择也以够跑s模型的独立显卡为底线。还有一个容易被忽视的性能点输入图像尺度。如果切图尺寸是640推理时又把整张原图缩放成640再跑小目标会变小。我们现场的方案是保持切图的640尺寸直接推理不做二次缩放速度不慢小目标细节保留更完整。5.2 误报漏检的常见来源和处理策略训练指标再漂亮一到现场就会被现实教育。轨面焊缝是最大的误报来源焊缝区域有不规则的纹理模型经常把焊缝当成裂纹。水渍在某个光照角度下看起来和剥落几乎一样。扣件类还会碰到弹条阴影被识别成目标的情况。针对这些我总结了一套组合拳优先提高置信度阈值。从0.4提到0.55焊缝误报能砍掉一大半代价是少量低置信度的真实裂纹也被过滤。配合图片复核流程人工看一遍截图比把大量误报框混在一起整体强。对高频误报区域做二次校验。比如焊缝区域专门收集一批负样本训练一个二分类小模型或者做一个区域过滤器检测框中心落在已知焊缝区时就标记为“待复核”而不是直接报缺陷。多帧确认机制。视频流场景下同一缺陷通常连续多帧都出现只出现一两帧的目标大概率是噪声或反光。要求连续三帧命中才上报能大幅降低偶发误报。这些策略我都实现成了配置文件里的开关现场调试时不用改代码调配置就行。5.3 新样本回流与模型的可持续迭代机制铁轨缺陷检测和其他目标检测项目不太一样缺陷类型相对固定但外观变化多。不同线路的钢轨锈蚀程度、不同季节的光照条件都会让模型渐渐“看走眼”。我的做法是建立新样本回流机制。现场在复核系统时凡是漏检的缺陷图片和误报的干扰图片都一键复制到一个“误检回收”目录每周人工标注一次把新标注样本合并进训练集。增量训练不是从头重训而是在已有best.pt基础上继续训练少量轮次学习率调低比如从0.001开始这样既利用了旧知识又能快速适配新场景。模型版本管理也很重要。我习惯在工程目录里给每次迭代记一个简单的表格记录训练日期、数据量、各类mAP、现场测试结论。看起来有点繁琐但两三个月后翻这个表比翻训练日志高效十倍。最后说一点我自己的体会这套铁轨轨道缺陷检测系统从零到能现场用最深的感受是YOLOv10本身只是整个系统里最省心的一部分数据、UI、部署和迭代机制的工程化才是真正花时间的地方。如果你想复现类似项目我建议先把数据管线的代码写好——采集、切图、增强、标注、验证集隔离每一步都留好接口。数据跑顺了模型训练就是一晚上的事。一个小技巧尤其值得说切图重叠率用0.2太高会让同一个目标在大量子图里反复出现验证结果虚高太低又把跨边界目标切断。这个参数看起来不起眼但对训练效果的影响比我预想的大得多。希望这篇复盘能让你少走几个我走过的弯路。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →