简介本资源提供一套已训练完成的YOLOv8摩托车佩戴头盔与驾驶员检测模型面向计算机视觉学习者、交通安全智能分析开发者及需要快速落地检测功能的工程人员可直接加载权重进行推理或二次微调省去从零标注与训练的成本。压缩包共901个文件约101.23MB以md说明文档、py训练与推理脚本、pyc缓存、yaml配置、jpg与png示例图、pt权重文件为主另含yml、sh、cpp、ipynb、csv等辅助文件覆盖模型配置、数据组织、部署示例与结果可视化等环节。目前已有828人学习下载说明该方案在头盔佩戴识别与驾驶员检测场景中具备一定参考价值。读者可获得训练好的权重、可复现的工程目录、推理代码与配置模板便于快速验证检测效果并迁移到自有数据适合作为课程设计、项目原型或算法对比的起点。1. 从一张路口抓拍说起yolov8摩托车佩戴头盔和驾驶员检测到底在做什么早晚高峰的路口摄像头每秒产生几十帧画面里面同时出现摩托车、电动车、骑手、后座乘客、头盔、遮阳伞、货筐。人工盯着屏幕看十分钟就眼花。我最早接触这个需求是帮一个园区做出入口安全提醒不戴头盔的骑手进闸时系统要能自动标出来而不是靠保安一辆辆拦。这就是 yolov8摩托车佩戴头盔和驾驶员检测 要解决的事——用目标检测模型在同一帧里同时定位摩托车、判断车上有没有驾驶员、驾驶员和乘客头上有没有头盔。它适合三类人做智慧交通或园区安防的算法工程师、拿这个方向做毕业设计的学生、以及想把现成模型部署到边缘盒子上的嵌入式开发者。核心难点不在“能不能检出摩托车”而在小目标头盔、遮挡、夜间逆光、后座乘客漏检这几个场景上。下面按数据、训练、调参、部署、避坑的顺序把我实际跑过一遍的路径拆开讲参数和命令都能直接抄。2. 数据集怎么攒从 labelme 标注到 yolov8 可训练的目录结构2.1 先想清楚要几个类别别一上来就堆标签很多人第一反应是建一堆类摩托车、电动车、三轮车、驾驶员、乘客、头盔、没戴头盔、帽子……类别一多标注成本翻倍模型还容易在相似类之间反复横跳。我一般会收敛成 4 类这是落地最稳的配置类别 id类别名说明0motorcycle摩托车/电动车车身整体框1driver车上驾驶员含骑手2helmet戴在头上的头盔3no_helmet头部但未戴头盔这样设计的好处是头盔检测不依赖“人”这个大类直接对头部区域建模小目标召回更好驾驶员和乘客统一归到 driver避免后座乘客因为样本少被漏掉。判断“是否佩戴”时用 helmet 和 no_helmet 两个类做互斥比用“人头盔”组合推理简单得多。提示如果业务只关心“有没有戴”可以把 driver 去掉只留 motorcycle、helmet、no_helmet 三类标注量能省三成。2.2 labelme 标注转 yolov8 格式的脚本labelme 存的是 JSONyolov8 要的是每张图一个 txt每行class_id cx cy w h归一化到 0~1。下面这个脚本我用了很多次直接改路径就能跑import json import os from pathlib import Path # 类别名到 id 的映射必须和 data.yaml 里的 names 顺序一致 CLASS_MAP {motorcycle: 0, driver: 1, helmet: 2, no_helmet: 3} def labelme_to_yolo(json_dir, out_dir, img_dir): json_dir Path(json_dir) out_dir Path(out_dir) out_dir.mkdir(parentsTrue, exist_okTrue) for jf in json_dir.glob(*.json): data json.loads(jf.read_text(encodingutf-8)) # labelme 里图片宽高存在 imageWidth/imageHeight w data[imageWidth] h data[imageHeight] 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] xmin, xmax min(xs), max(xs) ymin, ymax min(ys), max(ys) # 转成中心点 宽高并归一化 cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 过滤掉宽高为 0 的异常框 if bw 0 or bh 0: continue lines.append(f{CLASS_MAP[label]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) # 图片和 txt 同名yolov8 靠这个对应 out_file out_dir / (jf.stem .txt) out_file.write_text(\n.join(lines), encodingutf-8) if __name__ __main__: labelme_to_yolo(./raw_json, ./labels, ./images)逻辑说明脚本遍历 JSON按shapes里的矩形点算出外接框再归一化。CLASS_MAP是唯一需要你手动对齐的地方写错一个类别训练时 loss 会正常下降但预测全乱这是血泪经验。参数上cx/cy/bw/bh保留 6 位小数足够yolov8 内部会再处理。2.3 目录结构和 data.yaml 的写法yolov8 对目录有固定期待我一般这样组织dataset/ ├── images/ │ ├── train/ # 训练图 │ └── val/ # 验证图 ├── labels/ │ ├── train/ # 与 train 图同名的 txt │ └── val/ └── data.yamldata.yaml内容path: /home/user/dataset train: images/train val: images/val nc: 4 names: [motorcycle, driver, helmet, no_helmet]nc必须等于 names 长度path用绝对路径最稳相对路径在不同工作目录下容易翻车。划分比例上我一般按 8:2 切但如果你的 no_helmet 样本特别少验证集里要保证每类至少几十张否则 mAP 曲线会剧烈抖动看不出真实效果。3. 训练与调参yolov8 训练自己的数据集时哪些参数真正影响头盔召回3.1 环境搭建与预训练权重选择环境这块ubuntu20.04 搭建 yolov8 环境 cpu 版本 和带 GPU 的流程差不多区别只在 torch 装哪个包。我习惯用 conda 隔离conda create -n yolo8 python3.10 -y conda activate yolo8 # GPU 版本按自己的 cuda 版本选这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics装完yolo checks能打印出环境和设备信息。预训练权重用yolov8n.pt或yolov8s.ptn 最快适合边缘设备s 精度更好适合服务器。gtx1660ti 跑 yolov8 用 s 模型、imgsz 640batch 大概能到 8~16显存 6G 要盯着别爆。3.2 一份能直接跑的训练命令和参数含义yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience30 \ workers8 \ projectruns/helmet \ nameexp1逐个说关键参数imgsz640是输入分辨率头盔属于小目标如果你显存够提到 960 对小头盔召回提升明显但速度会掉lr0初始学习率 0.01 是默认值数据量小于 2000 张时我会降到 0.005避免早期震荡lrf是最终学习率比例配合余弦退火patience30表示 30 轮没提升就早停省时间workers是数据加载线程CPU 核多就调大不然 GPU 会饿着。训练过程中用 tensorboard 看曲线tensorboard --logdir runs/helmet重点盯三条线train/box_loss是否稳定下降、metrics/mAP50是否还在涨、val/box_loss有没有反弹。如果 val loss 早早抬头而 train loss 还在降就是过拟合要么加数据要么开增强。3.3 数据增强里对头盔检测最有效的几项yolov8 默认开了 mosaic、HSV、翻转等增强。针对头盔场景我建议显式调这几个# 在 data.yaml 同级建 hyp.yaml训练时加 hyphyp.yaml hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4 degrees: 10.0 # 小角度旋转模拟摄像头安装偏差 translate: 0.1 scale: 0.5 mosaic: 1.0 # 四图拼接对小目标友好 mixup: 0.1 # 别开太大头盔和背景混一起反而难学mosaic对头盔这种小目标帮助最大它把四张图拼成一张等效于让模型见到更多小尺寸目标。mixup开到 0.1 就够开大了会出现“半透明头盔”这种不真实样本。夜间数据少的话HSV 的 v 通道扰动要保留模拟不同光照。3.4 损失函数曲线怎么读什么时候该停yolov8 画损失函数曲线图 直接在 tensorboard 里看就行。我判断收敛的经验是mAP50连续 20 轮波动小于 0.005且mAP50-95不再上升就可以停。头盔检测里no_helmet的 AP 通常比helmet低因为未戴头盔的头部形态差异大有头发、帽子、逆光剪影如果这个类 AP 一直上不去优先补这类样本而不是盲目加轮数。4. 推理与部署从本地验证到 rk3588 板端跑通4.1 本地推理和结果可视化训练完先本地验证别急着上板子from ultralytics import YOLO model YOLO(runs/helmet/exp1/weights/best.pt) results model.predict( sourcetest_imgs, conf0.35, # 置信度阈值头盔小目标别设太高 iou0.5, # NMS 的 IoU 阈值 imgsz640, saveTrue, projectruns/predict, nametest )conf是关键。头盔目标小置信度普遍偏低设 0.5 会漏掉大量真实头盔我一般从 0.3 起调看误报能不能接受。iou控制重叠框合并摩托车和驾驶员框经常重叠设 0.5 比较平衡。4.2 导出 ONNX 与 rk3588 部署要点rk3588 部署 yolov8 走 ONNX 再转 rknn 是常见路径# 导出 onnxopset 用 12rknn 工具链兼容性最好 yolo export modelruns/helmet/exp1/weights/best.pt formatonnx opset12 imgsz640 simplifyTrue导出后确认输入输出节点名rknn 转换时要用。板端推理时注意两点一是量化rk3588 的 NPU 对 int8 支持好但头盔小目标量化后掉点明显建议先用 fp16 验证精度再决定要不要 int8二是预处理板端 letterbox 的填充值和训练时保持一致否则框会整体偏移。hi3516cv610 这类芯片的转换流程类似核心都是对齐预处理和后处理。4.3 用视频流做端到端验证图片验证过了用一段路口视频跑yolo detect predict modelbest.pt sourceroad.mp4 conf0.35 saveTrue streamTruestreamTrue对长视频省内存。看结果时重点检查后座乘客有没有被漏掉、夜间头盔有没有被误判成 no_helmet、摩托车密集时框有没有串。这些是实验室指标看不出来的。5. 避坑与排查头盔检测翻车的五个真实场景5.1 训练 loss 正常但预测全是 no_helmet现象mAP 看着还行但实际推理几乎把所有头都判成没戴。原因helmet 和 no_helmet 样本极度不均衡no_helmet 占了八成以上模型学会了“偷懒”全猜多数类。解决对 no_helmet 做欠采样或在训练时给 helmet 类更高权重也可以先用两类合并训练再细分。5.2 小头盔目标大量漏检现象远处骑手的头盔完全检不到。原因imgsz 太小头盔在原图里只有十几个像素缩到 640 后信息几乎没了。解决把 imgsz 提到 960 或 1280或者用切片推理SAHI把大图切块分别检测再合并。5.3 后座乘客被当成驾驶员重复计数现象一辆车检出两个 driver统计人数偏多。原因driver 类没有区分前后座模型把两个人都框成 driver。解决要么加 passenger 类要么在后处理里按框的 x 坐标和摩托车框做关联只保留主驾驶位。5.4 夜间逆光下头盔反光被误判现象夜间头盔高光区域被检成 no_helmet 或直接漏掉。原因训练集缺少夜间逆光样本HSV 增强模拟不出真实高光。解决补采夜间数据增强里加随机亮度/对比度扰动必要时对高光区域做预处理。5.5 导出 ONNX 后精度下降现象pt 模型正常onnx 推理框偏移或漏检。原因导出时simplify改变了某些算子或预处理 letterbox 的填充方式不一致。解决导出时对比 pt 和 onnx 在同一张图上的输出逐层排查确认板端预处理和训练时完全一致包括归一化和通道顺序。6. 一个提精度的小技巧用检测框做头盔佩戴的逻辑判定单靠 helmet/no_helmet 两类边界样本还是容易错。我后来加了一层逻辑判定先检出 driver 的头部区域再判断这个区域内 helmet 框和 no_helmet 框谁的面积占比大用比例而不是单框置信度来定结论。def judge_helmet(driver_box, helmet_boxes, no_helmet_boxes, head_ratio0.5): # driver_box: [x1, y1, x2, y2]这里近似用 driver 框上半部分当头部区域 x1, y1, x2, y2 driver_box head_y2 y1 (y2 - y1) * head_ratio # 取上半部分 head_area (x2 - x1) * (head_y2 - y1) def overlap_area(box): bx1, by1, bx2, by2 box ix1, iy1 max(x1, bx1), max(y1, by1) ix2, iy2 min(x2, bx2), min(head_y2, by2) if ix2 ix1 or iy2 iy1: return 0.0 return (ix2 - ix1) * (iy2 - iy1) h_area sum(overlap_area(b) for b in helmet_boxes) n_area sum(overlap_area(b) for b in no_helmet_boxes) # 头盔覆盖头部区域超过一半判为佩戴 return helmet if h_area n_area and h_area / head_area 0.3 else no_helmet这个函数的核心是不只看有没有 helmet 框而是看头盔框在头部区域的覆盖比例。head_ratio0.5是经验值驾驶员框的上半部分大致对应头部0.3是覆盖阈值低于它说明头盔框可能只是擦边。实际用的时候把检测结果按 driver 分组再对每组调用这个函数误报能压下去一截。验证这套逻辑是否有效别只看整体 mAP要单独统计“佩戴判定准确率”人工标一批骑手对比逻辑判定和真实情况。我一般抽 200 个样本准确率能到 90% 以上才敢上线。这个技巧不复杂但它把检测问题转成了判定问题边界样本的鲁棒性会好很多。我自己踩过的最大坑是早期迷信 mAP 数字忽略了夜间和后座这两个场景上线第一周就被保安反馈“晚上基本没用”。后来补数据、加逻辑判定、调 conf 阈值才慢慢稳住。做这类检测指标只是入场券真正决定能不能用的是那些指标覆盖不到的角落。希望帮到你。本文还有配套的精品资源点击获取