YOLOv8路面坑洼检测实战:从训练到边缘部署全链路

发布时间:2026/10/11 3:14:51
YOLOv8路面坑洼检测实战:从训练到边缘部署全链路
简介这份资源面向计算机视觉学习者与道路安全检测方向的开发者提供一套基于YOLOv8实现路面坑洼识别的完整Python项目涵盖从数据准备、模型训练到推理评估的全流程适合具备一定深度学习基础、希望动手实践目标检测的读者参考。压缩包共10个文件约170.66MB包含4个py脚本训练、测试、验证与预测、2个pt权重文件、1个requirements依赖清单、1个mp4演示视频、1个md项目说明及1张png效果图结构紧凑、开箱即用。目前已有423人学习下载。项目说明文档梳理了数据集标注、参数配置与结果分析思路配套权重可直接用于坑洼检测推理演示视频直观呈现检测效果依赖清单便于快速复现环境。读者可借此理解YOLOv8在真实道路场景中的落地方式并迁移至交通标志识别、路面破损评估等相似任务。1. 路面坑洼检测为什么值得单独做一个 YOLOv8 项目城市道路巡检、自动驾驶感知、市政养护评估这三类场景里「路面坑洼检测」几乎是绕不开的一环。传统做法靠人工巡检或传统图像处理前者效率低后者对光照、阴影、水渍极其敏感换个路段就翻车。YOLOv8 把目标检测做成了单阶段回归问题一次前向就能同时输出类别和边界框在坑洼这种「形状不规则、尺度跨度大、背景干扰强」的任务上比两阶段方案更适合落地到边缘设备。这份资源是一套完整的 Python 工程train.py、val.py、predict.py、test.py四个脚本覆盖训练到推理全链路附带best.pt权重、y8best.pt备份权重、tested.mp4实测视频、requirements.txt依赖清单和README.md项目说明。拿到手不用从零搭环境直接能跑通「加载模型 → 读图/读视频 → 输出带框结果」这条主线。适合想快速验证坑洼检测可行性的人也适合拿它当模板改造成裂缝、井盖、标线等其他路面病害检测。下面按「资源结构 → 训练与推理 → 避坑 → 进阶」的顺序拆开讲。2. 工程结构与 YOLOv8 训练链路拆解2.1 目录里每个文件到底干什么先把压缩包解开按功能把文件分成四类这样后面改代码时不会找错地方。文件/目录类型作用train.py脚本训练入口读取数据集配置并启动 YOLOv8 训练val.py脚本在验证集上评估 mAP、precision、recallpredict.py脚本单图/视频推理输出带检测框的结果test.py脚本快速自测通常用于确认环境和权重可用best.pt权重训练收敛后的最优模型权重y8best.pt权重备份或另一轮训练的权重命名区分tested.mp4视频实测推理输出用来直观判断效果requirements.txt依赖Python 库及版本约束README.md文档数据集说明、训练参数、使用步骤best.pt和y8best.pt同时存在说明作者至少跑过两轮训练或做过权重对比。实际使用时先确认哪个权重对应的 mAP 更高别默认best.pt一定最好——命名是人为的不是框架保证的。2.2 环境安装与依赖确认YOLOv8 依赖 Ultralytics 框架底层是 PyTorch。环境装不对后面全是玄学报错。建议用 Python 3.83.10太新的版本某些 CUDA 轮子还没跟上。# 创建独立环境避免和系统 Python 冲突 python -m venv pothole_env source pothole_env/bin/activate # Windows 用 pothole_env\Scripts\activate # 先装 PyTorch按自己的 CUDA 版本选对应命令 # 以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 再装项目依赖 pip install -r requirements.txt # 单独确认 ultralytics 版本训练脚本对版本敏感 pip show ultralyticsrequirements.txt里通常包含ultralytics、opencv-python、numpy、pillow、matplotlib。如果pip install卡在opencv-python多半是网络问题换国内镜像源即可。装完后跑一句python -c from ultralytics import YOLO; print(ok)能打印ok说明框架通了。提示不要用pip install ultralytics覆盖requirements.txt里锁定的版本版本漂移会导致train.py里的参数名对不上。2.3 训练脚本的关键参数怎么改train.py是整条链路的起点。YOLOv8 的训练参数集中在model.train()里下面这段是常见写法我按坑洼检测场景补了注释。from ultralytics import YOLO # 加载预训练权重从 COCO 迁移比从零训练收敛快得多 model YOLO(yolov8n.pt) # n/s/m/l/x 按算力选边缘设备优先 n 或 s model.train( datadata/pothole.yaml, # 数据集配置文件指向 train/val 路径和类别名 epochs100, # 坑洼样本少时 100 起步观察 mAP 是否还在涨 imgsz640, # 输入分辨率坑洼小目标多可提到 800 batch16, # 显存不够就降到 8 或 4 lr00.01, # 初始学习率迁移学习常用 0.01 patience20, # 20 轮 mAP 不涨就早停省时间 device0, # 0 表示第一块 GPUCPU 写 cpu projectruns/train, # 输出目录 namepothole_v8n # 本次实验名方便对比 )data/pothole.yaml是数据集描述文件格式如下路径写绝对路径最稳相对路径容易因为工作目录不同而找不到。path: /home/user/pothole_dataset train: images/train val: images/val nc: 1 names: [pothole]nc: 1表示只有坑洼一个类别。如果后面要加裂缝、井盖改nc和names即可但标注文件里的类别索引也要同步改否则训练时标签越界会直接报错。imgsz和batch是最容易翻车的两个参数分辨率翻倍显存大约翻四倍batch 调大要先看显存余量。2.4 验证与推理从 mAP 到可视化结果训练完先跑val.py别急着看视频。验证集上的 mAP50、mAP50-95 才是判断模型能不能用的硬指标。# 在验证集上评估指定权重和数据配置 python val.py --weights best.pt --data data/pothole.yaml --img 640 --batch 16输出里重点看三行mAP50反映宽松匹配下的检出能力mAP50-95反映框的贴合精度precision/recall反映误检和漏检的平衡。坑洼检测里 recall 通常比 precision 更重要——漏掉一个坑可能意味着车辆受损多检一个顶多人工复核。推理用predict.py单图和视频都支持# 单张图片推理保存带框结果 python predict.py --weights best.pt --source test.jpg --conf 0.25 --save # 视频推理输出到 runs/detect 目录 python predict.py --weights best.pt --source tested.mp4 --conf 0.25 --save--conf 0.25是置信度阈值低于它的框会被丢弃。坑洼边缘模糊时阈值设太高会漏检设太低会满屏框。我的习惯是先跑 0.25 看整体再针对具体路段微调到 0.30.4。--save会把可视化结果写到runs/detect/下tested.mp4就是这类输出的样例。3. 数据集准备与标注格式的实操细节3.1 坑洼数据从哪来、怎么标YOLOv8 要的是 YOLO 格式标注每张图对应一个.txt每行类别 中心x 中心y 宽 高坐标全部归一化到 01。很多人拿 LabelImg 标完导出 VOC 的 XML直接丢给 YOLO 训练结果标签读不进去——格式不对框架不会帮你转。# VOC XML 转 YOLO txt 的核心逻辑 import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, img_w, img_h, out_path): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): cls_id 0 # 单类别坑洼固定为 0 bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 归一化并转成中心点宽高 cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) Path(out_path).write_text(\n.join(lines))转换时最容易错的是img_w/img_h取错——必须用原图尺寸不能用缩放后的。另外坐标要裁剪到 01标注框超出图像边界时归一化会得到负数或大于 1 的值训练时直接报invalid label。3.2 数据划分与类别平衡坑洼数据集普遍存在两个问题负样本无坑洼路面太多正样本里小坑洼占比高。划分时按 8:1:1 分 train/val/test且要保证每个子集里都有不同光照、不同路面的样本不能随机切完训练集全是晴天、验证集全是雨天。# 按文件名列表划分避免随机种子导致每次结果不同 python split_dataset.py --images data/all_images --ratio 0.8 0.1 0.1 --seed 42如果正负样本比例超过 1:10训练时可以考虑在pothole.yaml里加fraction参数只取部分负样本或者用 YOLOv8 自带的copy_paste、mosaic增强。但增强不是万能药坑洼的形状被过度拼接后会失真mAP 反而下降这个后面避坑章节细说。3.3 用预训练权重做迁移的取舍yolov8n.pt是在 COCO 上训的COCO 里没有坑洼类别但底层卷积特征边缘、纹理、明暗对比是通用的。从预训练权重起步通常 3050 轮就能到可用水平从零训练100 轮可能还在震荡。选 n 还是 s/m取决于部署目标。如果只是本地验证yolov8s.pt精度更稳如果要往 RK3588 这类边缘板子上部署yolov8n参数量小、推理快但小坑洼召回会掉。我的做法是先用 n 跑通全流程确认数据标注没问题再换 s 对比 mAP最后按部署算力定版本。4. 训练与推理中的避坑排查清单4.1 现象训练 loss 正常下降但 mAP 一直是 0原因标注文件路径或类别索引不对。YOLOv8 读不到标签时不会报错而是把该图当负样本训练loss 照样降但模型学不到任何目标。解决跑一次python -c from ultralytics.data.utils import check_det_dataset; check_det_dataset(data/pothole.yaml)它会打印数据集统计。如果train的 instances 为 0就是标签没被读到。检查.txt是否和图片同名同目录以及names里的类别数是否和标注里的最大类别索引匹配。4.2 现象显存溢出报 CUDA out of memory原因imgsz或batch超过显卡容量。YOLOv8 训练时显存占用和imgsz² × batch近似成正比。解决先把batch减半还不行再降imgsz。GTX1660Ti 6G 显存跑imgsz640, batch16基本到顶建议batch8。也可以用--amp混合精度显存能省三成左右但个别老卡上会出现 loss NaN开了要盯着前几轮。4.3 现象推理时框大量重叠、同一个坑被检多次原因NMS非极大值抑制的 IoU 阈值设得过高重叠框没被合并。解决推理时加--iou 0.5或更低。YOLOv8 默认 IoU 是 0.7对坑洼这种大而模糊的目标偏松。但 IoU 调太低会把相邻的两个坑合并成一个需要按实际场景试。密集坑洼路段建议 0.50.6。4.4 现象换一段路视频检测效果断崖式下降原因训练集过拟合到特定路面材质或光照。模型学到的是「这段路的坑洼长这样」不是「坑洼的通用特征」。解决补充不同路段、不同天气的样本重新训练或者在推理前做简单的直方图均衡化。更彻底的做法是加mosaic0关掉拼接增强让模型看到更完整的单图上下文减少对局部纹理的依赖。4.5 现象predict.py报找不到best.pt原因权重路径写的是相对路径而脚本运行目录和权重目录不一致。解决统一用绝对路径或者在脚本里用Path(__file__).parent / best.pt定位。这类问题在 Windows 和 Linux 之间来回切的时候特别常见血泪经验是路径一律写绝对路径别偷懒。5. 从能跑到好用阈值调优与边缘部署的进阶技巧模型跑通只是起点真正决定这套东西能不能上巡检车或边缘盒子是后处理阈值和推理后端。先说置信度阈值--conf 0.25是通用起点但坑洼检测里我一般会做一次分路段标定。拿一段已知坑洼数量的视频把conf从 0.1 到 0.6 每 0.05 跑一遍画一条 recall-conf 曲线选 recall 开始明显下降前的那个点。多数情况下这个点在 0.3 附近比默认值高能压掉一批阴影误检。NMS 的 IoU 阈值同理但它和conf是耦合的。两个参数一起调别单独动一个。我习惯固定conf0.3只扫iou因为conf对召回的影响更直观先定它再定iou更省事。如果要往 RK3588 这类板子部署PyTorch 权重不能直接跑得先导出 ONNX 再转 RKNN。导出这一步有个坑YOLOv8 的动态输出在转 ONNX 时如果opset版本选低了后处理节点会丢转出来的模型输出维度对不上。# 导出 ONNXopset 至少 12imgsz 和训练时保持一致 yolo export modelbest.pt formatonnx opset12 imgsz640 simplifyTruesimplifyTrue会调用 onnx-simplifier 合并冗余节点转 RKNN 时成功率更高。导出后先用onnxruntime在 PC 上验证一遍输出和 PyTorch 一致再上板子转 RKNN否则板子上报错你分不清是模型问题还是转换问题。参数通用起点坑洼场景建议影响conf0.250.300.35越高误检越少漏检越多iou0.700.500.60越低重叠框合并越狠imgsz640640800越大越小目标越友好越吃显存batch1686G 显存越大训练越稳越吃显存最后说一个验证习惯每次改完参数别只看tested.mp4这种「作者挑过的样例」自己拿手机拍一段新路面的视频跑一遍。我吃过亏——在样例视频上 mAP 漂亮得很换到自己小区门口那段烂路模型把井盖和坑洼混在一起检。从那以后我每次调完阈值都强制用一段没参与训练的新视频走一遍确认没有系统性误检才收工。希望这套流程能帮你少走点弯路。本文还有配套的精品资源点击获取