尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

YOLOv8铁路轨道缺陷检测:从数据集到RK3588部署全流程

YOLOv8铁路轨道缺陷检测:从数据集到RK3588部署全流程 简介这份资源是面向计算机、人工智能、自动化等专业学生与开发者的铁路轨道检测项目实战包基于YOLOv8目标检测框架构建可用于毕业设计、课程设计或大作业帮助读者快速搭建一套可运行的轨道缺陷识别系统。压缩包共97个文件约24.21MB以70个Python源码文件为核心辅以4个pt模型权重、5个xml配置、12个pyc缓存及mp4演示视频、ico图标等覆盖模型训练、推理检测与可视化界面等模块。资源内含完整数据集、可视化页面与部署说明可生成核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线及验证集预测结果并附有README说明与训练脚本便于理解工程结构与排错思路。目前已有46人学习适合希望以较低部署成本完成目标检测项目实践、并在此基础上二次开发的学习者参考。1. 铁路轨道检测为什么值得用 YOLOv8 重做一遍铁路轨道检测这个方向过去几年在工业检测圈一直是个看起来简单、做起来全是坑的活。传统做法要么靠人工巡检要么用传统图像处理——边缘检测加霍夫变换找钢轨边缘再配合阈值分割判断扣件缺失。这套方案在光照均匀、轨道干净的场景下能跑但一到隧道口明暗交替、雨雪天反光、道砟飞溅遮挡误报率立刻飙升。YOLOv8 这类单阶段检测器之所以适合切入这个场景核心原因是它把找轨道区域和判断缺陷类别合并成一个端到端的回归问题不再依赖手工特征对光照和遮挡的鲁棒性天然更好。这套源码数据集可视化界面部署教程的组合本质上解决的是从零搭建一套轨道缺陷检测系统的完整链路问题。适合三类人做毕设或课程设计的学生需要一套能跑通、能改、能写进论文的完整工程刚转岗到工业视觉的工程师想拿一个真实场景练手 YOLOv8 的训练和部署以及需要快速验证轨道检测可行性的团队拿它当 baseline 再往上叠改进。下面按数据怎么准备→模型怎么训→界面怎么搭→部署怎么落→坑在哪的顺序拆开讲。2. 数据集准备从原始轨道图到 YOLOv8 可训练的标签2.1 轨道缺陷检测的数据集长什么样铁路轨道检测的标注体系通常围绕几类核心缺陷展开钢轨表面裂纹、扣件缺失或松动、轨道异物、轨枕破损。不同项目标注粒度不同有的只标缺陷区域一个类有的细分到七八类。从工程落地角度看类别不是越多越好——类别越多每类样本越少模型越容易在长尾类上翻车。我一般建议起步阶段控制在 4 到 6 类等 baseline 跑通、mAP 稳定后再考虑细分。数据集格式上YOLOv8 要求的是 YOLO 格式每张图对应一个同名.txt文件每行是类别索引 中心x 中心y 宽 高坐标全部归一化到 0 到 1 之间。如果你手头是 VOC 的 XML 或者 COCO 的 JSON需要先转换。这里有个血泪经验转换脚本一定要做坐标越界检查标注框超出图像边界的样本在训练时会直接报错或者产生异常梯度而且这种错误在几千张图里肉眼根本看不出来。2.2 用脚本把 VOC 标注转成 YOLO 格式假设你拿到的原始数据是 VOC 格式目录结构是Annotations/放 XMLJPEGImages/放图片。下面这个转换脚本我用了很多次加了越界裁剪和类别映射import os import xml.etree.ElementTree as ET from PIL import Image # 类别映射根据你的实际标注类别修改 CLASS_MAP {crack: 0, missing_fastener: 1, foreign_object: 2, broken_sleeper: 3} def convert_voc_to_yolo(xml_dir, img_dir, out_dir): os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() # 读取图像真实尺寸用于归一化 img_name root.find(filename).text img_path os.path.join(img_dir, img_name) with Image.open(img_path) as im: w, h im.size lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in CLASS_MAP: continue cls_id CLASS_MAP[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 越界裁剪防止标注框超出图像范围 xmin, xmax max(0, xmin), min(w, xmax) ymin, ymax max(0, ymin), min(h, ymax) if xmax xmin or ymax ymin: continue # 裁剪后无效的框直接丢弃 cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) # 写出同名 txt txt_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines)) convert_voc_to_yolo(data/Annotations, data/JPEGImages, data/labels)这段代码的关键点有三个。第一CLASS_MAP必须和你的data.yaml里的names顺序严格一致否则训练出来的模型会把裂纹识别成扣件缺失而且 loss 曲线看起来还挺正常属于典型的玄学翻车。第二越界裁剪那两行max(0, xmin)和min(w, xmax)是后悔药没有它标注工具手抖画出去的框会让训练在某个 epoch 突然崩掉。第三归一化用.6f保留六位小数YOLOv8 官方脚本对精度不敏感但保留足够位数能避免小目标框在缩放后坐标塌缩。2.3 数据集划分与 data.yaml 配置转换完标签后按 8:1:1 划分训练集、验证集、测试集。轨道检测数据有个特点同一段轨道连续拍摄的帧之间高度相似如果随机划分验证集里会出现和训练集几乎一样的图导致验证指标虚高。正确做法是按区段划分——同一段轨道的图要么全在训练集要么全在验证集。这个细节很多开源数据集没处理好直接拿来用会高估模型泛化能力。data.yaml的写法path: /home/user/railway_dataset train: images/train val: images/val test: images/test nc: 4 names: [crack, missing_fastener, foreign_object, broken_sleeper]nc是类别数必须和names长度一致。path用绝对路径最稳相对路径在不同工作目录下启动训练时容易找不到文件。3. 训练 YOLOv8参数怎么设、曲线怎么看3.1 环境配置与最小训练命令环境这块Python 3.8 到 3.10 都行PyTorch 建议 2.0 以上。装 ultralytics 一条命令pip install ultralytics如果你的显卡是 GTX 1660 Ti 这类 6G 显存的卡训练时 batch size 要压到 8 甚至 4否则直接 OOM。别硬撑显存不够时降 batch 比降分辨率对精度影响小。最小训练命令yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch8 \ device0 \ projectruns/railway \ nameexp1modelyolov8n.pt用的是 nano 版本参数量小、推理快适合先跑通流程。如果 mAP 上不去再换yolov8s.pt或yolov8m.pt。imgsz640是默认值轨道缺陷里裂纹属于细长目标如果发现小裂纹漏检严重可以提到 1024但显存占用会翻倍不止。3.2 损失函数曲线怎么读训练启动后runs/railway/exp1/下会生成results.csv和一堆曲线图。重点看三条线train/box_loss、val/box_loss、metrics/mAP50。正常情况train loss 和 val loss 同步下降mAP50 稳步上升最后趋于平缓。如果 train loss 还在降但 val loss 开始抬头说明过拟合了这时候要么加数据增强要么早停。YOLOv8 默认开了mosaic增强对轨道这种纹理重复度高的场景很有效但mosaic概率设太高会让小目标在拼接后变得更小反而伤害裂纹检测。我一般把mosaic从默认的 1.0 降到 0.5 到 0.7 之间。如果 mAP50 从第一个 epoch 就卡在很低的值不动先别怀疑模型去检查标签。用下面这段代码可视化几张训练图上的标注框确认框的位置和类别都对import cv2 import os def draw_yolo_labels(img_path, label_path, class_names): img cv2.imread(img_path) h, w img.shape[:2] with open(label_path) as f: for line in f: cls_id, cx, cy, bw, bh map(float, line.split()) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[int(cls_id)], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(check_vis.jpg, img) draw_yolo_labels(data/images/train/001.jpg, data/labels/train/001.txt, [crack, missing_fastener, foreign_object, broken_sleeper])跑完打开check_vis.jpg如果框的位置明显偏移或者类别标错问题就在数据侧调参救不回来。3.3 关键训练参数的含义与调整方向参数默认值作用轨道检测建议epochs100训练轮数数据少时 150-200配合早停batch16批大小按显存压6G 卡用 4-8imgsz640输入分辨率小缺陷多用 1024lr00.01初始学习率微调时降到 0.001mosaic1.0马赛克增强概率降到 0.5-0.7patience50早停耐心值数据少时降到 20-30lr0这个参数值得单独说。如果你是从yolov8n.pt预训练权重开始微调学习率保持 0.01 没问题但如果你在已有模型上继续训练自己的数据学习率要降到 0.001 甚至更低否则会把预训练学到的通用特征直接冲掉表现为训练初期 mAP 先掉一大截再慢慢爬回来。4. 可视化界面用 Gradio 搭一个能演示的检测面板4.1 为什么选 Gradio 而不是 PyQt毕设和课程设计场景下界面第一要求是能演示、好截图、方便写进论文。PyQt 功能强但代码量大一个检测界面动辄几百行调试成本高。Gradio 几十行就能搭出一个带图片上传、结果展示、参数调节的 Web 界面浏览器直接打开答辩时投屏也方便。缺点是定制性弱但对这个场景够用。4.2 检测界面的最小实现import gradio as gr from ultralytics import YOLO model YOLO(runs/railway/exp1/weights/best.pt) def detect(image, conf_threshold): results model.predict(image, confconf_threshold, imgsz640) # results[0].plot() 返回带框的 numpy 数组 annotated results[0].plot() # 统计各类别数量 boxes results[0].boxes counts {} for cls_id in boxes.cls.tolist(): name model.names[int(cls_id)] counts[name] counts.get(name, 0) 1 summary | .join([f{k}: {v} for k, v in counts.items()]) or 未检测到缺陷 return annotated, summary with gr.Blocks() as demo: gr.Markdown(## 铁路轨道缺陷检测) with gr.Row(): img_input gr.Image(typenumpy, label上传轨道图片) img_output gr.Image(label检测结果) conf_slider gr.Slider(0.1, 0.9, value0.25, label置信度阈值) text_output gr.Textbox(label缺陷统计) btn gr.Button(开始检测) btn.click(detect, inputs[img_input, conf_slider], outputs[img_output, text_output]) demo.launch(server_name0.0.0.0, server_port7860)conf参数控制置信度阈值默认 0.25。轨道检测里这个值调低会引入大量误报——道砟的纹理容易被误判成裂纹调高则漏检增加。演示场景下 0.3 到 0.4 之间比较平衡。results[0].plot()直接返回画好框的图省去手动画框的代码。server_name0.0.0.0让局域网内其他设备也能访问答辩时用手机或平板演示很方便。4.3 界面里值得加的两个实用功能第一个是批量检测。把gr.Image换成gr.Files循环处理每张图输出一个 ZIP 包。第二个是视频检测。用gr.Video输入逐帧推理后用cv2.VideoWriter写回视频文件。视频检测要注意帧率——YOLOv8n 在 1660 Ti 上单帧推理大约 10 到 15 毫秒但加上读写和画框实际处理速度会降到 20 到 30 FPS如果原视频是 60 FPS输出会变慢需要做帧丢弃或者加速播放。5. 部署落地从本地脚本到 RK3588 边缘设备5.1 部署前必须做的模型导出训练完的.pt文件不能直接扔到边缘设备上跑需要先导出成通用格式。RK3588 这类芯片通常走 ONNX 转 RKNN 的路线# 导出 ONNXopset 用 12 兼容性最好 yolo export modelruns/railway/exp1/weights/best.pt formatonnx opset12 simplifyTruesimplifyTrue会调用 onnx-simplifier 做图优化去掉冗余算子。opset12是经验值版本太高某些转换工具不认太低会缺算子支持。导出后在本地用 onnxruntime 跑一张图验证输出 shape 是否正确别等到设备上才发现问题。5.2 RK3588 部署的关键步骤RK3588 部署 YOLOv8 的链路是ONNX → RKNN → 板端推理。用 RKNN-Toolkit2 转换from rknn.api import RKNN rknn RKNN() # 加载 ONNX指定输入尺寸 rknn.config(mean_values[[0, 0, 0]], std_values[[255, 255, 255]], target_platformrk3588) rknn.load_onnx(modelbest.onnx) # 量化用几十张训练图做校准精度损失可控 rknn.build(do_quantizationTrue, datasetcalib_list.txt) rknn.export_rknn(best.rknn)do_quantizationTrue开启 INT8 量化模型体积缩小约 4 倍推理速度提升明显但精度会掉 1 到 3 个点。calib_list.txt里放校准图片的路径列表建议从训练集里随机抽 50 到 100 张覆盖不同光照和缺陷类型。如果量化后 mAP 掉太多可以改成混合量化把检测头部分保持 FP16。板端推理用 RKNN 的 Python API 或 C API 加载.rknn文件前处理resize、归一化和后处理NMS、坐标还原需要自己写。后处理里的 NMS 阈值建议设 0.45和训练时保持一致。5.3 部署到服务器或本地机器的轻量方案如果不需要边缘设备直接在有 GPU 的服务器上跑用 FastAPI 包一层 HTTP 接口就够了from fastapi import FastAPI, UploadFile from ultralytics import YOLO import numpy as np import cv2 app FastAPI() model YOLO(best.pt) app.post(/detect) async def detect(file: UploadFile): contents await file.read() img cv2.imdecode(np.frombuffer(contents, np.uint8), cv2.IMREAD_COLOR) results model.predict(img, conf0.3) boxes results[0].boxes.xyxy.tolist() return {count: len(boxes), boxes: boxes}启动命令uvicorn main:app --host 0.0.0.0 --port 8000。这个方案适合把检测能力集成到已有系统里前端传图、后端返回 JSON解耦干净。6. 避坑与排查轨道检测里最容易翻车的五个地方6.1 验证集指标很高但实际用起来全是误报现象训练完 mAP50 到 0.9 以上拿新拍的轨道图一测道砟和阴影被大量框成裂纹。原因训练集和验证集来自同一段轨道、同一批次拍摄分布几乎一样。模型学到的是这段轨道的纹理特征而不是裂纹的通用特征。解决按区段划分数据集验证集必须来自不同时间、不同地点拍摄的轨道图。如果数据量不够至少做一次跨区段测试把真实泛化能力摸清楚。6.2 训练到一半 loss 突然变成 NaN现象前几十个 epoch 正常突然 loss 爆成 NaN训练中断。原因大概率是标注框有越界或者宽高为负的脏数据也可能是学习率太高导致梯度爆炸。解决先用 2.2 节的转换脚本做越界裁剪再检查data.yaml里的路径有没有中文或空格。学习率方面微调场景把lr0降到 0.001并加warmup_epochs3让学习率从低到高预热。6.3 小裂纹漏检严重现象大块缺陷能检出细长裂纹几乎全漏。原因YOLOv8 默认 640 分辨率下几个像素宽的裂纹在特征图上只剩不到一个像素下采样后信息丢失。解决把imgsz提到 1024 或 1280同时在data.yaml同级加一个hyp.yaml把scale增强的上限调低比如 0.3避免小目标被进一步缩小。如果还不行考虑在模型里加一个 P2 检测头专门处理高分辨率特征图。6.4 RK3588 上推理结果和 PC 端对不上现象同一个模型PC 上检测正常RK3588 上框的位置偏移或者类别全乱。原因前处理不一致。PC 端 ultralytics 自动做了 letterbox 填充板端如果直接 resize 会改变宽高比导致坐标映射错位。解决板端前处理必须复现 letterbox 逻辑——按长边缩放、短边填充灰边记录缩放比例和填充偏移后处理时反向映射回原图坐标。这个细节差一个像素框就会偏。6.5 Gradio 界面在服务器上启动后外部访问不了现象本地demo.launch()能打开放到服务器上浏览器访问超时。原因Gradio 默认只监听127.0.0.1且服务器防火墙没放行端口。解决launch时加server_name0.0.0.0并确认服务器安全组放行了对应端口。如果服务器在内网还需要做端口转发或者用 Nginx 反代。7. 把 mAP 再往上推两个点的三个技巧baseline 跑通之后大部分人卡在 mAP 0.85 左右上不去。分享三个我实际用过、代价小收益明显的技巧。第一个是用 SAHI 做切片推理。轨道图里裂纹和扣件尺寸差异极大整图推理时小目标容易被忽略。SAHI 的思路是把大图切成有重叠的小块每块单独推理再合并结果。对 4000×3000 的轨道巡检图切成 640×640、重叠 20% 的块小目标召回率能提升 5 到 10 个点。代价是推理时间线性增加适合离线检测不适合实时。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathbest.pt, confidence_threshold0.3, devicecuda:0 ) result get_sliced_prediction( railway.jpg, detection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2 ) result.export_visuals(export_dirsahi_output/)overlap比例设 0.2 是平衡速度和召回的经验值设太低切缝处的目标会被截断设太高重复框增多、NMS 压力大。第二个是在检测头加一个针对小目标的 P2 层。YOLOv8 默认从 P3 开始检测P2 层分辨率更高适合小目标。改法是修改模型 YAML在 backbone 输出里多接一个 P2 分支到 head。这个改动会增加参数量和显存占用1660 Ti 上可能要把 batch 降到 4。第三个是用测试时增强TTA。推理时对同一张图做水平翻转、多尺度缩放把多次结果融合。YOLOv8 自带augmentTrue参数yolo detect predict modelbest.pt sourcetest_images/ augmentTrue conf0.3TTA 通常能涨 1 到 2 个点 mAP但推理速度慢 3 倍左右。适合对精度要求高、对速度不敏感的场景比如离线巡检报告生成。这三个技巧不用全上按你的场景选。实时检测优先保速度离线分析优先保精度。我自己做轨道巡检项目时最后稳定用的是 SAHI 切片加 P2 检测头的组合mAP50 从 0.86 推到 0.91代价是单张 4000×3000 图的处理时间从 0.3 秒涨到 2.1 秒但离线场景完全能接受。希望帮到你。本文还有配套的精品资源点击获取
返回列表