ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于YOLOv8的交通标志检测识别系统:从数据集到Gradio界面全流程

基于YOLOv8的交通标志检测识别系统:从数据集到Gradio界面全流程 简介这份资源是基于YOLOv8的交通标志检测识别系统完整项目源码面向高校学生、课程设计及毕业设计人群尤其适合需要完成期末大作业或希望快速上手目标检测实战的新手。项目采用YOLOv8模型结合PySide6搭建图形界面实现交通标志的检测与识别功能完善、界面美观、操作简单下载后简单部署即可运行。压缩包为zip格式共18个文件约82.74MB包含5个py源码文件、3个ui界面文件、3个txt说明文件、3个jpg示例图片以及训练权重pt文件、json配置、docx使用手册和png资源图等覆盖代码、界面、模型与文档全流程。目前已有345人学习下载。代码注释清晰新手也能看懂读者可获得一套可直接用于课程设计或期末大作业的完整方案包括模型权重、界面源码、依赖清单与操作手册便于快速复现、二次开发与答辩展示具有较高的实际应用与参考价值。1. 从一份期末大作业说起YOLOv8 交通标志检测识别系统到底要交付什么每年到了期末问得最多的一类问题就是「基于 YOLOv8 的交通标志检测识别系统项目源码」到底包含哪些东西、能不能跑起来、答辩会不会被追问。我见过太多同学把开源仓库 clone 下来改个标题就交上去结果老师一句「你这个类别不平衡怎么处理的」就当场卡壳。交通标志检测这件事本身不复杂难的是把它做成一个能演示、能讲清、能复现的完整系统而不是一个只会输出 mAP 数字的训练脚本。这个方向真正要交付的通常包含四块一份标注好的交通标志数据集常见是 CCTSDB 或 GTSRB 转过来的检测格式、一套 YOLOv8 训练与验证流程、一个能加载权重做推理的识别界面、以及一份能解释清楚指标和参数的报告。它适合做计算机视觉课程设计、毕业设计也适合刚接触目标检测、想用一个真实场景把 YOLOv8 全流程走一遍的工程师。下面我按自己带人做这类项目的顺序把数据、训练、推理、踩坑和进阶一条条拆开讲你照着做基本能跑通一套属于自己的版本。2. 数据集准备交通标志的标注、清洗与 YOLOv8 格式转换交通标志检测翻车十次里有七次不是模型的问题是数据的问题。标志牌在真实道路图像里往往只占几十个像素还经常被遮挡、逆光、模糊如果标注质量不过关后面调参调到天亮也没用。这一章先把数据这条链路走通。2.1 交通标志数据集的来源与类别设计常见做法有两种。一种是直接用公开数据集比如 CCTSDB中国交通标志检测数据集或者把 GTSRB 分类数据集用检测框包一层另一种是自己用手机或行车记录仪拍再用 labelme 标注。前者省事后者数据更贴近你的演示场景答辩时也更好讲。类别设计上我一般建议先做 4 到 8 类不要一上来就搞几十类。交通标志里最典型的是限速、禁止、警告、指示这几大类细分下去类别一多每类样本就少模型直接学不动。下面是一个常见的类别表类别 ID类别名说明建议最少样本数0speed_limit限速标志3001no_entry禁止通行3002warning警告标志4003mandatory指示标志4004stop停车让行200样本数不是硬指标但每类低于 150 张时训练出来的模型基本只能记住训练集。类别不平衡是交通标志的常态限速标志满地都是停车标志可能就几十张这个后面在训练参数里要专门处理。2.2 用 labelme 标注并转成 YOLO 格式如果你自己拍图标注工具用 labelme 就够了。标完每张图会生成一个同名 json里面是多边形或矩形坐标。YOLOv8 要的是归一化的class x_center y_center width height文本格式所以中间必须做一次转换。import json import os from pathlib import Path # 类别名到 id 的映射必须和后面 data.yaml 里的 names 顺序一致 CLASS_MAP { speed_limit: 0, no_entry: 1, warning: 2, mandatory: 3, stop: 4, } def labelme_to_yolo(json_path, out_dir, img_w, img_h): with open(json_path, r, encodingutf-8) as f: data json.load(f) lines [] for shape in data[shapes]: label shape[label] if label not in CLASS_MAP: continue # 跳过未定义类别避免训练时报错 pts shape[points] xs [p[0] for p in pts] ys [p[1] for p in pts] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # 归一化到 0~1YOLO 要求中心点加宽高 x_c (x_min x_max) / 2.0 / img_w y_c (y_min y_max) / 2.0 / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h # 过滤掉宽高为 0 的脏框 if w 0 or h 0: continue lines.append(f{CLASS_MAP[label]} {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}) out_path Path(out_dir) / (Path(json_path).stem .txt) out_path.write_text(\n.join(lines), encodingutf-8) # 批量处理 for jp in Path(raw_labels).glob(*.json): labelme_to_yolo(str(jp), labels, img_w1280, img_h720)这段代码有三个关键点。第一CLASS_MAP的顺序必须和data.yaml里的names完全一致否则类别会整体错位模型学出来的东西全是乱的。第二img_w和img_h必须是你标注时那张图的真实尺寸写错了归一化坐标就全废。第三宽高为 0 的框一定要过滤YOLOv8 遇到这种框会在训练时直接报错或者产生 NaN loss。2.3 划分训练集验证集与 data.yaml 写法转换完之后按 8:1:1 划分 train/val/test。注意同一个视频序列抽出来的帧不要跨集合否则验证集里出现训练集的近邻帧指标虚高答辩时一换真实场景就露馅。# 目录结构建议 dataset/ images/ train/ val/ test/ labels/ train/ val/ test/data.yaml是 YOLOv8 训练的入口配置路径写绝对路径最稳相对路径容易因为工作目录不同而找不到path: /home/user/dataset train: images/train val: images/val test: images/test nc: 5 names: 0: speed_limit 1: no_entry 2: warning 3: mandatory 4: stop提示nc必须等于names的条目数多一个少一个都会在训练启动时抛异常。改完类别后记得同步改CLASS_MAP。3. 训练与调参YOLOv8 在交通标志上的参数怎么设数据准备好之后训练本身其实很快真正花时间的是调参和看曲线。这一章讲清楚环境、命令和几个必调参数。3.1 环境搭建与预训练权重选择环境这块Ubuntu 20.04 或者 Windows 都行CPU 版本也能跑通小数据集只是慢。有 GPU 的话比如 GTX1660Ti 这种 6G 显存体验会好很多。安装用 pip 最省事conda create -n yolo python3.10 -y conda activate yolo pip install ultralytics # 验证安装 yolo checksyolo checks会打印出 PyTorch 版本、CUDA 是否可用、以及当前 ultralytics 版本。如果 CUDA 显示不可用但你确实有显卡多半是 PyTorch 装成了 CPU 版重装对应 CUDA 版本的 torch 即可。预训练权重直接用官方的yolov8n.pt或yolov8s.pt。交通标志属于小目标密集场景n最快但精度一般s是精度和速度比较平衡的选择显存够就上m。权重文件第一次运行会自动下载也可以提前下好放到项目根目录。3.2 训练命令与必调参数含义一条典型的训练命令长这样yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience30 \ workers4 \ projectruns/traffic \ nameexp1参数逐个说清楚这几个是交通标志场景里最该动的imgsz输入尺寸。交通标志小640 是底线显存允许可以上 800 或 960小目标召回会明显提升。batch批大小。显存不够就往下调调到 8 甚至 4 都行但太小会让 BN 统计不稳。lr0初始学习率。微调预训练权重时 0.01 是常用值从头训练可以到 0.02。lrf最终学习率系数余弦退火的终点一般 0.01。patience多少轮没提升就早停。交通标志容易过拟合30 是个稳妥值。workers数据加载线程。Windows 上设 0 或 2设大了容易卡死。训练过程中重点看runs/traffic/exp1/results.csv里面有每轮的 box_loss、cls_loss 和 mAP。想看损失曲线直接读这个 csv 画图import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/traffic/exp1/results.csv) df.columns [c.strip() for c in df.columns] # 列名可能带空格 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)box_loss 负责框的位置cls_loss 负责分类。如果 box_loss 一直降但 mAP 不涨通常是标注框质量差或者类别混淆如果 cls_loss 震荡厉害多半是学习率偏大或者类别不平衡。3.3 类别不平衡与数据增强的取舍交通标志里限速类样本远多于其他类直接训练会让模型偏向多数类。常见做法是在data.yaml同级加一个带权重的训练或者用 YOLOv8 内置的增强参数。默认的 mosaic、mixup、HSV 抖动对交通标志都有效但要注意mosaic默认 1.0能显著提升小目标但会让框的分布变怪后期可以调低。hsv_h、hsv_s、hsv_v控制颜色抖动交通标志颜色是重要特征抖动别开太大0.015/0.7/0.4 是默认值够用。degrees旋转交通标志在图像里基本是正的旋转开大了反而有害保持 0 或很小。如果某类样本实在太少与其硬训不如先做离线增强把样本补到 200 张以上比在训练里调参数见效快。4. 推理与识别系统把权重变成一个能演示的界面训练完拿到best.pt下一步是让它能被人用起来。期末大作业的演示环节老师看的就是这个。4.1 用 Python 脚本做单图与批量推理最基础的推理脚本from ultralytics import YOLO model YOLO(runs/traffic/exp1/weights/best.pt) # 单图推理 results model.predict( sourcetest.jpg, conf0.25, # 置信度阈值低于此值的框丢弃 iou0.45, # NMS 的 IoU 阈值重叠框合并 imgsz640, saveTrue, # 保存带框的结果图 projectinfer, namesingle ) # 批量推理整个文件夹 model.predict(sourcetest_images/, conf0.25, saveTrue, projectinfer, namebatch)conf和iou是推理阶段最该调的两个参数。交通标志场景里conf设太低会冒出一堆误检设太高会漏掉远处的小标志0.25 到 0.35 之间试。iou控制重叠框合并标志牌密集时调低一点避免把相邻标志合并掉。4.2 用 Gradio 快速搭一个识别界面要演示界面比命令行直观得多。Gradio 几行就能搭起来import gradio as gr from ultralytics import YOLO import numpy as np model YOLO(runs/traffic/exp1/weights/best.pt) def detect(image): results model.predict(image, conf0.3, imgsz640) # results[0].plot() 返回画好框的 numpy 图像 return results[0].plot() demo gr.Interface( fndetect, inputsgr.Image(typenumpy), outputsgr.Image(typenumpy), title交通标志检测识别系统 ) demo.launch(server_name0.0.0.0, server_port7860)gr.Image(typenumpy)保证输入直接是数组省去格式转换。results[0].plot()会把框、类别和置信度都画上去直接返回就能显示。启动后浏览器打开对应端口就能上传图片看效果答辩演示用这个足够。4.3 识别结果的类别名与置信度输出如果要在界面上额外显示文字结果可以遍历results[0].boxesnames model.names # {0: speed_limit, ...} for box in results[0].boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() print(f{names[cls_id]} 置信度 {conf:.2f} 位置 {xyxy})model.names是从权重里读出来的类别映射和你训练时的data.yaml一致。这里输出的置信度是排序后的界面上一般只显示前几个高分结果避免刷屏。5. 避坑与排查交通标志检测最常见的 5 个翻车现场这一章是我带人做项目时踩出来的血泪经验每条都按现象、原因、解决写遇到问题直接对号入座。现象一训练 loss 正常下降但 mAP 一直是 0 或者极低。原因data.yaml里的names顺序和标注转换时的CLASS_MAP不一致类别整体错位模型学的是错的映射。 解决打开一个标注 txt对照data.yaml检查类别 id 和名字是否一一对应改完重新训练。现象二验证集 mAP 很高换一批真实图片全是误检。原因训练集和验证集来自同一段视频或同一批图分布太接近模型过拟合了场景而不是标志本身。 解决划分数据时按视频序列或拍摄日期切分保证验证集是「没见过」的场景必要时补一些不同光照、不同角度的图。现象三训练到一半 loss 变成 NaN。原因标注里有宽高为 0 的框或者坐标超出图像范围归一化后出现非法值。 解决写个脚本扫一遍所有 label 文件过滤掉宽高小于 0.001 的框并检查坐标是否都在 0 到 1 之间。现象四显存明明够batch 调大就报 OOM。原因imgsz和batch是乘性关系尺寸翻倍显存涨四倍光看 batch 不够。 解决先固定imgsz640调 batch或者用yolo detect train ... batch-1让框架自动找最大可用 batch。现象五推理时同一块标志被框了好几次。原因NMS 的iou阈值设太高重叠框没被合并。 解决把推理的iou从默认 0.7 降到 0.45 左右密集场景可以再低一点但别低于 0.3否则相邻标志会被误合并。注意这五条里前两条最致命因为它们不会报错只会让你在错误的方向上越走越远。每次改完数据或配置先跑 5 个 epoch 看 mAP 有没有正常起步再开长训练。6. 进阶技巧让交通标志检测在答辩和实测里都站得住基础流程跑通之后想拿高分或者真正上线还得再往前推一步。这里讲三个我常用的技巧都是投入产出比比较高的。第一个是用测试时增强TTA换精度。推理时把图片做几种变换各跑一遍再融合mAP 通常能涨 1 到 2 个点代价是速度慢几倍。YOLOv8 里直接加augmentTrueresults model.predict(sourcetest.jpg, augmentTrue, conf0.25)演示场景对速度不敏感这个开关值得开。但如果要部署到边缘设备比如 RK3588 或者 Orin 这类板子上TTA 就别开了老老实实做模型转换和量化。第二个是针对小目标调整检测头。交通标志在 640 输入下经常只有 20 来个像素YOLOv8 的 P3 层负责小目标如果漏检严重可以尝试把输入尺寸提到 960或者用更大的模型。改网络结构属于进阶操作答辩时能讲清楚「为什么小目标难、P3 负责什么」比真的改结构更加分。第三个是把指标讲清楚。老师最爱问的就是 mAP50 和 mAP50-95 的区别。mAP50 是 IoU 阈值 0.5 时的平均精度偏宽松mAP50-95 是 0.5 到 0.95 每隔 0.05 取一次再平均更严格。交通标志检测里mAP50 到 0.9 以上不难但 mAP50-95 往往只有 0.6 左右这个差距要能解释标志框小IoU 稍微偏一点分数就掉得厉害。指标含义交通标志典型值Precision检出的框里有多少是对的0.85~0.95Recall真实标志里有多少被检出0.80~0.92mAP50IoU0.5 的平均精度0.88~0.95mAP50-95多阈值平均精度0.55~0.70最后说个我自己的习惯每次训练完我都会挑 10 张验证集里表现最差的图单独看而不是只看总体指标。翻车的图往往能告诉你数据里还缺什么——可能是夜间、可能是遮挡、可能是某个类别标注太少。盯着平均分容易自我感觉良好盯着最差的那几张才会真正进步。希望帮到你。本文还有配套的精品资源点击获取
返回列表