YOLOv8路面坑洼检测实战:从Labelme标注到RK3588部署全流程

发布时间:2026/10/2 14:03:07
YOLOv8路面坑洼检测实战:从Labelme标注到RK3588部署全流程 简介这份资源面向计算机视觉学习者与道路安全检测方向的开发者提供一套基于YOLOv8实现路面坑洼识别的完整项目方案涵盖从数据准备、模型训练到推理评估的全流程适合具备一定Python与深度学习基础、希望动手实践目标检测的读者参考。压缩包共10个文件约170.66MB包含4个Python脚本训练、测试、验证与预测、2个pt模型权重、1份依赖清单、1段演示视频、1份说明文档及1张效果图结构清晰便于快速上手。目前已有423人学习下载。项目说明详细记录了数据集信息、训练参数与结果分析配合训练好的权重可直接用于坑洼检测推理帮助读者理解YOLOv8在真实道路场景中的特征提取、非极大值抑制与mAP评估等关键环节也可为交通标志识别、路面破损评估等同类任务提供可复用的工程参考。1. 路面坑洼检测为什么值得用 YOLOv8 重做一遍市政巡检的朋友跟我吐槽过一件事他们之前用传统图像处理做路面坑洼检测阈值调了三个月晴天勉强能用一到阴天或者路面有积水误报率直接飙到七成以上。后来换成 YOLOv8 重新训练同样的数据量mAP50 从 0.61 拉到 0.87推理速度在 GTX1660Ti 上单张只要 12ms 左右。这个差距不是调参调出来的是检测范式变了。路面坑洼检测本质上是一个小目标、类内差异极大的检测任务。坑洼的形状从细长裂缝到不规则凹陷都有颜色从深黑到灰白不等还经常和井盖、修补痕迹、阴影混淆。YOLOv8 的 Anchor-Free 解耦头加上 Task-Aligned Assigner 正样本分配策略对这种形态多变的目标天然比 YOLOv5 的 Anchor-Based 方案更友好。这套方案适合谁做市政巡检系统集成的工程师、想拿检测项目练手的学生、需要快速验证路面病害检测可行性的团队。下面从数据准备到模型训练再到推理部署把整条链路拆开讲。2. 从 Labelme 标注到 YOLOv8 数据集格式转换与目录结构2.1 为什么路面坑洼数据更适合 YOLO 格式而不是 COCOLabelme 标注出来的是 JSON 文件每个多边形点集对应一个坑洼区域。COCO 格式虽然通用但它的 JSON 结构嵌套深解析慢而且 YOLOv8 原生训练接口直接吃 YOLO txt 格式省去中间转换环节。YOLO 格式每行是class_id x_center y_center width height全部归一化到 0~1 之间。对于坑洼检测这种单类别或者少类别任务YOLO 格式的文件体积小、读取快一个 5000 张图的数据集标注文件总共不到 2MB。常见做法是先用 Labelme 标注然后写脚本批量转成 YOLO 格式。我一般会保留原始 JSON 备份转换后的 txt 单独放一个目录方便后面排查标注问题。2.2 转换脚本与目录组织import json import os from pathlib import Path def labelme_to_yolo(json_dir, output_dir, class_names): 将 Labelme JSON 转为 YOLO txt 格式 json_dir: Labelme JSON 文件目录 output_dir: 输出 txt 目录 class_names: 类别名列表如 [pothole] os.makedirs(output_dir, exist_okTrue) for json_file in Path(json_dir).glob(*.json): with open(json_file, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_names: continue cls_id class_names.index(label) points shape[points] # 计算多边形外接矩形 xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # 归一化中心点和宽高 x_center (x_min x_max) / 2.0 / img_w y_center (y_min y_max) / 2.0 / img_h width (x_max - x_min) / img_w height (y_max - y_min) / img_h # 过滤掉宽高为0的无效标注 if width 0 or height 0: continue lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) # 写入同名 txt txt_path Path(output_dir) / (json_file.stem .txt) with open(txt_path, w) as f: f.write(\n.join(lines)) # 调用示例 labelme_to_yolo( json_dir./raw_annotations, output_dir./labels, class_names[pothole] )这段脚本的核心逻辑是读取 Labelme JSON 中的多边形点集取外接矩形再归一化成 YOLO 需要的中心点加宽高格式。class_names参数决定了类别索引如果你有多个类别比如[pothole, crack]索引 0 对应 pothole索引 1 对应 crack。width 0的过滤是为了防止标注时误点产生的零面积框这种框在训练时会引发 NaN 损失。2.3 数据集划分与 data.yaml 配置转换完成后按 8:1:1 划分训练集、验证集、测试集。目录结构建议这样组织dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml的内容path: ./dataset train: images/train val: images/val test: images/test nc: 1 names: [pothole]nc是类别数names是类别名列表。注意path用相对路径时YOLOv8 会相对于data.yaml所在目录解析。如果图片和标签不在同一级目录YOLOv8 默认会把images替换成labels去找标签文件所以目录名必须严格对应。提示划分数据集时一定要用随机种子固定否则每次跑出来的验证集不一样指标没法对比。我一般用random.seed(42)然后 shuffle 后再切分。3. YOLOv8 训练参数怎么设从 CPU 环境到 GPU 微调3.1 Ubuntu 20.04 下 CPU 版本环境搭建有些场景没有 GPU比如在 RK3588 板端做前期验证或者开发机就是普通笔记本。CPU 版本跑 YOLOv8 训练虽然慢但做小规模数据集验证完全够用。安装步骤# 创建虚拟环境 python3 -m venv yolov8_env source yolov8_env/bin/activate # 安装 PyTorch CPU 版本Ubuntu 20.04 默认 Python 3.8 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 安装 ultralytics pip install ultralytics # 验证安装 yolo checksyolo checks会输出环境信息包括 PyTorch 版本、CUDA 是否可用。CPU 版本会显示CUDA: None这是正常的。如果后面要切到 GPU直接重装对应 CUDA 版本的 PyTorch 即可ultralytics 不用动。3.2 训练命令与关键参数解读yolo detect train \ data./dataset/data.yaml \ modelyolov8n.pt \ epochs200 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience50 \ device0 \ workers8 \ project./runs/pothole \ nameexp1逐项说明modelyolov8n.pt用的是 nano 版本参数量 3.2M适合边缘部署如果精度不够可以换yolov8s.pt或yolov8m.pt。imgsz640是输入分辨率坑洼目标普遍偏小如果显存够建议上到 800 或 960小目标召回会明显提升。lr00.01是初始学习率lrf0.01是最终学习率因子YOLOv8 默认用余弦退火从 0.01 降到 0.0001。patience50表示 50 轮没有提升就早停这个值别设太小坑洼数据容易在 80 轮左右才出现明显下降。batch16在 8GB 显存上跑 640 分辨率刚好如果 OOM 就降到 8 或者开ampTrue混合精度。workers8是数据加载线程数CPU 核心少就降到 4不然反而拖慢。3.3 低显存和 CPU 训练的降级策略GTX1660Ti 只有 6GB 显存跑yolov8m加 640 分辨率会爆。我一般用两个策略一是冻结主干前 10 层freeze10只训练检测头显存占用能降 40% 左右二是用yolov8n加imgsz512精度损失大概 2 个点但速度翻倍。CPU 训练的话把batch降到 4workers降到 2epochs加到 300用时间换精度。# 低显存配置示例 yolo detect train \ data./dataset/data.yaml \ modelyolov8n.pt \ epochs300 \ imgsz512 \ batch4 \ freeze10 \ device0 \ ampTruefreeze10冻结的是 backbone 的前 10 层这些层学的是通用特征坑洼检测和 ImageNet 的底层特征差异不大冻结后收敛更稳。ampTrue开启自动混合精度显存占用再降 20%速度提升 15% 左右精度几乎无损。4. 训练过程排查与调优损失曲线和验证指标怎么看4.1 损失函数曲线的正确读法YOLOv8 训练完会在runs/pothole/exp1/下生成results.csv里面记录了每轮的 box_loss、cls_loss、dfl_loss 和 mAP 指标。用 pandas 画出来import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/pothole/exp1/results.csv) df.columns df.columns.str.strip() fig, axes plt.subplots(1, 3, figsize(15, 4)) axes[0].plot(df[epoch], df[train/box_loss], labeltrain) axes[0].plot(df[epoch], df[val/box_loss], labelval) axes[0].set_title(Box Loss) axes[0].legend() axes[1].plot(df[epoch], df[train/cls_loss], labeltrain) axes[1].plot(df[epoch], df[val/cls_loss], labelval) axes[1].set_title(Cls Loss) axes[1].legend() axes[2].plot(df[epoch], df[metrics/mAP50(B)], labelmAP50) axes[2].plot(df[epoch], df[metrics/mAP50-95(B)], labelmAP50-95) axes[2].set_title(mAP) axes[2].legend() plt.tight_layout() plt.savefig(training_curves.png, dpi150)正常情况train loss 和 val loss 同步下降最后趋于平稳。如果 train loss 继续降但 val loss 开始升说明过拟合需要加数据增强或者减模型容量。如果两个 loss 都震荡不降检查学习率是不是太大或者标注文件有没有问题。4.2 验证指标异常时的排查顺序mAP50 低于 0.5 时按这个顺序查第一看标注框是不是把整个路面都框进去了坑洼检测最常见的标注错误就是框太大把正常路面也包进去模型学不到判别特征。第二看验证集和训练集的分布是不是差太多比如训练集全是白天验证集全是夜间这种分布偏移会让指标崩掉。第三看imgsz是不是太小坑洼在 640 分辨率下可能只有 20x20 像素上到 960 再试。# 用验证集跑一次评估看每类的 AP yolo detect val \ modelruns/pothole/exp1/weights/best.pt \ data./dataset/data.yaml \ imgsz960 \ batch8输出里会分列mAP50和mAP50-95如果mAP50高但mAP50-95低说明框的位置不够准可以调box损失权重或者加 DFL 的 reg_max 参数。如果两个都低那就是特征没学好换大模型或者加数据。4.3 数据增强参数的针对性调整YOLOv8 默认开了 mosaic、mixup、hsv 增强。坑洼检测里mosaic 增强有时候会把坑洼拼到奇怪的位置导致模型学到错误的上下文关系。我一般把mosaic0.5降低概率mixup0.1几乎关掉hsv_h0.015、hsv_s0.7、hsv_v0.4保持默认因为路面颜色变化本来就大HSV 增强是合理的。flipud0.0和fliplr0.5上下翻转对路面没意义左右翻转可以保留。yolo detect train \ data./dataset/data.yaml \ modelyolov8s.pt \ epochs200 \ imgsz800 \ mosaic0.5 \ mixup0.1 \ fliplr0.5 \ flipud0.0 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4这些参数没有绝对的最优值但坑洼检测这个任务里降低 mosaic 和 mixup 的收益比较稳定我试过三组数据mAP50 平均能涨 1.5 到 2 个点。5. 避坑指南路面坑洼检测训练中最容易翻车的 5 个点5.1 标注框把阴影当成坑洼现象模型在验证集上把树荫、电线杆阴影都框成坑洼误报率极高。原因Labelme 标注时没有区分阴影和真实坑洼阴影区域在灰度上和浅坑洼接近。解决标注规范里明确写清楚只有路面结构层破损、有明显凹陷或碎裂的才算坑洼阴影、水渍、修补痕迹单独标成ignore类别或者直接不标。训练时把ignore类别的损失权重设为 0。5.2 验证集 mAP 虚高但实际推理效果差现象训练日志里 mAP50 到 0.9 了但拿手机拍几张路面照片推理一个坑洼都检不出来。原因训练集和验证集来自同一批数据分布太单一模型过拟合了采集设备的光照和角度。解决验证集必须留一部分来自不同路段、不同时间、不同设备的数据。如果实在没有至少做一次跨数据集验证用公开的路面病害数据集跑一遍。5.3 CPU 训练时 DataLoader 卡死现象在 Ubuntu 20.04 CPU 环境下跑训练进度条卡在第 0 轮不动CPU 占用 100% 但显存没变化。原因workers设太大CPU 核心不够数据加载进程互相抢资源。解决把workers降到 2 或者 0batch降到 4。如果还卡检查data.yaml里的路径是不是绝对路径相对路径在 CPU 环境下有时候解析会出问题。5.4 模型导出 ONNX 后推理结果和 PyTorch 不一致现象PyTorch 下推理正常导出 ONNX 后用 onnxruntime 跑框的位置偏移了几十个像素。原因YOLOv8 导出 ONNX 时默认做了动态轴设置如果推理时输入的尺寸和导出时不一致后处理里的 anchor 解码会出错。解决导出时固定imgsz推理时严格用同样的尺寸。yolo export modelbest.pt formatonnx imgsz640 opset12 simplifyTruesimplifyTrue会做图优化去掉冗余算子opset12兼容性最好。推理时用cv2.resize把图缩到 640x640不要用 letterbox 之外的填充方式。5.5 小目标坑洼在 640 分辨率下漏检严重现象宽度小于 30 像素的坑洼几乎全漏。原因YOLOv8 的 P3 特征图 stride 是 8640 输入下 P3 是 80x80一个 20 像素的坑洼在 P3 上只有 2.5 个格子特征太弱。解决把imgsz提到 960 或 1280P3 变成 120x120 或 160x160小目标特征明显增强。如果显存不够用yolov8n加 960比yolov8m加 640 的小目标召回高 8 个点左右。6. 推理部署与效果验证从 PyTorch 到 RK3588 的最后一公里训练完拿到best.pt只是第一步真正落地要看推理端。我一般分两步验证先在 PC 上用 PyTorch 跑一遍测试集确认指标和训练日志一致再导出 ONNX 或者 RKNN在目标硬件上跑实际视频流。PC 端推理脚本from ultralytics import YOLO import cv2 model YOLO(runs/pothole/exp1/weights/best.pt) cap cv2.VideoCapture(test_road.mp4) while cap.isOpened(): ret, frame cap.read() if not ret: break results model(frame, imgsz960, conf0.4, iou0.5) annotated results[0].plot() cv2.imshow(Pothole Detection, annotated) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()conf0.4是置信度阈值坑洼检测建议设 0.35 到 0.45 之间太低误报多太高漏报多。iou0.5是 NMS 的 IoU 阈值坑洼之间重叠少0.5 够用。如果要在 RK3588 上部署流程是best.pt - ONNX - RKNN。RKNN 工具链对 YOLOv8 的支持已经比较成熟但有几个参数必须注意量化时用dataset.txt做混合量化里面放 200 张左右的代表性路面图片mean_values和std_values要和训练时一致YOLOv8 默认是0-255输入不做归一化target_platform填rk3588。量化后 mAP 掉 1 到 2 个点是正常的如果掉超过 5 个点检查量化数据集是不是和训练集分布差太远。验证方法上我习惯用一段 1080p 的路面巡检视频分别跑 PyTorch 和 RKNN逐帧对比检测框。如果 RKNN 的框位置偏移超过 5 个像素大概率是量化时的尺度因子没对齐。这时候把quantized_dtype改成w8a8再试或者对检测头部分不做量化。最后说一个我踩过的坑导出 ONNX 时忘了加simplifyTrue结果 RKNN 转换时报了一堆不支持的算子折腾了一下午。后来养成习惯导出命令里simplifyTrue和opset12是标配再也没翻过车。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询