简介:一份基于YOLOv8的交通道路标线磨损监测系统完整项目,面向计算机相关专业本科生、研究生及开发者,可直接用于毕业设计、课程设计或初期项目演示。资源提供从模型训练到可视化展示的闭环方案,包含源码、预训练权重、完整数据集和部署说明,覆盖数据准备、训练、检测与可视化界面设计等环节。包体共8个文件,以3个Python脚本、3个权重文件和2个说明文档为主,压缩包仅15.91MB,轻量易下载。脚本分别实现模型训练、视频检测和可视化界面,权重文件含不同规模预训练模型,文本说明给出部署要点,目前已有53人学习下载。代码经完整测试,可产出核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图,为答辩提供充分数据支撑,可在此基础上二次开发,也可直接作为毕设成果提交。
1. 拿到一批道路巡检图片,最枯燥的活就是把磨损的交通标线一张张挑出来。很多人第一反应是上语义分割,逐像素把线抠出来,但放到毕设或课程设计里,YOLOv8 目标检测反而更务实——把一段段标线当成矩形目标框出来,再按框的类别统计磨损比例,训练、部署、解释的成本都低得多。标题里这套系统就是干这个的:模型侧用 YOLOv8 区分完好标线和磨损标线,交付侧带 PyQt 可视化界面、可直接开训的标注数据集和部署教程。对要快速出成果的学生来说,它比从零造轮子靠谱;对工程师来说,先跑通这个闭环,再换数据换场景也顺。
2. 为什么用 YOLOv8 做标线磨损:检测思路与数据闭环
2.1 用检测框而不是分割:磨损统计的两条路线
标线磨损监测要回答的问题很具体:这段路的白线是否还醒目,需不需要重新施划。常见做法有两种:一种是语义分割,把图像中每个像素分类成“完好标线/磨损标线/背景”,再按像素面积算出磨损率;另一种就是标题采用的目标检测,直接输出标线片段的矩形框,以及这段框对应的磨损类别。分割的精度上限更高,但标注成本也高——你要沿着标线的锯齿边缘画 mask,几十张图就能标到怀疑人生。目标检测只需要画一个覆盖标线段的矩形,标成 good_line 或 worn_line,速度是分割标注的好几倍。
从落地效果看,交通标线本来就是细长目标,磨损后边缘模糊、颜色接近路面。如果用矩形框去圈,框里不可避免包含一部分背景,但这并不影响最终指标。我一般按“帧级磨损率”来统计:遍历一帧里所有 worn_line 框的数量,除以 worn_line 加 good_line 的总框数;或者更细一点,用 worn 框面积占两类框总面积的比例。这种统计方式用在道路养护巡线上已经够了,因为决策者关心的是“某段路标线退化超过多少”,而不是具体像素级的形状。
YOLOv8 的网络结构图值得先看一眼:它延续了 C2f 特征提取加 PAN-FPN 多尺度融合的结构,检测头是解耦的 classification 分支和 regression 分支。对标线这种目标,PAN-FPN 自顶向下和自底向上两条路径能同时照顾到远看时的细线段和近景时的粗轮廓。很多人一上来就想去改检测头或加注意力,我建议先把原版跑通,再回来看网络结构图决定改哪里。盲目加模块只会让训练时间变长,磨损检测这种任务原版 YOLOv8 sufficient 已经够用。
2.2 数据从哪来:公共数据集、自采与 YOLO 标注格式
训练一个能用的标线磨损模型,数据是真正的门槛。标题里的完整数据集一般是针对这个任务重新标注过的道路图像,但我没见过原包,不能替它背书。如果手头只有公开的车辆检测数据集,比如 BDD100K,你主要能拿它来做预训练或者挑出包含清晰标线的帧做二次标注,因为它本身的车辆标注和标线磨损没关系。想要和自己场景匹配,最稳的办法是自采:手机横屏或行车记录仪截帧,尽量覆盖晴天、阴天、逆光、阴影遮挡,每类至少三百到五百框,比盲目堆两万张没用图片强得多。
标注工具方面,我习惯用 X-AnyLabeling 或 labelImg,输出都是 YOLO 的 txt 格式。每条 txt 对应一张同名的 jpg,每行是“类别 中心x 中心y 宽度 高度”,坐标全部归一化到 0 到 1 之间。对于标线这种形状,有两点要注意:第一,完整标线如果很长,不要硬塞进一个大框,按视野里能看清的一段切成多个框;第二,磨损标线不要只框“破损的那一小块”,要连同一段标线的剩余完好处一起框,类别标 worn_line。否则模型学到的是“一堆碎片”,而不是“一整条磨损线”。
如果使用标题配套的数据集,训练前最好写个脚本检查一下标注有没有越界、有没有空的 txt 文件。YOLO 格式里宽高可以是小数,但中心坐标在 0 到 1 之外、或者边框宽度是负数,训练时会直接报错或者静默丢样本。这种脏数据是后面 mAP 上不去的头号原因,后面避坑章节我会专门展开。
2.3 模型选型和预训练权重:低算力显卡上的取舍
YOLOv8 官方给了 n、s、m、l、x 五个尺寸,对交通标线磨损这种两类小目标任务,n 和 s 已经足够。如果你只有 GTX1660Ti 这类 6GB 显存的卡,yolov8n.pt 用 batch 16 加 imgsz 640 能舒服地跑,s 版本要降到 batch 8。别一上来就挑 yolov8l,训练慢不说,小目标漏检改善有限,换来的收益可能只有一两个点的 mAP。我先跑 n,跑通全流程,再用 s 做最终训练,这是稳妥的节奏。
预训练权重我用官方 COCO 的 yolov8n.pt 做起点。虽然 COCO 里没有“磨损标线”这个类别,但它的低层特征对纹理、边缘、光照变化有很好的泛化性,在自建数据上微调比从零训练收敛快得多。训练时 backbone 是否冻结看数据量:超过两千张图就放开全部权重;只有几百张图时冻结前十个 epoch 的 backbone,能防止模型把路面纹理当成标线特征。
3. 用 YOLOv8 训练自己的标线数据集:环境、命令与可视化界面
3.1 环境配置:ultralytics 安装和 GTX1660Ti 上的显存参数
这套系统最核心的环境依赖是 ultralytics 库,它内置了 YOLOv8 的训练、验证、导出和推理接口,不需要你从源码编译。我习惯在干净的 conda 环境里装,避免把 OpenCV 和 PyTorch 的版本搞乱。如果你的电脑上已经装了其他深度学习项目,务必新建一个虚拟环境,否则后面遇到“cv2 找不到”“module 'PIL' has no attribute 'Resampling'”这类问题会浪费一整晚。
conda create -n yolov8 python=3.9 -y conda activate yolov8 pip install ultralytics opencv-python pyqt5 onnxruntime这段命令做的事是:创建一个 Python 3.9 环境,然后安装 YOLOv8 核心库、图像处理库和后面要用到的界面、推理库。python 3.9 目前兼容性最稳,3.10 以上装 PyQt5 可能遇到 sip 版本冲突。如果你是用 NVIDIA 显卡,PyTorch 装完后再装 ultralytics;没有 GPU 也不怕,标线检测在 CPU 上也能跑,只是训练慢很多。验证环境是否成功,直接跑yolo predict model=yolov8n.pt source=https://ultralytics.com/images/bus.jpg,能在当前目录生成一张画着框的输出图就算通了。这一步是排查环境问题最快的路径,比逐个 import 库管用。
3.2 训练命令和数据集 YAML:从数据划分到训练日志
数据准备好之后,先按下面的目录摆好,这是 YOLOv8 默认的 dataset 结构。train 和 val 下面各有两个文件夹,images 和 labels,文件名一一对应;labels 里每张 jpg 对应一个同名 txt。如果原封装包里的数据是 VOC 格式的 XML,可以用 ultralytics 自带的转换脚本,或者自己写一个三十行的转换函数。
datasets/road_mark/ ├── images/ │ ├── train/ │ │ ├── img_00001.jpg │ │ └── ... │ └── val/ │ ├── img_00051.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── img_00001.txt │ │ └── ... │ └── val/ │ └── ... └── road_mark.yamlroad_mark.yaml是训练入口,内容如下。path指定数据集根目录,train和val是相对于根目录的图片路径,nc是类别数,names列表要和标注 txt 里的数字一一对应。这里类别顺序最好不要随意调,后面可视化界面的统计逻辑都靠它。
path: datasets/road_mark train: images/train val: images/val nc: 2 names: 0: good_line 1: worn_line写明白就可以开始训练了。下面这条命令适合只有一张 6GB 显卡的机器,batch 16 是 YOLOv8n 在 640 分辨率下比较稳的值。如果训练时显存爆掉,把 batch 改成 8 或者把 imgsz 改成 512,提示信息会显示当前的 CUDA out of memory。
yolo detect train \ data=road_mark.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ device=0 \ workers=4 \ cache=True \ patience=20 \ project=./runs \ name=mark_wear这条命令里每个参数都值得说清楚。model=yolov8n.pt代表从 COCO 预训练权重续训,如果你想从零开始就把这个值改成yolov8n.yaml,一般不推荐。epochs=100是最大轮数,实际跑多少看早停;patience=20表示验证集指标连续 20 个 epoch 不提升就自动停,这是防止过拟合的后悔药。cache=True能把图片加载进内存,GTX1660Ti 上如果内存小于 16GB 建议改成cache=ram或者不缓存,否则数据加载会吃满内存。
训练结束后,runs/mark_wear/weights/目录下会有best.pt和last.pt。best.pt是验证集 mAP 最高的权重,后面的部署和界面全部用它。你还会看到results.csv和results.png,里面记录了每一轮的损失曲线和指标曲线。别急着看最终的 mAP,先看 val 损失是不是持续下降,如果 val_loss 在中间反弹,说明学习率太大或数据噪声太多。
3.3 可视化界面:PyQt5 加载模型并输出磨损统计
标题里强调可视化界面,常见做法是用 PyQt5 做一个最简单的桌面窗口,上面一个放图区域,一个选择图片按钮,下面一行磨损统计文字。这类界面的核心不是炫,而是让你能选一张图立刻看到检测框,并算出“这段路标线磨损比例”。我用下面这个骨架做演示,实际压缩包里界面多半更复杂,但原理一致。
import sys import cv2 from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QFileDialog from PyQt5.QtGui import QPixmap, QImage from ultralytics import YOLO class WearWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("标线磨损监测") self.model = YOLO("runs/mark_wear/weights/best.pt") self.label = QLabel(self) self.label.setFixedSize(800, 450) self.btn = QPushButton("选择图片", self) self.result = QLabel(self) self.btn.clicked.connect(self.predict_image) def predict_image(self): path, _ = QFileDialog.getOpenFileName(self, "选择图片", "", "Images (*.jpg *.png)") if not path: return frame = cv2.imread(path) frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = self.model.predict(frame, conf=0.25, imgsz=640)[0] worn_cnt = 0 good_cnt = 0 for box in results.boxes: x1, y1, x2, y2 = map(int, box.xyxy[0].tolist()) cls = int(box.cls[0]) cv2.rectangle(frame, (x1, y1), (x2, y2), (255, 0, 0), 2) if cls == 1: worn_cnt += 1 else: good_cnt += 1 ratio = worn_cnt / (worn_cnt + good_cnt) * 100 if (worn_cnt + good_cnt) else 0 self.result.setText(f"完好标线段: {good_cnt} 磨损标线段: {worn_cnt} 磨损比例: {ratio:.1f}%") h, w, ch = frame.shape self.label.setPixmap(QPixmap.fromImage(QImage(frame.data, w, h, ch * w, QImage.Format_RGB888)))这段代码的逻辑分三步。第一步,把选中的图片读进来并转成 RGB;第二步,用self.model.predict推理,得到results.boxes,然后逐个取类别画框,类别 1 是磨损,类别 0 是完好;第三步,统计两类框的数量计算磨损比例,显示在窗口底部。参数conf=0.25是置信度阈值,实测发现阈值低于 0.15 时磨损误检会明显变多,高于 0.4 时又会漏掉边缘模糊的磨损线。建议部署时做成一个滑块,白天和阴天场景可以现场调。这个界面直接运行可以跑,但要注意别把predict放在 UI 线程里跑视频流,否则窗口会卡死,第五章节我会专门说。
4. 部署教程:导出 ONNX、本机推理与 RK3588 边缘部署
4.1 导出 ONNX 并用 onnxruntime 跑 CPU 推理
训练好的best.pt你可以继续用 PyTorch 方式加载,但交付给用户的机器未必有 GPU,甚至未必能装完整 PyTorch。常见做法是把权重导出成 ONNX,用 onnxruntime 在 CPU 上跑。导出命令在yolo上一行就能完成,导出后会得到一个best.onnx文件,体积比.pt小一些。
yolo export model=runs/mark_wear/weights/best.pt format=onnx \ opset=12 simplify=True imgsz=640 dynamic=False命令里opset=12是兼容性最好的算子集版本,老机器上的 onnxruntime 也能跑;simplify=True会用 onnxsim 做图优化,去掉一些冗余算子;dynamic=False表示固定输入尺寸为 640,换来的是推理速度更快,部署更省心。如果你希望界面里能自定义图片分辨率,再考虑开 dynamic,但那样后处理代码要额外处理动态 shape,对毕设没必要。导出完成后,用 onnxruntime 推理的核心代码可以控制在五十行以内,我习惯写成函数:
import cv2 import numpy as np import onnxruntime as ort sess = ort.InferenceSession("best.onnx", providers=["CPUExecutionProvider"]) def infer(img): h, w = img.shape[:2] resized = cv2.resize(img, (640, 640)) blob = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0 blob = blob.transpose(2, 0, 1)[None] outputs = sess.run(None, {sess.get_inputs()[0].name: blob})[0] # 输出 shape: [1, 4+nc, 8400],先转成 [8400, 4+nc] preds = outputs[0].transpose(1, 0) return preds函数里做的是标准预处理:缩放、通道交换、归一化、转 NCHW。读懂这段代码很重要,因为 PyTorch 的model.predict会自动处理这些,换成 ONNX 后这些都得你自己写。有一个大坑是输出格式:YOLOv8 的 ONNX 输出是[1, 4+nc, 8400],8400 是三个尺度的预测框总数,4 是 x1y1x2y2(或 cxcywh 的变体)加每个类别的置信度。很多人在后处理直接取前四列当坐标,结果画出来的框全偏到左上角,就是因为忘了先做 transpose。转置之后的每一行,前四列是框坐标,后两列才是两个类别的得分,取 argmax 得到类别。
4.2 简单部署的三种形态:命令行、HTTP 服务和桌面打包
“简单部署即可运行”这句话,在不同场景下的含义不同。如果只是自己验证,命令行或者一个 Python 脚本就够了;如果指导教师要看界面,PyQt 桌面程序是主流;如果要把算法挂到局域网里给几个人同时用,那就得起 HTTP 服务。我不建议把三种形态都做进毕设,选一个你最可能被验收的场景即可。
命令行形态最简单,直接用yolo predict指定权重和图片目录,结果会落到一个输出目录里。适合深夜加班快速批量验证。HTTP 形态我用 Flask 写,核心接口接收上传图片,返回检测框和磨损比例。桌面形态就是第三章的 PyQt 代码,打包成 exe 时要注意,ultralytics 和 torch 加起来体积很大,打包出来一个安装包甚至超过 3GB。如果你只是给老师演示,不必非要打包 exe,装个 Python 环境跑脚本反而更省事。
从维护角度看,我强烈建议把“训练”和“部署”的代码分开放。训练代码跟着数据集走,部署代码只依赖best.onnx和推理函数,不依赖torch。这样换一台没有 GPU 的电脑,只需要安装opencv-python和onnxruntime,两分钟就能起来。实际交付时,优化部署依赖比优化模型的收益更明显,毕竟老师验收时最怕的就是“在我电脑上跑不起来”。
4.3 嵌入式设备部署:RK3588 上跑 YOLOv8 的注意事项
如果项目要求脱离电脑运行,RK3588 是边缘部署常见的选择,这块芯片自带 NPU,YOLOv8n 经过转换可以跑实时。网上一搜一堆“YOLOv8 部署到 RK3588”的教程,但标线磨损这种小目标任务有个特殊问题:RK3588 的 NPU 对 int8 量化很敏感,量化后磨损线很可能直接丢检测。这不是模型没训练好,而是量化时置信度分布被压缩了。
转换流程一般是先用rknn-toolkit2把 ONNX 转换成 RKNN 格式,量化需要准备一个 dataset 文件,里面写几十张图像的路径列表。关键参数有两个:一个是量化数据类型,我建议先用fp16跑通,再开int8对比;另一个是量化数据集要选择和真实场景接近的标线图片,不能用公开的 bus 图,否则激活值范围不对。如果int8效果掉点明显,退一步用fp16混合精度跑,NPU 仍然能加速,只是显存占用高一点。
最后提一句,RK3588 部署时后处理可以直接复用 4.1 节的 ONNX 代码,但要注意输入输出尺度。RKNN 的输入通常是NCHW、大小固定 640,输出和 ONNX 一致。如果你在板子上拿摄像头实时跑,建议把画框和统计磨损比例的代码放到推理线程之外,避免掉帧后 UI 看起来像错过了关键路段。实测这种任务,YOLOv8n 在 RK3588 上单帧推理 CPU 环境大约要 40 到 60 毫秒,NPU 加速后能压进 20 毫秒,足够做视频流巡检。
5. 训练到出图避坑:标线检测最常翻车的 5 个问题
5.1 磨损标线漏检成背景
现象:训练完拿到 val 图上一看,磨损严重的标线完全没有框,反而一些路缝、污渍被框成 worn_line。
原因:这类问题百分之八十出在标注标准不一致。磨损标线的可视度很低,标注人员会犹豫“这算不算线”,结果是同一条线的不同片段,有人标有人不标,模型学到的正样本噪声极大。还有一种情况是正样本太少,worn_line 只有几百个框,而 good_line 有两千个框,模型天然偏好预测出现频率更高的类别。
解决:先把训练集里 worn_line 的标注全部复查一遍,用 labelimg 的“显示所有类别”模式检查,把边缘模糊的框补上,把误标的污渍删掉。然后做简单的类别平衡复制,先复制一份 worn_line 的图片再训练,代价是训练时间稍长;或者把 loss 里类别权重调到 2 比 1。如果调完仍然漏检,降低推理时的conf阈值到 0.15 看看能不能找回来,但代价是误检变多,需要配合画框面积下限过滤掉巴掌大的碎屑。
5.2 完好标线和磨损标线互相错分
现象:mAP 显示 good_line 和 worn_line 都有 0.8 以上,但打开可视化界面看一张图,明明磨损到发灰的线被标成了 good_line,偏白的完好线被标成 worn_line。
原因:这两类别的边界本身模糊。一张标线如果只有前三分之一磨损,按 2.1 里的标注建议,整条都算 worn_line,此时框内其实包含大量完好像素,网络提取的特征就会“脏”。另一个原因是训练数据里“磨损程度居中”的样本太少,模型只能学成一个二分类的简单判断。
解决:最有效的办法是把分类标准量化,比如定一个规则:“裂缝或者剥落区域占整条线段超过 30%,就整条标为 worn_line;低于 30% 算 good_line,但要保证所有标注一致。”不要靠肉眼感觉来切换。如果数据里确实有很多中间态,考虑再加一个 moderate 类别做三分类,后处理再把它合并进磨损统计。这个改动会让标注量增加,但模型学起来会清晰很多。
5.3 PyQt 界面卡死:推理阻塞了 UI 线程
现象:点完“选择图片”按钮,界面直接变白转圈,过十几秒才恢复,如果是视频流,整个窗口一卡一卡,点关闭都没反应。
原因:这是 PyQt 写法的经典翻车点。第三章的示例为了简短把self.model.predict放在按钮事件里直接执行,这等于让 UI 线程去跑同步推理,图像推理期间消息循环被阻塞,鼠标键盘事件全部排队。视频流每帧推理 50 毫秒还好,如果模型是 s 或 m 版本,帧率直接掉到 10,界面就彻底卡死。
解决:把推理放进 QThread,用信号把结果传回主线程更新界面。常用的简化写法是定义一个继承 QThread 的InferThread,run()里循环读视频并predict,每帧拿到结果后发一个finished.emit(frame_with_boxes, ratio),主线程的 slot 只负责更新 QLabel。你只需要记住一个原则:UI 里永远不要直接调模型推理,所有模型调用都要丢到子线程。这是毕设答辩时最容易暴露的问题。
5.4 验证集 mAP 很高,实地却一直误检
现象:训练时 val mAP@0.5 到了 0.92,界面在自己拍的几张测试图上也很像样,可拿到真实的道路巡查视频里,路边的树影、井盖周围的水渍全被框成磨损标线。
原因:这就是数据分布差异。标线磨损模型在训练时看到的背景大多是干净的柏油路,而实地场景里有大量干扰物:树叶阴影、积水反光、白色井盖、路面修补痕迹。mAP 高只能说明模型在验证集分布内表现好,验证集和巡检视频不是同分布。另一个常见原因是训练时用 640 分辨率,而视频源是 1080p,小目标被缩小后纹理特征丢失。
解决:训练集中至少要混入 20% 的“负样本”——完全没有标线的道路图,同时标注文件留空,让模型明确学到“这些路面是背景”。然后做分辨率对齐,评估时把视频抽帧统一缩放到 640 再算指标。若实地误检还是多,用yolo val输出混淆矩阵,看看误检集中在哪一类,再针对性地去采集那种背景样本。单纯加好标线图片是治标不治本。
5.5 中文路径导致推理报错和视频内存翻车
现象:把整个项目放到桌面,路径里有中文,比如C:\Users\张三\道路标线系统,PyQt 窗口能打开,一选图片就报cv2.error: ... could not find encoder,或者视频推理跑到一半内存占满崩溃。
原因:OpenCV 的老版本通过文件路径读图时使用 C 接口,中文路径可能解析失败;而视频推理内存翻车通常是因为视频流解码出的每一帧都被保存到检测结果列表里,没有及时释放,加上 PyQt 的 QPixmap 缓存,多线程叠加后内存爆炸。
解决:第一,项目根目录改用纯英文和数字,比如D:/road_mark_system,这是最省事的办法,不要在中文路径这件事上硬刚。第二,视频推理时用生成器逐帧处理,处理完的旧帧直接把引用置空,不要在列表里累积所有结果。第三,如果必须读中文路径图片,先用pathlib.Path转成二进制再读,避免直接调cv2.imread。这类问题不会出现在数据集训练阶段,全是在部署阶段突然冒出来,所以部署测试时一定要换一台“什么都没配置”的电脑走一遍流程。
6. 验证模型:画损失函数曲线和混淆矩阵,再决定要不要换改进版
训练完不要只看最后的 mAP,先把results.csv拉出来画损失函数曲线。YOLOv8 训练过程中自动记录了train/box_loss、val/box_loss等数据,用 pandas 读进来一行就能画。这条曲线能告诉你模型是不是欠拟合、过拟合,或者学习率有没有调崩。
import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("runs/mark_wear/results.csv") df.columns = [c.strip() for c in df.columns] plt.figure(figsize=(10, 4)) plt.plot(df["epoch"], df["train/box_loss"], label="train_box_loss") plt.plot(df["epoch"], df["val/box_loss"], label="val_box_loss") plt.xlabel("epoch") plt.ylabel("loss") plt.legend() plt.title("Box Loss Curve") plt.savefig("loss_curve.png")我判断训练是否结束的标准是:val_loss 曲线在最后 20 个 epoch 里还在持续下降,那就继续加 epochs;如果 val_loss 先降后升,说明早停已经帮你拦住了过拟合,这时候加数据比加 epoch 管用。如果 train_loss 一直降,val_loss 纹丝不动,说明模型容量不够,才轮到考虑换 YOLOv8 改进版或更大模型。这一步能避免你盲目去 GitHub 找各种魔改 head 的源码,很多改进换来换去还不如把数据清洗一遍。
混淆矩阵是另一个必须看的验证工具,ultralytics 在验证后会自动生成confusion_matrix.png。你看对角线的两个数字是不是明显大于其他元素,尤其是“worn_line 被预测成 background”的比例,超过 15% 就说明磨损类召回不足。此时不要急着改网络,先回看第 5.1 节,检查标注一致性和类别平衡。
我自己的习惯是,每次训练结束先画损失曲线和混淆矩阵,再决定是否投入时间去换改进模型。标准流程跑通之后,你心里对这套系统就有底了:YOLOv8 原版能解决 80% 的标线磨损问题,剩下 20% 靠数据迭代和阈值调优。等到哪天真要部署到 RK3588 再做 int8 量化时,你会感激当时把这些验证动作留成了脚本。希望帮到你。
本文还有配套的精品资源,点击获取