尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于YOLOv8的电动车头盔检测系统:ONNX推理与GUI集成实战

基于YOLOv8的电动车头盔检测系统:ONNX推理与GUI集成实战 简介本资源是一套基于YOLOv8的电动车佩戴头盔检测系统面向计算机视觉学习者、安全监管研发人员及课程设计开发者用于在图像或视频中自动识别骑行者与驾驶员是否佩戴头盔。压缩包共129个文件以105张jpg样本图、6个xml标注、6张png图表、3个py源码及1个onnx模型为主另含qrc资源与评估曲线整体约17.12MB结构清晰便于直接运行与二次训练。系统可检测Bicyclist、driver、helmet、no-helmet四类目标配套PyQt5精美GUI界面支持Windows10下Anaconda3Python3.8、torch1.9.0cu111与ultralytics8.2.70环境。已有1012人学习下载读者可获得完整源码、ONNX推理模型、评估指标曲线与可视化界面快速完成从数据标注、模型推理到安全提醒的闭环实践。1. 电动车头盔检测这套源码到底能不能直接跑起来电动车不戴头盔引发的交通事故这几年一直是交管和物业场景里的高频痛点。我拿到这份「基于 YOLOv8 的电动车佩戴头盔检测系统」压缩包时第一反应不是看 GUI 好不好看而是先确认三件事模型是不是真的训练过、ONNX 能不能脱离 PyTorch 独立推理、评估曲线是不是真实跑出来的。这套资源包含 Python 源码、ONNX 模型、评估指标曲线和一套 GUI 界面定位很明确——给需要做课程设计、毕业设计或者小区/厂区电动车入口检测的从业者一个能落地的起点。它适合已经会装 Python、能看懂 YOLO 训练命令的人也适合想拿现成 ONNX 做端侧部署验证的工程师。但如果你连pip install都没用过建议先把 Python 环境配置这一关过了再回来。2. 拆开压缩包先看什么目录结构与技术栈判断2.1 从文件清单反推这套系统的工作流拿到一个检测类源码包我习惯先不跑代码而是把目录树打印出来看结构。这套资源的核心文件大致会落在几个位置训练权重.pt、导出后的 ONNX 模型.onnx、推理脚本、GUI 主程序、评估曲线图通常是results.png、confusion_matrix.png、PR_curve.png这类、以及数据集配置文件.yaml。判断它是不是「能直接用」关键看 ONNX 模型和推理脚本是否配套——很多网上流传的源码只有.pt没有 ONNX或者 ONNX 的输入尺寸和推理代码对不上跑起来就是一堆 shape 报错。常见做法是先用tree或者文件管理器把层级看清楚重点确认三样东西models/下有没有.onnxutils/或根目录下有没有独立的onnx_inference.pyruns/下有没有训练产出的曲线图。如果这三样齐全说明作者至少完整走过一遍「训练→导出→推理→可视化」的流程不是拼凑的。# 查看压缩包内容不解压先看结构 unzip -l 基于yolov8的电动车佩戴头盔检测系统.zip | head -50 # 解压后进入目录看核心文件分布 find . -maxdepth 2 -type f \( -name *.onnx -o -name *.pt -o -name *.py -o -name *.png \) | sort上面第一条命令只列出压缩包内文件避免解压出一堆无关内容第二条用find按扩展名过滤能快速定位模型、脚本和曲线图的位置。参数-maxdepth 2是防止递归太深刷屏实际排查时如果没看到 ONNX可以把这个值调大再找一遍。2.2 技术栈选型为什么是 YOLOv8 ONNX GUIYOLOv8 在电动车头盔这种「小目标 密集场景」里优势明显Anchor-Free 结构对头盔这种不规则形状更友好而且 Ultralytics 的工程化做得好训练和导出都是一行命令的事。选 ONNX 而不是直接上 TensorRT 或者 RKNN是因为 ONNX 是中间格式通用性最强——你在 Windows 上导出的 ONNX拿到 Ubuntu 或者 RK3588 上都能继续转不用重新训练。GUI 部分大概率是 PyQt5 或者 Tkinter前者做检测框叠加和视频流显示更顺手后者胜在轻量、依赖少。这里要提醒一句ONNX 模型分动态轴和静态轴。如果导出时用了dynamicTrue推理时输入尺寸可以变如果没加那推理代码里的resize尺寸必须和导出时严格一致否则直接报维度不匹配。我一般会在导出后先用onnxruntime跑一张测试图确认输入输出节点名字和形状再往 GUI 里集成。import onnxruntime as ort import numpy as np # 加载 ONNX 模型查看输入输出信息 session ort.InferenceSession(helmet_yolov8.onnx, providers[CPUExecutionProvider]) for inp in session.get_inputs(): print(输入名:, inp.name, 形状:, inp.shape, 类型:, inp.type) for out in session.get_outputs(): print(输出名:, out.name, 形状:, out.shape) # 构造一张符合输入尺寸的假数据跑通前向 dummy np.random.randn(1, 3, 640, 640).astype(np.float32) result session.run(None, {session.get_inputs()[0].name: dummy}) print(输出张量数量:, len(result), 首个输出形状:, result[0].shape)这段代码的作用是「验模型」——在写任何 GUI 代码之前先确认 ONNX 本身是活的。providers参数指定 CPU 推理如果你机器上有 CUDA 且装了onnxruntime-gpu可以换成CUDAExecutionProvider提速。dummy的尺寸(1, 3, 640, 640)是 YOLOv8 的默认输入如果你的模型导出时改了imgsz这里要同步改。输出形状里通常包含框坐标、置信度和类别概率具体排列顺序取决于导出时的设置跑通一次心里就有数了。3. 从零跑通推理环境配置与 ONNX 前向验证3.1 Python 环境与依赖安装的版本坑这套源码对 Python 版本有要求YOLOv8 官方推荐 3.8 到 3.11太新的 3.12 在某些torch版本上会翻车。我一般用 conda 建一个干净环境避免和系统里的包打架。依赖清单里通常会有ultralytics、onnxruntime、opencv-python、PyQt5、numpy、matplotlib这几个。注意onnxruntime和onnxruntime-gpu只能装一个装错了要么用不了 GPU要么直接 import 报错。# 创建并激活虚拟环境 conda create -n helmet_det python3.9 -y conda activate helmet_det # 安装核心依赖指定版本避免自动升级到不兼容版本 pip install ultralytics8.0.200 onnxruntime1.16.3 opencv-python4.8.1.78 pip install PyQt55.15.9 numpy1.24.3 matplotlib3.7.4 # 验证 onnxruntime 是否可用 python -c import onnxruntime as ort; print(ort.get_available_providers())ultralytics指定 8.0.x 是因为 8.1 之后部分 API 有变动老代码可能报AttributeError。onnxruntime选 1.16.3 是相对稳定的版本太新的版本在某些 Windows 环境下会缺 DLL。最后一行打印可用推理后端如果只显示CPUExecutionProvider说明你装的是 CPU 版想用 GPU 得换onnxruntime-gpu并确认 CUDA 版本匹配。3.2 用 ONNX 跑单张图并解析检测框环境好了之后先别急着开 GUI用脚本跑一张电动车头盔的测试图把检测框画出来看看效果。这一步能验证三件事模型能不能检出目标、类别标签对不对、置信度阈值设多少合适。YOLOv8 的 ONNX 输出通常是(1, 84, 8400)或者(1, 8400, 84)84 是 4 个框坐标加 80 个类别概率COCO 预训练但头盔检测一般是自定义数据集类别数会少很多比如 2 类戴头盔/不戴头盔。import cv2 import numpy as np import onnxruntime as ort def preprocess(img, size640): # 保持长宽比的 letterbox 缩放避免形变影响检测 h, w img.shape[:2] scale min(size / h, size / w) nh, nw int(h * scale), int(w * scale) resized cv2.resize(img, (nw, nh)) canvas np.full((size, size, 3), 114, dtypenp.uint8) top (size - nh) // 2 left (size - nw) // 2 canvas[top:topnh, left:leftnw] resized blob canvas[:, :, ::-1].transpose(2, 0, 1).astype(np.float32) / 255.0 return np.expand_dims(blob, 0), scale, left, top session ort.InferenceSession(helmet_yolov8.onnx, providers[CPUExecutionProvider]) img cv2.imread(test_helmet.jpg) blob, scale, left, top preprocess(img) outputs session.run(None, {session.get_inputs()[0].name: blob})[0] # 输出形状通常是 (1, 4nc, 8400)转置后按行处理 preds np.squeeze(outputs).T scores np.max(preds[:, 4:], axis1) keep scores 0.45 # 置信度阈值可按实际效果调整 boxes preds[keep, :4] classes np.argmax(preds[keep, 4:], axis1) print(检出目标数:, len(boxes), 类别分布:, np.bincount(classes))preprocess里的 letterbox 是 YOLO 系列的标准预处理灰色填充值 114 是官方默认换成别的值会影响精度。scores 0.45这个阈值不是固定的头盔检测场景里如果误检多就调高漏检多就调低我一般从 0.45 开始试。preds[:, :4]是框的cx, cy, w, h要还原到原图还得除以scale再减去left、top的偏移这部分在 GUI 里画框时一定要做对否则框会整体偏移。3.3 评估指标曲线怎么看mAP、PR 曲线与混淆矩阵资源里带的评估曲线图不是装饰品它能告诉你这个模型在验证集上的真实水平。重点看三张图results.png里的mAP0.5和mAP0.5:0.95曲线是否收敛、PR_curve.png里各类别的曲线下面积、confusion_matrix.png里有没有把「戴头盔」误判成「不戴头盔」。如果 mAP0.5 在 0.85 以上说明模型基本可用如果低于 0.6要么数据集标注有问题要么训练轮次不够。指标含义合格参考值mAP0.5IoU 阈值为 0.5 时的平均精度头盔检测建议 ≥ 0.85mAP0.5:0.95多个 IoU 阈值下的综合精度≥ 0.55 算不错Precision检出的目标里有多少是对的误检多时重点关注Recall真实目标里有多少被检出漏检多时重点关注混淆矩阵各类别之间的误判分布对角线越集中越好看 PR 曲线时注意如果「不戴头盔」这一类曲线明显低于「戴头盔」说明小目标或者遮挡样本的召回不够可能需要补充难例样本重新训练。混淆矩阵里如果出现大量「背景→不戴头盔」的误判那是把路灯、行人误检成了目标得回头检查数据集里有没有标错。4. GUI 集成与实时视频流推理的落地细节4.1 PyQt5 界面与检测线程的分离GUI 卡顿是这类系统最常见的翻车点。原因很简单如果把 ONNX 推理直接放在主线程里每处理一帧界面就冻结一次视频流看起来像幻灯片。正确做法是把推理逻辑放到QThread里通过信号槽把检测结果传回主线程画框。这套源码如果已经做了线程分离那说明作者有工程经验如果没做你得自己补上。from PyQt5.QtCore import QThread, pyqtSignal import cv2 import numpy as np class DetectThread(QThread): frame_ready pyqtSignal(np.ndarray, list) # 信号原图 检测框列表 def __init__(self, session, source0): super().__init__() self.session session self.source source self.running True def run(self): cap cv2.VideoCapture(self.source) while self.running and cap.isOpened(): ret, frame cap.read() if not ret: break # 推理逻辑与前面单图一致此处省略预处理细节 boxes self.infer(frame) self.frame_ready.emit(frame, boxes) cap.release() def infer(self, frame): # 实际推理返回框列表 return [] def stop(self): self.running False self.wait()QThread子类里重写run方法循环读帧、推理、发信号。pyqtSignal定义了两个参数np.ndarray传图像list传检测框。主线程收到信号后只负责cv2.rectangle画框和QLabel.setPixmap显示不碰推理界面就不会卡。stop方法里先置runningFalse再wait()是防止线程还在跑的时候直接关窗口导致崩溃。4.2 视频流推理的帧率优化与跳帧策略实时视频流不一定每帧都要推理。如果摄像头是 30 帧ONNX 在 CPU 上跑一帧要 80 毫秒那实际只能处理 12 帧左右剩下的帧要么丢弃要么复用上一帧的检测结果。常见做法是「跳帧推理」每 3 帧做一次检测中间帧沿用上一次的框视觉上几乎看不出差别但 CPU 占用能降一半。frame_count 0 last_boxes [] while True: ret, frame cap.read() if not ret: break frame_count 1 if frame_count % 3 0: # 每 3 帧推理一次 last_boxes infer(frame) draw_boxes(frame, last_boxes) # 中间帧复用上次结果 cv2.imshow(Helmet Detection, frame) if cv2.waitKey(1) 0xFF ord(q): breakframe_count % 3这个数字根据你机器的实际推理速度调CPU 慢就设 5GPU 快就设 1。last_boxes复用的时候要注意如果目标移动很快框会有拖影这时候要么提高推理频率要么在中间帧做简单的线性插值。我一般会在 GUI 上留一个「跳帧间隔」的输入框方便现场根据机器性能调。4.3 置信度阈值与 NMS 参数的联动调整GUI 上通常会有置信度阈值和 IoU 阈值的滑动条。这两个参数是联动的置信度调低检出的框变多NMS 的 IoU 阈值如果还很高重叠框就删不干净置信度调高框变少IoU 阈值可以适当降低。头盔检测里两个人挨得近的时候NMS 的 IoU 设 0.45 到 0.5 比较合适太低会把相邻目标的框误删。def nms(boxes, scores, iou_threshold0.45): # 标准 NMS 实现boxes 格式为 xyxy x1, y1, x2, y2 boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3] areas (x2 - x1) * (y2 - y1) order scores.argsort()[::-1] keep [] while order.size 0: i order[0] keep.append(i) xx1 np.maximum(x1[i], x1[order[1:]]) yy1 np.maximum(y1[i], y1[order[1:]]) xx2 np.minimum(x2[i], x2[order[1:]]) yy2 np.minimum(y2[i], y2[order[1:]]) inter np.maximum(0, xx2 - xx1) * np.maximum(0, yy2 - yy1) iou inter / (areas[i] areas[order[1:]] - inter) order order[1:][iou iou_threshold] return keepiou_threshold0.45是经验值实际调的时候看场景电动车密集停放时调到 0.5 减少误删稀疏场景调到 0.4 去掉更多重叠框。scores.argsort()[::-1]是按置信度从高到低排序NMS 的核心逻辑就是保留最高分框、抑制与它重叠度超阈值的框。这段代码在 GUI 里应该封装成独立函数滑动条一变就重新跑一遍 NMS不用重新推理。5. 避坑与排查这套源码最容易翻车的五个地方5.1 现象ONNX 加载报错InvalidGraph或维度不匹配原因通常是导出时的opset版本和onnxruntime不兼容或者输入尺寸写死了但推理时传了别的尺寸。解决方法是重新导出时指定opset12并在推理前用session.get_inputs()[0].shape确认尺寸把预处理里的resize对齐。5.2 现象GUI 启动后摄像头画面黑屏或卡死原因多半是摄像头索引不对或者推理线程阻塞了主线程。先确认cv2.VideoCapture(0)里的 0 是不是你的摄像头笔记本外接摄像头可能是 1。如果是线程问题检查QThread的run里有没有死循环没退出的情况stop方法有没有被正确调用。5.3 现象检测框位置整体偏移或缩放不对这是 letterbox 还原时算错了scale和padding。检查预处理里scale min(size/h, size/w)是不是用了max以及画框时有没有先除以scale再减去left、top。我见过有人直接拿 640 的框往原图上画结果框全挤在左上角。5.4 现象评估曲线 mAP 很高但实际检测效果差原因通常是训练集和验证集分布太接近模型过拟合了。看results.png里训练 loss 还在降但验证 loss 已经抬头就是过拟合信号。解决办法是加数据增强 mosaic、mixup 、增加背景负样本、或者减少训练轮次。5.5 现象onnxruntime和ultralytics版本冲突导致 import 失败ultralytics依赖特定版本的torch而onnxruntime又依赖特定版本的numpy三者版本不匹配时 import 就报错。最稳的做法是按ultralytics官方要求的版本装torch再单独装onnxruntime不要用pip install -r requirements.txt一把梭那个文件里的版本约束经常是过期的。6. 进阶把 ONNX 转到 RK3588 或 ncnn 的验证思路这套资源里的 ONNX 模型不只是能在 PC 上跑它更大的价值是作为中间格式往端侧转。现在 RK3588 部署 YOLOv8 的需求很多流程是 ONNX → RKNN用rknn-toolkit2转换。但转之前必须确认 ONNX 的输入是静态的、opset 不超过 12、没有 RKNN 不支持的算子比如某些自定义的Resize模式。我一般会先用onnxsim简化模型再去转 RKNN成功率会高很多。from rknn.api import RKNN rknn RKNN() rknn.config(mean_values[[0, 0, 0]], std_values[[255, 255, 255]], target_platformrk3588) rknn.load_onnx(modelhelmet_yolov8.onnx) rknn.build(do_quantizationTrue, datasetquant_dataset.txt) # int8 量化需要校准集 rknn.export_rknn(helmet_yolov8.rknn)do_quantizationTrue是 int8 量化能大幅降低模型体积和推理延迟但需要准备一个校准集quant_dataset.txt里面放几十张代表性图片的路径。量化后精度通常会掉 1 到 3 个点如果掉太多就改成do_quantizationFalse跑 fp16。target_platform写rk3588如果是 RK3568 就改掉平台选错转换会直接失败。转 ncnn 的话用在线转换工具或者onnx2ncnn命令行都行但 ncnn 对 YOLOv8 的Split和Concat算子支持要看版本转完最好用ncnnoptimize过一遍再用benchncnn测一下速度。验证方法很简单同一张测试图PC 上 ONNX 推理的结果和板端 RKNN/ncnn 推理的结果框的位置偏差应该在几个像素以内类别和置信度基本一致。如果偏差很大多半是预处理里的归一化参数没对齐——PC 上用的std255板端如果用了std1结果就全乱了。从那以后我每次拿到新的 ONNX 模型都强制走一遍「单图推理 → 结果可视化 → 端侧转换 → 交叉验证」的流程不看到框画在原图上绝不往 GUI 里集成。这套电动车头盔检测源码把训练、导出、评估、GUI 都串起来了省去了自己搭框架的时间但里面的参数和版本坑还是得自己踩一遍才踏实。希望帮到你。本文还有配套的精品资源点击获取
返回列表