基于Python的道路坑洼检测:YOLO、Faster R-CNN、SSD多模型对比实战
简介这份资源是面向计算机视觉方向的课程设计与毕业设计参考项目聚焦道路坑洼检测任务适合计算机、人工智能、通信工程、自动化等专业学生及需要项目实战练习的学习者。项目以Python实现围绕AlexNet、LeNet-5及LeNet-5 2.0等多种算法模型展开对比实验可用于课程设计、期末大作业或毕设初期立项演示。压缩包共14个文件包含11个py源码、2个h5模型权重和1个md说明文档整体约10.49MB源码与训练好的模型均已测试运行成功便于直接复现与二次修改。资源已有155人学习下载作者为RuanJian_GC。读者可从中获得完整的坑洼检测实现流程、多模型对比思路、模型加载与预测脚本以及项目结构参考既能用于答辩展示也可在此基础上扩展其他检测功能。1. 道路坑洼检测从一段行车记录仪视频说起路面上的坑洼轻则让乘客颠一下重则爆胎、伤悬挂。市政巡检靠人眼扫街一天跑不了几十公里漏检率还高。把行车记录仪或巡检车摄像头拍到的画面交给计算机视觉模型自动框出坑洼位置这件事在工程上已经能跑通。这个标题里的「python源码模型多种算法模型对比」核心就是一套可复现的检测流程数据标注、模型训练、推理部署外加把 YOLO、Faster R-CNN、SSD 这类主流检测器放在同一份数据上比一比看谁在坑洼这种小目标、低对比度场景下更稳。适合做计算机视觉大作业的学生也适合想给养护系统加自动巡检模块的工程师。下面按「数据怎么准备 → 模型怎么选 → 怎么训 → 怎么比 → 坑在哪」推一遍。2. 数据与标注坑洼检测的第一道门槛2.1 为什么坑洼数据比想象中难标道路坑洼在图像里通常只占几十到几百像素边缘和阴影、水渍、井盖、修补痕迹高度相似。我见过不少开源数据集直接把「深色不规则区域」全标成坑洼训出来的模型把井盖当坑洼报上路就是灾难。常见做法是定义清楚标注边界只标路面结构层已经破损、有明显凹陷或材料剥落的区域阴影和水渍不标。标注格式优先选 YOLO 的 txt每行class x_center y_center width height归一化到 0~1因为后面换模型时转换成本最低。如果手头只有原始视频先用 ffmpeg 抽帧再筛掉模糊和重复帧。抽帧间隔别太密城市道路 30fps 视频每 10 帧取一张就够否则相邻帧几乎一样训出来模型对场景多样性不敏感。# 每 10 帧抽一张输出到 frames 目录 ffmpeg -i road.mp4 -vf selectnot(mod(n\,10)) -vsync vfr frames/frame_%05d.jpgselectnot(mod(n\,10))表示帧号能被 10 整除时保留-vsync vfr防止输出帧率错乱。抽完帧后建议用图像哈希去重否则同一处坑洼会出现几十张几乎一样的图训练集和验证集还会泄漏。2.2 标注工具与目录结构标注用 LabelImg 或 CVAT 都行导出 YOLO 格式。目录按下面组织后面训练脚本直接读这个结构dataset/ images/ train/ val/ labels/ train/ val/ data.yamldata.yaml内容path: ./dataset train: images/train val: images/val nc: 1 names: [pothole]nc是类别数坑洼检测通常就一类。如果还要区分「坑洼」和「修补」改成 2 并对应调整 names。标注完成后一定要写个脚本统计每张图的框数量和框面积分布框面积中位数低于图像面积 0.5% 时说明目标极小后面选模型和调 anchor 都要针对性处理。2.3 数据增强的边界坑洼检测的增强不能乱来。水平翻转、轻微旋转、亮度对比度扰动是安全的垂直翻转要谨慎因为路面纹理有方向性翻过来不自然马赛克增强Mosaic对小目标有帮助但四张图拼接后坑洼可能被裁掉一半建议开启但把概率控制在 0.5 左右。雨天、夜间样本少的话优先补真实数据别指望靠增强凭空造出夜间泛化能力。3. 模型选型YOLO、Faster R-CNN、SSD 到底怎么比3.1 三类检测器的本质差异YOLO 系列是单阶段检测器一次前向就出框和类别速度快适合巡检视频实时处理。Faster R-CNN 是两阶段先出候选区域再分类回归精度通常更高但推理慢适合离线批量分析。SSD 也是单阶段用多尺度特征图预测对小目标比早期 YOLO 友好但 anchor 设计敏感。坑洼属于小目标且背景复杂选型时不能只看 mAP还要看小目标召回率和推理帧率。我一般会先跑 YOLOv8n 或 YOLOv5s 作为基线因为训练快、社区资料多能快速判断数据质量。如果基线模型 mAP50 都上不去换 Faster R-CNN 也救不了问题在标注或数据分布。基线跑通后再上 Faster R-CNN 对比精度上限最后看 SSD 在边缘设备上的速度优势是否值得牺牲精度。3.2 统一实验配置才能公平对比多种算法模型对比最容易翻车的地方是每个模型用不同输入尺寸、不同 epoch、不同增强最后比出来的数字没有意义。正确做法是固定输入分辨率比如 640×640、固定训练轮数、固定数据划分只换模型结构。下面是一个统一的训练入口示例用 Ultralytics 跑 YOLO用 torchvision 跑 Faster R-CNN 和 SSDimport torch from ultralytics import YOLO # YOLO 基线训练 model YOLO(yolov8n.pt) model.train( datadataset/data.yaml, epochs100, imgsz640, batch16, device0, projectruns/pothole, nameyolov8n_baseline )imgsz640是输入边长batch16按显存调整device0指定第一块 GPU。训练日志里重点看metrics/mAP50(B)和metrics/mAP50-95(B)前者宽松后者严格。坑洼检测里 mAP50 高但 mAP50-95 低说明框的位置不够准可能是标注框偏大或回归损失权重问题。Faster R-CNN 用 torchvision 的预训练权重微调import torchvision from torchvision.models.detection.faster_rcnn import FastRCNNPredictor # 加载预训练 Faster R-CNN替换分类头为 2 类背景坑洼 model torchvision.models.detection.fasterrcnn_resnet50_fpn(weightsDEFAULT) in_features model.roi_heads.box_predictor.cls_score.in_features model.roi_heads.box_predictor FastRCNNPredictor(in_features, 2) # 优化器只调需要更新的参数 params [p for p in model.parameters() if p.requires_grad] optimizer torch.optim.SGD(params, lr0.005, momentum0.9, weight_decay0.0005)FastRCNNPredictor(in_features, 2)里 2 是背景加坑洼。Faster R-CNN 的输入是 0~1 归一化的 tensor 列表不是 YOLO 那种直接读 yaml数据加载要自己写 Dataset 返回(image_tensor, target_dict)target 里包含 boxes 和 labels。这一步写错的话训练 loss 会一直不降别问我是怎么知道的。3.3 对比指标怎么记录建一张表每个模型跑完后填一行至少包含 mAP50、mAP50-95、小目标召回率、单帧推理耗时、模型体积。小目标召回率可以按框面积小于 32×32 像素的样本单独统计这个指标比整体 mAP 更能反映坑洼检测的实际可用性。模型mAP50mAP50-95小目标召回推理耗时(ms)体积(MB)YOLOv8n待填待填待填待填待填Faster R-CNN待填待填待填待填待填SSD300待填待填待填待填待填表格里的数字必须来自同一验证集、同一置信度阈值。置信度阈值不统一比出来的召回率没有意义。4. 训练与推理把模型跑到能用的程度4.1 训练参数怎么设才不白跑学习率是最容易翻车的参数。YOLO 微调一般用 0.01 起步配合余弦退火Faster R-CNN 用 0.005 的 SGD。如果 loss 在前几个 epoch 剧烈震荡先把学习率降一个数量级。权重衰减设 0.0005防止过拟合。坑洼数据量通常不大几千张图就算多了所以早停patience20很有必要验证集 mAP 连续 20 轮不涨就停。另一个关键是冻结策略。用预训练权重时前几轮可以冻结 backbone只训检测头让模型先适应坑洼这个新类别再解冻全网络微调。Ultralytics 里用freeze10冻结前 10 层torchvision 里手动设置requires_gradFalse。4.2 推理脚本与后处理训练完导出权重后推理脚本要处理视频流和单图两种输入。YOLO 的推理很直接from ultralytics import YOLO model YOLO(runs/pothole/yolov8n_baseline/weights/best.pt) results model.predict( sourcetest_video.mp4, conf0.35, iou0.45, saveTrue, projectruns/detect, namepothole_result )conf0.35是置信度阈值低于它的框不输出iou0.45是 NMS 的 IoU 阈值控制重叠框合并。坑洼检测里 conf 设太低会满屏误报设太高会漏掉浅坑建议在验证集上画 P-R 曲线选拐点。saveTrue会把带框的视频存下来方便肉眼复核。Faster R-CNN 推理要手动做 NMS 和阈值过滤torchvision 的detection.fasterrcnn_resnet50_fpn输出已经是后处理过的但置信度阈值要自己卡。推理时记得model.eval()和torch.no_grad()否则显存会爆。4.3 部署前的量化与加速如果要在 Jetson 或树莓派上跑YOLOv8n 导出 ONNX 再转 TensorRT 是常见路线。导出命令yolo export modelbest.pt formatengine halfTrue device0halfTrue用 FP16 精度速度提升明显精度掉得不多。Faster R-CNN 部署相对麻烦算子多TensorRT 支持不如 YOLO 好边缘设备上一般优先选 YOLO 或 SSD。量化后一定要在验证集上重新跑一遍 mAP确认掉点可接受别直接上线。5. 避坑与排查那些让实验白跑的细节5.1 验证集 mAP 很高实拍视频全是误报现象验证集 mAP50 到 0.85拿手机拍一段路测视频模型把井盖、阴影、车道线全框成坑洼。原因通常是训练集和验证集来自同一段视频或同一路段分布太像模型没学到泛化特征。解决按路段划分数据集训练集和验证集不能有同一路段的帧补入不同光照、不同路面的负样本尤其是井盖和修补痕迹。5.2 训练 loss 正常但 mAP 一直是 0现象YOLO 训练 loss 在降但验证 mAP 始终为 0。原因多半是 data.yaml 路径写错或标签格式不对模型实际在学背景。解决先跑一遍yolo checks确认数据能被正确读取再可视化几张训练图的标注框确认框和坑洼对齐检查标签文件里坐标是否归一化有没有超出 0~1 范围。5.3 显存不够batch 调小后 mAP 掉得厉害现象batch 从 16 降到 4 后mAP 掉 5 个点以上。原因是小 batch 下 BN 层统计量不稳定梯度噪声大。解决改用梯度累积batch4但累积 4 次等效 batch16或者换更小的输入尺寸但输入尺寸太小会进一步恶化小目标检测坑洼场景不建议低于 512。5.4 模型把水渍当坑洼雨天误报翻倍现象晴天正常雨天视频里水渍被大量误检。原因是训练集缺少雨天样本模型把「深色反光区域」和坑洼关联了。解决补雨天标注数据水渍明确标为背景推理时如果知道是雨天可以适当提高 conf 阈值但根本办法还是数据覆盖。5.5 多种模型对比时Faster R-CNN 训练不收敛现象Faster R-CNN 的 loss 震荡或直接 NaN。原因常见于学习率过高、数据归一化不一致、target 里 boxes 格式错误。解决学习率降到 0.001 试确认图像 tensor 是 0~1 且通道顺序为 CHWboxes 必须是[x_min, y_min, x_max, y_max]且归一化到图像尺寸不是 YOLO 的 center 格式。格式转错是最高频的翻车点。6. 进阶技巧用切片推理把远处小坑洼捞回来坑洼在图像里往往集中在画面下半部分远处路面上的坑只有十几个像素直接整图推理很容易漏。一个实用技巧是切片推理SAHI 思路把原图切成有重叠的小块每块单独推理再把结果映射回原图做 NMS。这样小目标在局部图里相对变大召回率能明显提升代价是推理耗时增加。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction # 加载 YOLO 权重做切片推理 detection_model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathbest.pt, confidence_threshold0.3, devicecuda:0 ) result get_sliced_prediction( road_far.jpg, detection_model, slice_height320, slice_width320, overlap_height_ratio0.2, overlap_width_ratio0.2 ) result.export_visuals(export_dirruns/sahi)slice_height和slice_width是切片尺寸320 适合 640 原图切四块overlap_ratio0.2保证边缘目标不被切断。切片太小会引入大量背景块推理变慢切片太大又失去小目标放大的意义。我一般从 320 起步在验证集上对比切片前后的召回率涨点不明显就调回整图推理。另一个技巧是测试时增强TTA对同一张图做水平翻转和多尺度推理把结果融合。TTA 能涨 1~2 个点 mAP但推理时间翻倍实时巡检场景要权衡。如果只是离线出报告TTA 值得开。验证模型是否真的可用别只看 mAP。我会额外做两件事一是把验证集里漏检和误检的图各挑 20 张逐张看原因归类是标注问题、光照问题还是模型容量问题二是拿一段完全没参与训练的路测视频跑一遍统计每公里误报次数和漏报次数。这两个数字比 mAP 更能说服自己这个模型能不能上线。踩过的坑里最贵的一个是数据集泄漏训练集和验证集有同一段视频的相邻帧mAP 虚高到 0.9实际路测一塌糊涂。从那以后我划分数据集一定按视频源或路段分绝不按帧随机分。希望帮到你。本文还有配套的精品资源点击获取