轨道检测与障碍物识别:Canny+霍夫变换+YOLOv5实战解析 简介一套面向电车轨道与障碍物检测的目标检测项目整合传统数字图像处理与YOLOv5深度学习算法适合计算机相关专业学生、教师及开发者用于课程设计、毕业设计或算法学习。项目先采用边缘检测、透视变换、霍夫变换标注轨道并划定感兴趣区域再借助YOLOv5模型对区域内障碍物进行实时识别与标注白天和夜晚条件下均有较好效果实测处理速度约为十七帧每秒。压缩包内共有六十四个文件以配置文件、Python脚本、示例图片为主同时包含Shell脚本、Markdown说明、Jupyter笔记本、Dockerfile等便于环境搭建、模型配置与二次开发整体压缩后大小仅约九百六十一千字节。已有111人学习下载。资料提供从轨道检测、区域提取到障碍物识别的完整代码管线附有测试图片、模型配置文件和使用说明文档代码均通过运行验证可直接上手学习也能够在此基础上扩展其他检测功能。1. 轨道检测和障碍物识别混搭不是炫技电车轨道检测有个反直觉的事实仅用YOLOv5端到端识别轨道白天勉强能用晚上几乎不可靠因为轨道是细长线状目标标注成本高且小目标特征弱。而传统数字图像处理里的边缘检测、霍夫变换却能稳稳锁定轨道线代价是无法判断轨道上有什么。这套SJTU课程设计把两者串成一条流水线先用Canny霍夫变换求轨道线再得到矩形ROI最后把ROI交给YOLOv5做障碍物识别输出帧率约17FPS。项目代码按python工程组织含calImage、line、pipeline、detect、vedio等模块适合做课设、毕设也适合想搞懂目标检测预处理逻辑的工程师。它不是把两个模型堆在一起而是让传统算法替深度模型做了一次空间注意力。2. 从边缘检测到透视变换轨道ROI提取与坐标系矫正轨道检测的第一步不是跑网络而是先搞清楚轨道在图像里的几何规律。电车轨道在画面中通常呈两条近似直线交于灭点只要把它们提取出来就能框出火车驶来的方向区域。常见做法是Canny边缘检测 霍夫直线检测 透视变换。下面拆开讲。2.1 Canny边缘检测与形态学闭运算的配合Canny对光照敏感但白天和夜晚的轨道边缘都有一个共同点轨道与道床之间的灰度跳变是局部的。用Canny前先转灰度再高斯模糊去掉细纹理。核心参数是threshold1和threshold2过高会把夜间昏暗轨道过滤掉过低会引入大量道砟边缘。我一般先设threshold150, threshold2150再按视频亮度上下浮动。import cv2 import numpy as np def get_edges(frame): gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) blur cv2.GaussianBlur(gray, (5, 5), 0) edges cv2.Canny(blur, 50, 150) kernel cv2.getStructuringElement(cv2.MORPH_RECT, (5, 3)) closed cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel) return closed这里Canny先给出二值边缘再闭运算把断成一段段的轨道线连起来。闭运算的结构元用宽5高3的矩形因为轨道在图像里是水平延展的曲线宽度方向有轻微斜度如果结构元太大会把相邻两条轨道粘在一起太小则夜间补不上断口。这个细节直接影响后续霍夫变换能不能检出完整直线。2.2 霍夫直线检测与轨道线聚类得到闭合边缘后用cv2.HoughLinesP检测直线段。HoughLinesP是概率霍夫比标准霍夫快且输出线段端点。要特别注意minLineLength和maxLineGap两个参数minLineLength设太短会把枕木阴影、路边护栏的短边缘也选成候选设太长夜间轨道边缘断续时可能检不出。实测中minLineLength设为80像素maxLineGap设为20像素能兼顾白天和夜间。lines cv2.HoughLinesP(closed, rho1, thetanp.pi/180, threshold50, minLineLength80, maxLineGap20) left_lines, right_lines [], [] if lines is not None: for line in lines: x1, y1, x2, y2 line[0] k (y2 - y1) / (x2 - x1 1e-6) if k -0.3: left_lines.append(line[0]) elif k 0.3: right_lines.append(line[0])这里按斜率粗略分类图像坐标系y轴向下电车轨道向左远方延伸时斜率为负向右延伸为正。之后对左右两组线段分别取最长的几条做最小二乘拟合得到轨道直线方程。注意不能用平均斜率代替拟合因为近处轨道在画面中占比大远处占小简单平均会高估远端的收敛角度。2.3 透视变换矩阵计算与ROI掩膜生成得到左右轨道直线后可以计算它们在图像平面内的交点作为灭点再结合画面底部的两个端点构成一个梯形。这个梯形是轨道区域的自然表示。但YOLOv5的输入是矩形训练时多是正方形缩放直接把梯形送给网络会拉伸目标比例。所以要做一个透视变换把梯形矫正成矩形。pts_src np.float32([[x_left_bottom, y_bottom], [x_right_bottom, y_bottom], [x_right_top, y_top], [x_left_top, y_top]]) pts_dst np.float32([[0, height], [width, height], [width, 0], [0, 0]]) M cv2.getPerspectiveTransform(pts_src, pts_dst) bird_view cv2.warpPerspective(frame, M, (width, height)) mask np.zeros((height, width, 3), dtypenp.uint8) cv2.fillPoly(mask, [np.int32(pts_src)], (255, 255, 255))M就是透视变换矩阵。warpPerspective把原始图像投影到一个虚拟俯视角坐标系中后续YOLOv5的推理既可以在这个鸟瞰图里做也可以把矩形ROI反变换回原图做。注意pts_dst的width和height应当和YOLOv5输入尺寸对齐否则后面坐标映射时要再做一次缩放容易出错。mask的作用是限定障碍物检测的有效范围把轨道区域外的电线杆、行人过滤掉。3. 基于YOLOv5的障碍物识别模型选型与检测流程轨道区域框出来之后真正的目标是识别轨道上的障碍物。项目选的是YOLOv5这里不光是会用的问题还要知道为什么在课设里选它而不是Faster R-CNN或SSD。3.1 选择YOLOv5s作为基础模型的原因YOLOv5s是yolov5网络结构中最小的标准版本参数量大约7.2M输入640x640时单帧推理在GTX1660上大约5ms加上前后处理能到17FPS正好满足本项目视频流的实时需求。而Faster R-CNN在同等精度下推理速度慢一个数量级SSD对小型障碍物如石块、锥桶召回率低。更重要的是YOLOv5的工程配套完善detect.py直接支持摄像头、视频和图片训练脚本自带数据增强配好环境和数据集就能跑适合课程设计周期。障碍物类别一般定义成person、bicycle、car、truck、cone、barrier等因为电车轨道上的障碍物多是行人或停放的车辆。如果检测目标限定在轨道范围内类别数不超过6个时YOLOv5s在公开COCO预训练权重上微调即可不需要从头训练。3.2 detect.py推理链路与参数配置项目中的detect.py基于YOLOv5官方源码主要改动了两个地方一是读取视频帧后先调用pipeline.py得到ROI mask二是把检测结果框与mask做逻辑与操作滤除区域外框。启动推理的命令常见做法是python detect.py --weights best.pt --source vedio.mp4 \ --img-size 640 --conf-thres 0.45 --iou-thres 0.45 \ --device 0 --project output --exist-ok参数含义weights训练好的权重文件课程设计里一般用val集上mAP最高的权重而非最后一轮权重。source输入视频或图片路径也可以设为0调用摄像头。conf-thres置信度阈值过滤低置信度框。白天可设0.45夜间会适当降到0.35因为夜间检测框得分整体偏低。iou-thresNMS的IoU阈值0.45是YOLOv5默认值重叠目标多时改成0.3更保守。img-size推理尺寸640对速度与精度平衡最好480能提升FPS但小障碍物容易漏。3.3 白天/夜晚样本增强与训练细节项目要求同时处理白天和夜晚两种环境所以训练数据不能只用白天图像。YOLOv5自带的Mosaic增强把四张图拼成一张能增强小目标与遮挡鲁棒性但对夜晚样本Mosaic反而可能让夜间目标被白天背景稀释。常见做法是在数据集中按1:1混入白天与夜晚帧然后单独关闭夜间样本的RandomPerspective或者对夜间图做一次等宽Gamma校正。超参数建议值说明epochs150微调时100-200都行看验证损失是否收敛batch-size16取决于显存8G显存建议8lr00.01预训练权重微调用0.01随机初始化用0.1mosaic0.5概率0.5夜间数据占比高时调低fliplr0.25轨道目标左/右翻转仍合理但太高会破坏灭点方向这里特别要提一句yolov5训练自己的数据集时一定要确认data.yaml里的nc和names与实际标注一致。项目中常见错误是标注类别索引从0开始但训练时写了从1开始导致所有标签偏移一位检测框全部错位。检查方法很简单训练前运行python train.py --data data.yaml --weights yolov5s.pt观察第一个epoch的loss是否有明显下降若震荡不降多半是标签问题。4. 轨道与障碍物结果融合坐标映射与性能优化模型单独跑通只是第一步。实际视频里YOLOv5输出的是640x640坐标系的矩形框必须与原始画面坐标对齐同时还要受ROI约束。这个融合模块会决定检测结果看起来“准不准”。4.1 ROI区域映射与置信度过滤如果推理在原始图像上进行那么检测框坐标就是原始坐标直接用cv2.pointPolygonTest判断框底边中点是否落在ROI多边形内。如果推理在鸟瞰图里进行则需要用透视变换矩阵的逆矩阵把检测框四个角点映射回原图再做同一个判断。pts_src trailer_roi # 梯形ROI四个点由line.py输出 def in_roi(box, roi_pts): cx (box[0] box[2]) / 2 cy (box[1] box[3]) / 2 return cv2.pointPolygonTest(roi_pts, (cx, cy), False) 0 filtered [b for b in detections if in_roi(b, pts_src)]这里用框底边中心点而不是整个框来判断是因为障碍物与轨道的接触点通常在地面附近如果框的上半部分如行人头部在ROI外但脚在ROI内应该保留反过来如果底边中心在ROI外即便框的上边缘压线也应该剔除。用框的中心点会误留很多路旁行人实测漏检和误检都会上升。注意pointPolygonTest的第三个参数设置成False表示只返回点在多边形内部还是外部不加距离计算速度最快。4.2 帧间处理与FPS优化策略17FPS来自几个取舍。第一是推理分辨率本项目最终选择640但关闭了类别输出第二是启用半精度推理detect.py中加一句model.half()在GTX 16系以上显卡上能把推理延迟降低约30%第三是视频解码用cv2.VideoCapture直接读不做逐帧缩放而是只在送入模型前resize。这三个改动组合常见效果稳定。另一个更激进的方法是跳帧每两帧只对一帧做YOLOv5检测不做检测的帧直接沿用上一帧的检测结果配合简单的KCF跟踪能把总体帧率提高到25FPS。课程设计答辩时可以用这个方案展示“实时效果”但要注意评估指标里要注明实际推理帧率是17FPS跳帧属于后处理优化。4.3 常见误检分析路灯、信号灯与反光夜间场景中YOLOv5容易把亮度集中的路灯灯头、信号灯和轨道反光区域当作障碍物。原因很简单conf阈值降低后这些高对比目标与障碍物特征接近。处理方式不只有调阈值把ROI底边中心点的判断改成“地面接触点”压线信息比框中心更可靠。对检测类别做先验限制比如轨道内出现“car”且位置固定不动连续30帧没有位移就降低其置信度并标记为静态物体不作为紧急障碍物告警。对反光带可以在预处理里增加一个对比度归一化让反光区域与障碍物的纹理差别更大。注意不能只靠颜色过滤因为夜间列车灯光会把轨道照射成亮黄色与警告锥桶颜色接近。5. 从课程设计到落地验证指标与调参技巧课设不能只停在“能跑”还要让评估结果可复现。这里分享验证指标和调参的具体做法这两项做扎实了答辩才能从“效果较好”变成“结果可信”。5.1 用mAP0.5和漏检率评估检测效果课程设计里不能只说“效果较好”需要给量化指标。常见做法是在标注好的测试视频帧上统计mAP0.5。这里给出一个轻量级评估脚本import torch from pathlib import Path from utils.metrics import ap_per_class def evaluate(dataloader, model, iou_thres0.5): stats [] for images, targets in dataloader: preds model(images)[0] # 将preds转为(x1y1x2y2, conf, cls)格式 for batch_idx, pred in enumerate(preds): target targets[targets[:, 0] batch_idx] stats.append((pred.cpu(), target.cpu())) # 调用YOLOv5官方metrics计算AP p, r, ap, f1, _ ap_per_class(*stats, plotFalse, save_dirPath(.)) return ap.mean(), r.mean(), p.mean()这个脚本直接用YOLOv5源码里的ap_per_class省去自己实现IoU匹配。测试时要注意每类样本数量不能太少至少每个类别超过50个真实框否则mAP做出来不稳定。除了mAP0.5还要统计漏检率针对视频里连续出现的同一障碍物只要在连续10帧中有一帧没检测到就算一次漏检。这个指标对轨道障碍物比mAP更敏感因为行人一旦漏检一帧后续跟踪就会丢失。5.2 超参数调整优先级与踩坑记录调参与其说按经验不如按优先级排查。我一般会这样收敛先固定conf-thres0.4看无效检测框是太多还是太少太多说明类别混淆严重应回头检查数据集标注太少则明显漏检说明模型欠拟合或阈值不合适。再看NMS的iou-thres检测框重叠度高时降低到0.3不要盲目用默认值。最后才动模型超参数比如学习率从0.01减到0.005用余弦退火观察loss曲线是否平滑。整个过程要记录每个版本在验证集上的mAP和漏检率而不是只看demo视频。踩坑记录中最常见的有几个OpenCV版本影响透视变换结果OpenCV 4.5以上对坐标精度有变化课设中最好固定python3.8, opencv-python4.5.5.64。中文路径问题视频文件名或图片路径含中文时cv2.VideoCapture会读取失败detect.py报错找不到文件。把工程路径统一为英文小写。权重文件路径.pt文件是相对路径打包的把best.pt移到其他目录后要同步复制模型对应的yaml文件否则会报yaml not found。最容易被忽略的是eval期间的半精度开关训练时用了model.half()测试时如果忘记调成float32会得到精度降低的框特别是小目标上。还有一个实用技巧把pipeline.py中的轨道检测过程单独抽出来输出一张可视化图叠加Canny边缘和轨道直线。这样在答辩时可以清楚展示“数字图像处理”部分的中间结果说明算法不黑盒。检测模型只在ROI中有意义轨道线的质量决定了障碍物检测的上限。本文还有配套的精品资源点击获取