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

资讯详情

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

基于深度学习的电动自行车头盔佩戴检测系统:YOLO与PyTorch实战指南

基于深度学习的电动自行车头盔佩戴检测系统:YOLO与PyTorch实战指南 简介基于YOLOv5与DeepSORT的电动自行车头盔佩戴检测系统是一份面向人工智能及深度学习开发者的完整工程。针对骑行场景中头盔佩戴状态的实时识别与多目标追踪问题整合了目标检测与重识别技术适合智慧交通、安全监控等场景落地也适合有Python基础的学生进行算法实践与二次开发。压缩包共186个文件容量133.57MB包含55个Python脚本、22个YAML配置、7个模型权重文件、45张PNG图片及HTML/JS/CSS展示页面等其中Python脚本覆盖训练与推理逻辑YAML用于模型结构配置pt文件提供预训练权重。已有422人学习浏览。借助该工程可直接复现头盔检测与追踪过程获得模型结构定义、预训练权重、训练调参代码和前端监控界面既能用于理解YOLOv5目标检测与DeepSORT多目标追踪机制也为后续算法改进和业务系统集成提供了可行基础。1. 基于深度学习的电动自行车头盔佩戴检测系统先搞懂它解决什么问题这类名字带“.zip”的项目我每年都要帮人盘一遍。它解决的问题很具体摄像头拍下电动自行车经过的画面系统自动判断骑车人有没有戴头盔没戴就抓拍、报警戴了就正常通行。用深度学习的检测系统来做比普通图像处理稳定得多——能扛逆光、夜间、侧脸和遮挡准确率普遍能做到95%以上。这套东西适合三类人毕业设计选型的学生、园区或工地出入口想加一道自动监管的工程师、还有刚接触目标检测想跑通一个完整项目的算法入门者。它不是一个只能跑demo的黑匣子而是把数据、标注、训练、部署完整串起来的系统工程。2. 模型选型为什么头盔检测绕不开YOLO和PyTorch2.1 头盔佩戴检测的本质是定位不是单纯分类头盔佩戴检测听起来是“判断戴没戴”但真正落到系统里必须同时输出“人在哪”和“这个人是否戴盔”否则没法联动抓拍或统计车流。所以它天然是一个目标检测任务不是图像分类任务。如果你用分类网络把整张图分成“戴盔”和“没戴盔”只要图里有一个人没戴整张图就报废漏报率极高。目标检测的主流路线有三类两阶段检测器Faster R-CNN、单阶段检测器YOLO/SSD和基于Transformer的端到端检测器DETR/RT-DETR。头盔这类小目标多、实时性要求高的场景两阶段虽然精度上限高但速度太慢DETR那套在CPU和低端边缘设备上跑不动YOLO系单阶段检测器在速度和精度的平衡上最友好因此绝大多数落地系统选它。我的经验是别在模型选型上过度纠结把精力放到数据和标注上。用YOLOv8n或者YOLOv5s对头盔检测这种语义简单的任务已经能跑到mAP50在0.9以上。真正决定上限的是标注质量、类别定义和夜间样本数量。另外类别设计也有讲究。常见方案是直接分两个类0表示“戴着头盔的人”1表示“没戴头盔的人”框画在人身上另一种是把head和helmet分别检测再通过IoU判断头盔是否戴在头上。后者能处理“手里拿着头盔”的干扰但标签和后处理复杂度高。对于电动自行车出入口这种场景二分类方案足够了。2.2 YOLOv5和YOLOv8怎么选一张表说清常见的新手问题是用YOLOv5还是YOLOv8。这里给一个可抄作业的对比模型主干是否anchor-free显存占用bs16,640推荐场景YOLOv5sCSPDarknet否约6GB老项目维护、N卡部署资料多YOLOv8n改进CSPDarknet是约4GB快速验证、边缘部署YOLOv8s改进CSPDarknet是约6GB精度优先的小型系统RT-DETRResNetTransformer是约8GB不追求速度、只做离线分析如果只是毕设或者出demo我一般直接用ultralytics库配YOLOv8n因为它的训练命令和导出工具一条命令搞定不用手写很多胶水代码。如果要求严谨的工程交付YOLOv5的生态更稳定TensorRT部署资料也多。注意这里的“n/s”是模型尺寸不是版本后缀。头盔目标相对小直接上n可能会有漏检可以先跑一版s如果速度不够再换回n。2.3 环境搭建PyTorch加ultralytics的最小配置环境不用装一堆东西PyTorch、ultralytics、OpenCV三件套就够了。这里给一个Linux或者Windows都可以用的conda安装命令conda create -n helmet python3.9 -y conda activate helmet pip install torch1.13.1cu117 torchvision0.14.1cu117 --extra-index-url https://download.pytorch.org/whl/cu117 pip install ultralytics opencv-python先解释逻辑conda创建独立的Python 3.9环境避免把系统Python搞乱pip安装指定版本的PyTorchcu117表示适配CUDA 11.7这个版本对RTX 30系和40系驱动都友好。如果你显卡驱动不支持11.7需要去PyTorch官网查对应CUDA版本不要盲目抄。pip下载慢的话可以在命令末尾加-i https://pypi.tuna.tsinghua.edu.cn/simple。安装完先验证一下GPU是否被识别import torch print(torch.__version__) print(torch.cuda.is_available())如果输出False大概率是CUDA/显卡驱动版本不匹配或者装成了CPU版。先用CPU版跑通小规模训练也没有问题只是慢。头盔数据集一般不会太大CPU训练一晚也能出结果这条血泪经验后面避坑章节会展开。3. 数据准备把头盔标注成YOLO格式的4个关键步骤3.1 数据来源和数量别迷信公开数据集自己补拍才管用头盔佩戴检测没有特别统一的标准数据集。很多公开安全帽数据集以工地大黄色安全帽为主电动自行车的头盔是半盔、全盔、彩色头盔形状差异大直接迁移会翻车。常见做法是混合三路数据公开数据集比如SCUT-HEAD、Global Safety Helmet Dataset里头的head类主要用来预训练和补充负样本自己用手机或摄像头录街道骑行视频抽帧得到图像如果设备到位做合成把头盔抠图贴到背景上做马赛克增强但注意不要破坏光照一致性。数量经验戴头盔和不戴头盔两类目标各不少于3000个框这个数量级对YOLO来说足够。图像总数在5000到10000张之间不要太多到训练时间爆炸也不要少到类别不平衡。如果你做毕设时间有限可以先用公开数据集跑通流程再补2000张自己的场景数据。数据里一定要包含夜间、逆光、雨天、侧脸这些难例否则白天现场效果很好一入夜就大面积漏检。3.2 标注规范两类还是分部位先想清楚再动手标注前必须定类别方案否则返工到崩溃。我推荐用二分类方案类别0helmet_ridden戴着头盔的人类别1no_helmet没戴头盔的人注意框的是“人头盔”整体不是单独框头盔。这样模型直接输出人的位置和是否戴盔省掉后处理。如果采用多类别方案把person、helmet、head分开检测再通过几何关系判断头盔和head的重叠率能处理“手里拿着头盔”的干扰但标签和后处理复杂度高不建议第一次做就选它。标注工具我用LabelImg因为它直接输出Pascal VOC XML稍后转成YOLO txt很方便。标注时遵循几个原则被严重遮挡的目标不标只有上半身出现在画面里也标但像素面积小于30x30的忽略夜间看不清的不硬标。这些原则看起来琐碎实际上决定模型泛化能力。还有一条很容易忽略不要用同一个文件既有VOC又有YOLO格式LabelImg会自动生成classes.txt这个文件里的类别顺序必须和CLASS_MAP一致否则转出来的txt类别索引是乱的。3.3 把VOC标注转成YOLO格式Python脚本直接用LabelImg默认保存为VOC格式而YOLO训练需要的是每个图片一个txt文件每行是“类别 cx cy w h”坐标相对图像宽高。写转换脚本时最容易错的是归一化和类别索引贴一个我常用的版本import xml.etree.ElementTree as ET import os CLASS_MAP {helmet_ridden: 0, no_helmet: 1} def convert_voc_to_yolo(xml_file, out_txt): tree ET.parse(xml_file) root tree.getroot() width int(root.findtext(size/width)) height int(root.findtext(size/height)) lines [] for obj in root.findall(object): name obj.findtext(name) if name not in CLASS_MAP: continue bndbox obj.find(bndbox) xmin float(bndbox.findtext(xmin)) ymin float(bndbox.findtext(ymin)) xmax float(bndbox.findtext(xmax)) ymax float(bndbox.findtext(ymax)) x_center (xmin xmax) / 2 / width y_center (ymin ymax) / 2 / height box_w (xmax - xmin) / width box_h (ymax - ymin) / height # 防止越界写死一点更稳 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) lines.append(f{CLASS_MAP[name]} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) with open(out_txt, w, encodingutf-8) as f: f.write(\n.join(lines)) if __name__ __main__: xml_dir Annotations out_dir labels os.makedirs(out_dir, exist_okTrue) for xml_name in os.listdir(xml_dir): if not xml_name.endswith(.xml): continue convert_voc_to_yolo(os.path.join(xml_dir, xml_name), os.path.join(out_dir, xml_name.replace(.xml, .txt)))这段代码做的事情遍历一个目录下所有XML读图像宽高把每个object的bbox从左上右下坐标转成中心点加宽高再除以宽高完成归一化。注意三个细节。第一类别名必须和CLASS_MAP里的完全一致包括大小写写错会静默跳过第二YOLO格式要求类别索引从0开始第1个字段是整数后面是浮点第三坐标可能会因为标注工具误差越界加一个min/max裁剪可以减少训练警告。3.4 数据增强和划分不要只加翻转要加夜间和遮挡YOLO内置增强在配置文件里就能开比如mosaic、mixup、hsv_h/hsv_s/hsv_v、fliplr。对于头盔检测最有用的增强是mosaic4张图拼一起增加小目标出现频率夜间亮度变化把hsv_v的range拉大模拟暗光随机裁剪和仿射变换增强戴盔的人被杆子、手部遮挡的情况。划分数据集时注意不要随机分而要按照视频来源/时间分。比如你录了三个视频应该让同一段视频的帧只出现在train或val中否则验证集是“作弊”的测出来mAP虚高。这是我踩过的坑之一。划分比例7:2:1或8:2都可以但val至少要有300张以上否则mAP波动太大。4. 训练与调参让头盔检测模型在100轮内收敛到90% mAP4.1 数据配置写对helmet.yaml别让训练静默跑偏ultralytics训练需要自己的YAML配置指定训练集、验证集和类别信息。常见错误是把图片和标签放在同一个文件夹或者路径写成绝对路径换机器后失效。我一般在项目根目录放一个helmet.yaml内容这样path: ./helmet_dataset train: images/train val: images/val names: 0: helmet_ridden 1: no_helmetpath是数据集根目录train和val是相对根目录的图片路径。labels与images并列ultralytics会自动到images/train同级的labels/train里找txt。这里有一个隐藏规则图片路径下必须存在对应的同名txt否则训练时该图片直接跳过而且不报错导致mAP虚高。新手最容易在这地方翻车。4.2 训练命令和关键参数从预训练权重开始别从零训练训练不要自己从头搭模型用官方预训练权重做迁移学习。命令如下yolo detect train \ datahelmet.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ optimizerAdamW \ patience15 \ workers8逐行说明data指向刚才写的yamlmodel用yolov8n.pt第一次运行会自动下载COCO预训练权重如果你网络环境没法访问可以先把权重下载好后放到目录里epochs设100头盔数据集小100轮足够多反而过拟合imgsz用640如果你的摄像头画面是1080P且头盔占比小可以提高到960或1280但显存占用指数上涨batch16是一个均衡值8G显存能跑lr00.01配合AdamW是ultralytics默认推荐SGD则需要调低到0.001patience15表示15轮mAP没有提升就早停防止晚上睡觉后训练跑过头。训练日志里重点看两类指标box_loss和cls_loss是否单调下降val的mAP50是否稳步上升。如果loss降了但mAP不动大概率是标签和图片对不上或者类别定义有问题。训练过程中不要频繁改参数等一轮结束再看趋势。4.3 验证与评估不只盯着mAP要看漏检和误检训练完生成best.pt和last.pt验证命令是yolo detect val modelbest.pt datahelmet.yaml batch32输出包含mAP50和mAP50-95。对于头盔检测这个场景mAP50比mAP50-95更实用因为最终决策只要IoU大于0.5就算命中。如果mAP50在90%以上基本可以进入部署环节。但mAP是整体统计掩盖了小目标漏检建议额外看一下混淆矩阵和PR曲线。混淆矩阵里最容易出现的是类别0和类别1互相混淆这说明两类目标在视觉上太像——常见原因是标注时把“戴着头盔但头盔很小”标成了no_helmet。如果目标是做系统我还会把验证结果的预测图导出来人工看几百张。这不是玄学目标检测项目的数据bug很多都靠人工翻图才能发现比如标签错位、漏标、遮挡框乱跳。4.4 断点续训和最终权重选择训练如果因为断电中断不用从头开始yolo detect train modelruns/train/exp/weights/last.pt datahelmet.yaml epochs100断点续训用last.pt而不是best.pt因为best.pt是mAP最高点但对应的学习率状态可能不是最后状态。续训后epochs是指“总轮数”不是“剩余轮数”——这个坑我踩过续训设100会多训100轮导致过拟合。最终选择权重时别迷信best.pt如果best.pt对应的验证损失很高但mAP高说明是阈值巧合我一般选训练后期稳定轮次的权重用验证视频实测效果定版本。5. 避坑清单头盔数据集最常见的5个翻车点5.1 mAP一直为0先查标签文件是不是空的现象训练loss下降但是val结果全为0输出图片上一个框都没有。 原因ultralytics在数据目录下没找到任何标注文件时不会报错只是静默跳过全部图片。 解决检查labels目录里是否有txt且txt非空用脚本统计每个txt的行数如果全是0回看转换脚本的类别名是否匹配。5.2 推理时头盔小目标漏检现象大头盔能检测远处的小头盔就是预测不到。 原因模型输入是640x640原图压缩后小目标只有十几个像素特征丢失。 解决提高imgsz到960或1280或者在预处理时对图像做切片推理SAHI把大图切成重叠块分别检测再合并。后者能立竿见影但推理时间也成倍增加。5.3 显存溢出现象batch16报CUDA out of memory。 原因显卡显存不够或者后台有其他进程占显存。 解决先看nvidia-smi确认显存占用将batch降到4或8同时开启梯度累积。注意降batch会影响BN统计所以尽量用更大的batch显存不够时用累积模拟大batch。5.4 torch.cuda.is_available()返回False现象训练完全在CPU上跑慢到怀疑人生。 原因PyTorch装成了CPU版或者CUDA版本与显卡驱动不匹配。 解决用python -c import torch;print(torch.cuda.is_available())验证如果是CPU版需要卸载重装。NVIDIA显卡驱动更新后老CUDA也经常失效所以安装前用nvidia-smi查出驱动支持的最高CUDA版本再选PyTorch对应wheel这也是深度学习环境配置里最常见的坑。5.5 标注框整体偏移导致检测框错位现象训练后模型检测框偏左/偏上像是整体平移。 原因VOC转YOLO时用错了图像宽高或者XML里的size和实际图像不一致。 解决转换脚本里打印一行日志对比XML的width/height和实际图像尺寸另外很多标注工具会生成旋转框如果坐标带theta就需要用旋转框公式而不是直接取min/max。头盔检测场景不需要旋转框直接忽略theta就好。6. 从模型到系统ONNX/TensorRT导出与摄像头实时检测6.1 导出ONNX和TensorRT边缘部署的必由之路训练得到的best.pt是PyTorch权重生产环境不会直接用它跑因为加载慢、显存高。我一般先导出ONNX做跨平台验证再在目标设备上转成TensorRTyolo export modelbest.pt formatonnx opset12 yolo export modelbest.pt formatengine device0 halfTrueONNX的opset可以指定12兼容性强。engine是TensorRT专有格式halfTrue用FP16推理速度能翻倍。导出后最好在Jetson或者带TensorRT的电脑上测一下速度确认模型推理延迟低于50ms否则实时性无从谈起。6.2 摄像头实时检测一版能跑通的推理脚本部署端我用OpenCV读摄像头配合ultralytics的predict接口做推理import cv2 from ultralytics import YOLO model YOLO(best.engine) # TensorRT引擎 cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while True: ret, frame cap.read() if not ret: break results model(frame, conf0.25, iou0.45, verboseFalse) annotated results[0].plot() cv2.imshow(helmet detection, annotated) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段脚本的核心是模型推理接口conf和iou两个参数要现场调。conf设太低会出现头盔误检设太高会漏掉小目标iou是NMS阈值多人聚集时设0.45比较稳。如果只需要报警不要每帧都判断增加一个计数窗口比如连续3帧检测到未戴头盔再触发否则单帧抖动会造成误报。验证方法也简单准备一段10分钟实拍视频逐帧统计检测框和人工标注算出漏报率。这个数值才是系统能否投入的关键mAP高并不代表现场能用。我自己在头盔检测上栽过的跟头基本都写进避坑清单了。希望这个从数据到部署的完整路径能帮到你。本文还有配套的精品资源点击获取
返回列表