资讯详情

资讯详情

YOLOv8路面坑洼检测实战:从训练到RK3588部署全流程

简介这份资源面向计算机视觉学习者与道路安全检测方向的开发者提供一套基于YOLOv8实现路面坑洼识别的完整项目方案适合具备一定Python与深度学习基础、希望上手目标检测实战的人群。压缩包共10个文件约170.66MB包含4个py脚本、2个pt权重文件以及txt依赖清单、mp4演示视频、md说明文档和png效果图覆盖数据预处理、模型训练、推理与后处理全流程。项目围绕坑洼特征标注、模型训练、特征提取、非极大值抑制与mAP评估等环节展开配套训练好的权重可直接用于检测README与requirements则帮助快速复现环境。目前已有423人学习下载读者可借此理解YOLOv8在真实道路场景中的落地方式并迁移至交通标志识别、路面破损评估等相似任务。1. 路面坑洼检测为什么值得用 YOLOv8 重做一遍市政巡检和自动驾驶感知里路面坑洼检测是个被低估的刚需。传统做法靠人工开车巡查、拍照、事后标注一条主干道跑下来大半天漏检率还高。换成视觉方案后核心矛盾变成坑洼目标尺度差异极大近处一个坑能占半屏远处只剩十几个像素加上路面纹理、阴影、井盖、修补痕迹全是干扰。YOLOv8 之所以在这类任务里被反复选中是因为它在小目标召回和推理速度之间给了一个可调的平衡点而且 Python 生态完整从训练到部署到 RK3588 这类边缘板子都有现成路径。这套「python 源码 项目说明 模型」的组合本质是把数据准备、训练、验证、导出、推理串成一条能复现的流水线。适合做毕设的学生、做道路巡检产品的工程师以及想把检测模型落到边缘设备的人。下面按「先立住原理、再动手复现、最后避坑」的顺序讲清楚。2. 从数据集到 YOLOv8 训练一条能跑通的流水线2.1 为什么选 YOLOv8 而不是 v5 或两阶段检测路面坑洼检测的输入是车载或手持相机拍的连续帧要求单帧推理在边缘设备上压到几十毫秒。两阶段检测器精度够但速度拖后腿YOLOv5 生态成熟但 anchor 机制在小目标上要调不少参数。YOLOv8 换成 anchor-free 解耦头分类和回归分支分开小目标的召回更稳而且官方把训练、验证、导出、推理统一到ultralytics一个包里命令行和 Python API 都能调。对坑洼这种「形状不规则、边界模糊」的目标anchor-free 少了一层先验框匹配的玄学调参负担明显下降。选型时还要看部署端。如果最终要上 RK3588YOLOv8 的 ONNX 导出和后续量化链路比较顺社区里rk3588 部署 yolov8的案例也多遇到问题能查到。GTX1660Ti 这种 6G 显存的卡跑 yolov8n 或 yolov8sbatch 设 8 到 16 完全够用训练自己的数据集不需要换卡。2.2 数据标注格式与目录结构YOLOv8 吃的是 YOLO 格式标签每张图对应一个同名.txt每行类别 中心x 中心y 宽 高坐标全部归一化到 0 到 1。坑洼检测通常只有一个类别所以类别 id 恒为 0。目录按下面组织images和labels分开train 和 val 分开dataset/ ├── images/ │ ├── train/ # 训练图片jpg 或 png │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 与 train 图片同名的 txt │ └── val/ └── data.yaml # 数据集描述文件data.yaml是训练的入口配置路径写绝对路径最稳避免相对路径在不同工作目录下翻车path: /home/user/dataset train: images/train val: images/val nc: 1 names: [pothole]nc是类别数坑洼检测填 1。names顺序必须和标注时的类别 id 对应写反了模型学出来的全是错的。标注工具用 labelImg 或 roboflow 都行导出时选 YOLO 格式。如果手里是 VOC 的 xml需要转一道转换脚本后面避坑章会提。2.3 环境配置与最小训练命令环境这块Python 3.8 到 3.10 都行装ultralytics会连带把 torch、torchvision、opencv 拉下来。国内网络装 torch 容易卡建议先单独装好对应 CUDA 版本的 torch再装 ultralytics# 先装 torch按自己的 CUDA 版本选这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 再装 ultralytics它会复用已装的 torch pip install ultralytics # 验证环境 python -c import torch; print(torch.cuda.is_available())最后一行输出True才说明 GPU 可用。如果输出False先别急着训练检查驱动和 CUDA 版本匹配否则会退到 CPU 上跑一个 epoch 能等到怀疑人生。训练用命令行最省事一条命令把模型、数据、轮数、图片尺寸全指定yolo detect train \ modelyolov8n.pt \ data/home/user/dataset/data.yaml \ epochs100 \ imgsz640 \ batch16 \ device0 \ projectruns/pothole \ nameexp1modelyolov8n.pt是官方预训练权重从它开始做迁移学习比从头训收敛快得多。imgsz640是输入分辨率坑洼目标小的话可以提到 960但显存和速度要重新权衡。batch16在 6G 显存上跑 640 尺寸基本安全爆显存就降到 8。device0指定第一块 GPU。project和name决定权重和日志存哪跑多次实验时靠name区分别都堆在一个目录里。2.4 训练过程怎么看、损失曲线怎么读训练启动后终端会打印每个 epoch 的 box_loss、cls_loss、dfl_loss 和 mAP。box_loss 管边界框回归cls_loss 管分类dfl_loss 是分布焦点损失配合解耦头用。三个 loss 整体下降是正常但如果 cls_loss 早早掉到接近 0 而 mAP 不涨多半是类别太单一、模型在背样本这时候要看验证集是不是和训练集同分布。想看损失曲线ultralytics 训练完会在runs/pothole/exp1/下生成results.csv用 pandas 加 matplotlib 几行就能画import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/pothole/exp1/results.csv) df.columns df.columns.str.strip() # 列名可能带空格先清掉 plt.plot(df[epoch], df[train/box_loss], labelbox_loss) plt.plot(df[epoch], df[train/cls_loss], labelcls_loss) plt.plot(df[epoch], df[metrics/mAP50(B)], labelmAP50) plt.legend() plt.xlabel(epoch) plt.savefig(loss_curve.png, dpi150)results.csv的列名带斜杠和括号读进来先strip()去空格否则按列名取值会报 KeyError。mAP50 是 IoU 阈值 0.5 下的平均精度坑洼检测一般看这个就够如果要做严格评估再看 mAP50-95。曲线震荡大不一定是坏事但验证 mAP 连续多个 epoch 不涨就可以早停省时间。3. 推理、验证与模型导出把训练结果变成能用的东西3.1 用验证集确认模型没白训训练完别急着上真实场景先在验证集上跑一遍看混淆矩阵和 PR 曲线。命令行验证yolo detect val \ modelruns/pothole/exp1/weights/best.pt \ data/home/user/dataset/data.yaml \ imgsz640 \ batch16输出里重点看mAP50、precision、recall。坑洼检测里 recall 比 precision 更关键漏检一个坑可能意味着一次爆胎误检顶多多看两眼。如果 recall 明显低于 precision说明模型偏保守可以调低置信度阈值再验证。best.pt是验证集上表现最好的权重last.pt是最后一轮的通常用best.pt。3.2 单张图和批量推理的写法推理用 Python API 更灵活能直接拿结果做后续处理from ultralytics import YOLO model YOLO(runs/pothole/exp1/weights/best.pt) # 单张图 results model(test.jpg, conf0.25, iou0.45) for r in results: boxes r.boxes for box in boxes: xyxy box.xyxy[0].tolist() # 左上右下坐标 conf box.conf[0].item() # 置信度 cls int(box.cls[0].item()) # 类别 id print(xyxy, conf, cls) # 批量推理整个目录 results model.predict(sourcetest_images/, saveTrue, conf0.25)conf0.25是置信度阈值低于它的框直接丢。iou0.45是 NMS 的 IoU 阈值两个框重叠超过这个值就合并。坑洼密集的路段可以把 iou 调高到 0.5 到 0.6避免相邻的坑被误合并。saveTrue会把画好框的图存到runs/detect/predict/下方便肉眼核对。3.3 导出 ONNX 与边缘部署前的准备要在 RK3588 这类板子上跑先导出 ONNX再做量化。导出命令yolo export \ modelruns/pothole/exp1/weights/best.pt \ formatonnx \ imgsz640 \ opset12 \ simplifyTrueopset12兼容性较好RKNN 工具链对高版本 opset 支持不一定全。simplifyTrue会做一层图优化去掉冗余算子。导出后在同目录得到best.onnx。上板子前建议先在 PC 上用 onnxruntime 验证一遍输出和原模型一致import onnxruntime as ort import numpy as np sess ort.InferenceSession(best.onnx) inp np.random.randn(1, 3, 640, 640).astype(np.float32) out sess.run(None, {sess.get_inputs()[0].name: inp}) print([o.shape for o in out])输出形状对得上说明导出没丢东西。RK3588 的完整量化转换涉及 RKNN Toolkit属于另一条链路这里只保证 ONNX 这一步是干净的后面转换出问题多半能定位到量化参数而不是模型本身。4. 路面坑洼检测的避坑与排查清单4.1 现象训练 loss 正常但 mAP 一直是 0原因通常是标签格式错了。YOLO 格式要求坐标归一化如果标注工具导出的是像素坐标没除宽高模型学到的框全在图像外。解决写个脚本抽查几个 txt确认每行后四个数都在 0 到 1 之间超出范围就是没归一化。另外检查data.yaml里names和标注类别 id 是否对应类别对不上也会导致 mAP 归零。4.2 现象验证集 mAP 高真实路面漏检严重这是分布不一致的典型。训练集多是晴天、干燥路面真实场景有积水、逆光、阴影模型没见过就翻车。解决训练集里主动补进雨天、夜间、逆光样本哪怕每类只加几十张泛化也会明显改善。另外检查推理时的imgsz是否和训练一致训练用 640 推理用 1280小目标尺度对不上召回会掉。4.3 现象显存爆了报 CUDA out of memory原因无非 batch 太大、imgsz 太高、或者没释放上一轮缓存。解决先把 batch 降到 8 甚至 4再把 imgsz 从 960 降回 640。如果还爆检查是不是同时开了别的占显存进程。训练脚本里可以在每个 epoch 后手动torch.cuda.empty_cache()但治本还是调小 batch。GTX1660Ti 6G 显存跑 yolov8s 加 640 尺寸batch 8 是稳妥值。4.4 现象导出的 ONNX 在板子上推理结果乱多半是预处理没对齐。训练时 ultralytics 会把图片做 letterbox 填充到正方形再归一化到 0 到 1通道顺序是 RGB。如果板子端推理时直接 resize 没做 letterbox或者用了 BGR框的位置就会整体偏移。解决把 ultralytics 的预处理逻辑照搬到部署端letterbox 的缩放比例和填充值都要一致归一化除 255 别漏。4.5 现象同一张图多次推理结果框数量不一样这是 NMS 的随机性或者阈值卡在边界上。如果conf设得刚好让某些框在阈值附近浮动每次结果就会有出入。解决把conf稍微调高一点让边界样本稳定被过滤同时确认没有开多线程同时调同一个模型实例onnxruntime 的 session 在多线程下要各自建实例共享会出问题。5. 把坑洼检测做扎实的两个进阶习惯第一个习惯是给模型加一个「尺寸分层评估」。坑洼检测里大坑和小坑的检测难度完全不同只看整体 mAP 会掩盖小目标的短板。做法是在验证脚本里按标注框面积把样本分成 small、medium、large 三档分别算 recall。面积阈值可以按imgsz的平方比例定比如小于 32×32 像素算 small。分层之后经常发现整体 mAP 0.8但 small 档只有 0.4这时候就该考虑提高输入分辨率或者用带 P2 层的模型结构而不是盲目加数据。第二个习惯是固定一套「回归测试集」。从真实场景里挑 50 到 100 张有代表性的图覆盖晴天、雨天、夜间、修补路面每次改完模型或换导出参数都在这套图上跑一遍记录漏检和误检数量。这套集子不参与训练只做验收。时间长了你会发现很多改动在验证集上涨点在回归集上反而掉这就是过拟合验证集的信号。# 回归测试集批量评估的骨架 import os from ultralytics import YOLO model YOLO(best.pt) test_dir regression_set/ total_gt, total_pred 0, 0 for img in os.listdir(test_dir): if not img.endswith(.jpg): continue r model(os.path.join(test_dir, img), conf0.3, verboseFalse)[0] total_pred len(r.boxes) # 这里读同名 txt 统计 gt 数量做漏检误检对比 print(pred boxes:, total_pred)conf0.3比训练验证时略高是为了让回归结果更贴近实际部署的保守策略。每次记录 pred 数量和人工核对的漏检数形成趋势表比单看一个 mAP 数字有说服力得多。我自己踩过最深的坑是早期图省事直接用像素坐标训练loss 看着在降实际框全飘在图像外白白跑了两天。后来养成习惯任何数据集进训练前先写三行脚本抽查标签范围确认归一化没问题再开训。这个动作花不了一分钟能省下的是整晚的显卡时间。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

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

立即咨询 →