基于YOLO26的安全带检测系统:从PyTorch训练到PyQt部署实战 📅 发布时间:2026/8/30 11:12:48 👁 浏览次数: 简介本资源是一套面向智能交通与车载视觉应用开发者的安全带检测实战方案聚焦驾驶行为规范监管场景适用于YOLO系列算法v5至v26的模型训练、部署与效果验证。压缩包共2000个文件含1976个VOC格式XML标注文件、22个Markdown说明文档及配置文件总大小293.17MB其中5055张高清图像已按train/val/test划分并提供data.yaml及YOLO格式标签开箱即用于多版本YOLO训练。资源配套完整使用教程、模型评价指标曲线图及settings.json等工程化配置显著降低部署门槛。目前已有41人学习下载适合计算机视觉初学者掌握目标检测数据集构建流程也便于研究人员快速复现安全带识别任务并拓展至疲劳驾驶、分心行为等衍生方向。1. 为什么要做安全带检测一个看起来很“小”却让人头疼的视觉任务我一开始接到这个需求时心里想的是“就检测一条带子能有多难”。真正动手做了才知道安全带检测在整个驾驶监控类项目里算得上是最容易翻车的任务之一。因为安全带在画面里占比小、形态细长、颜色和车内饰接近再加上阳光直射、夜间逆光、深色衣物遮挡等乱七八糟的情况传统视觉方案比如边缘检测几何判断基本一到真实场景就崩了。这个项目最终的形态是用YOLO26训练了一个专门识别“驾驶位安全带是否正确佩戴”的模型外面套了一层PyQt写的桌面程序支持从摄像头或视频文件实时读取画面对画面里驾驶员上半身区域做检测如果判定为“未系安全带”界面立刻给出告警提示。同时项目里带了整理好的数据集和训练完成的模型权重拿到的机器只要把依赖装好跑起来就能直接做演示或者二次开发。这个项目的价值说白了就是两件事第一用目标检测模型替代传统图像处理把一个曾经极度依赖环境和角度的小目标识别问题变成了一个可以应付复杂场景的标准化检测流程第二把模型从训练到部署的完整链路串了起来从PyTorch训练到PyQt推理到PyInstaller封装exe每一步都有能跑的代码和对应的坑。所以这篇文章适合两类人一类是想做驾驶行为监控相关项目的开发者想知道安全带检测到底该怎么落地另一类是手里有YOLO模型但是不太清楚怎么和桌面界面结合、怎么打包给别人用的人。我先把项目的整体技术栈摆出来检测框架YOLO26用的官方权重结构做了少量针对细长目标的改进开发语言Python 3.10界面框架PyQt5推理后端PyTorchCPU/GPU都兼容后续可换ONNX数据集来源公开驾驶行为数据集 自采补充样本交付物训练代码、数据处理脚本、PyQt界面源码、训练好的.pt权重、样例视频这套组合不是随便定的。后面我会逐个讲清楚选型理由和实际操作中遇到的问题。2. YOLO26为什么适合这个项目结构认知和选型复盘先说说YOLO26。很多人一听到YOLO最新版第一反应是“哦又出了一个版本精度应该更高”实际上YOLO26的核心卖点不只是精度而是它把整个训练流程变得更适合工程化调优。它吸收了之前多个版本的优点在特征提取部分继续沿用CSP结构的思路但把更深层的特征融合做得更干净。我画一下我理解的YOLO26核心结构不展开代码就说它对本项目的三个关键优势2.1 对细长小目标的特征保留能力安全带在画面里经常只占几十个像素宽度长度倒是有几百像素传统检测器容易把它当成背景纹理。YOLO26在backbone部分对高分辨率特征层的下采样次数做了更灵活的配置也就是说模型可以保留更多浅层高分辨率信息给检测头。这对安全带这种“细长条”目标非常友好。我在实验里对比过同样的数据集YOLOv8的mAP50大概在0.912左右YOLO26能跑到0.946提升主要就来自安全带这一类。2.2 动态标签分配更适配类别不平衡实际的安全带检测本质上是一个“正样本极少”的任务——多数画面里驾驶员都好好系着安全带真正违规的画面占比低。如果你拿一个类别极其不平衡的数据集去训练模型很容易“偷懒”把所有框都预测成“已系”。YOLO26的标签分配策略会根据预测结果动态调整正样本匹配相当于它会在训练过程中主动去挖掘那些难分的未系安全带样本。这一点我在训练初期体会特别明显前20个epoch的时候“未系安全带”这个类别的recall一直起不来动态分配策略介入后到第60个epoch左右就明显拉平了。2.3 训练成本和部署灵活性YOLO26的模型体量相比YOLOv8没有明显变大但收敛速度快了不少。我用一张RTX 3060跑batch size 16640分辨率大概2个小时能跑完100个epoch。而且它的推理代码和旧版YOLO一脉相承导出ONNX、TensorRT都非常顺这意味着后续如果要把模型塞进嵌入式设备比如Jetson Nano或者RK3588不需要重写推理逻辑。当然YOLO26也有它的毛病。最明显的一点是官方的一些改进模块比如说部分注意力机制在边缘设备上的加速效果不如预期量化到INT8后精度掉得比YOLOv8更明显。如果打算做嵌入式部署我的建议是先用FP16跑通再考虑要不要量化。这一点我在第6章会再展开讲。3. 数据集的构建安全带检测真正的大头工作量说句实在话模型训练反而是这个项目里最“轻松”的部分真正耗时的是数据。安全带检测的数据集不像COCO那种通用目标检测数据集直接download下来就能用它有几个特殊情况必须自己处理。3.1 数据来源划分我用到的数据大致分三块公开驾驶行为数据集比如一些开源的车内驾驶员监控数据集里面包含了驾驶员面部、手部、安全带状态的标注。这类数据质量参差不齐有的标注框给的是整个上半身有的是给安全带区域用之前必须统一。自采视频抽帧找了一段真实车内视角的视频包括白天、傍晚、夜间、逆光、戴深色衣服、系了但系错位置等场景按每3秒一帧抽出来再人工筛选。数据增强扩充对已有的图片做HSV扰动、随机遮挡、水平翻转注意安全带位置左右对称可以翻、mosaic拼接。我的最终数据集是8400张图片其中“已系安全带”5200张“未系安全带”2100张“系错位置”比如系在腋下1100张。后两类是真正的难点因为系错位置和未系的视觉差异其实很微妙。3.2 标注细节三种状态的决定标注这一步最关键的是先确定类别定义。我最初想做的是二分类——要么系了、要么没系但后来发现实际场景里经常出现“系了但是完全没起到保护作用”的情况比如安全带从腋下穿过或者系在肚子上。只用二分类模型这类样本会被模型当成“已系”导致漏报。所以我把类别扩成了三类safetybelt_worn正确佩戴safetybelt_notworn完全未系safetybelt_misplaced系错位置三个类别在后续告警策略里的权重不一样。misplaced的置信度就算到0.5我也会弹告警worn则必须到0.6以上才判定为正常。这样做的原因是漏报的代价远大于误报。标注工具我用的是LabelImg格式直接导出YOLO的txt。这里有一个坑LabelImg默认导出的框坐标是归一化的但有些旧版本会把坐标写成百分比格式如果你的训练脚本按像素坐标解析就会出问题。我建议拿到任何公开数据集之后先写个小脚本统一格式别直接拿去训练。3.3 训练集和验证集划分的讲究安全带检测还有一个容易忽略的问题同一段视频里相邻两帧的画面几乎一样如果随机划分训练集和验证集模型可能在验证集上表现虚高因为它“见过”几乎一样的画面。我一开始就是随机划分验证集mAP50跑到了0.96兴奋得不行后来换成了按视频文件划分同一个视频的所有帧只能出现在一个集合里mAP降到0.93。这才是真实水平。所以做视频类检测项目划分数据时一定要按“视频ID”分组而不是按帧。4. 模型训练全流程参数、Loss曲线和中间踩过的坑4.1 训练环境配置我的环境是Ubuntu 20.04 CUDA 11.8 cuDNN 8.6PyTorch 2.1.0显卡RTX 3060 12G如果你用的是Windows环境配置也差不多但要注意YOLO26的一部分CUDA算子需要编译Windows下VS的C生成工具必须装好否则会在pip install的时候直接报错。这个坑我帮朋友排过两次都是VS没装全。我用的是conda创建虚拟环境Python版本3.10。这里提醒一下不要用Python 3.12有些旧版的PyTorch和torchvision不支持编译会很痛苦。4.2 训练参数选择超参数我直接给出最终能用的版本不一定最优但稳定model: yolov26s.yaml data: safetybelt.yaml epochs: 100 batch: 16 imgsz: 640 optimizer: AdamW lr0: 0.001 lrf: 0.01 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3 mosaic: 1.0几个要解释的点为什么用AdamW而不用SGD安全带这个任务的类别差异不大特征也偏细节AdamW在收敛速度上的优势更明显。SGD也不是不行但需要更多epoch才能达到同等精度。batch size 16在12G显存上刚好卡住如果你显存不够建议降到8同时把imgsz从640降到512先跑通流程再提分辨率。mosaic增强我保留了但把它从默认的1.0调成了和随机仿射一起用。安全带是细长物体mosaic拼接时如果目标被切到边缘标注框容易出问题所以我加了一个限制被截断超过50%的目标直接丢弃。4.3 训练过程中的关键信号训练到第20个epoch左右我发现一个问题训练集loss在降但验证集的box_loss在震荡。典型的过拟合前兆。当时我怀疑是数据不够但后来排查发现是标注数据里有几十张图的安全带框标注得太大了——框的一半落在了座椅上。这类脏标注对模型的干扰比想象中大得多。把脏样本挑出来重新标注之后验证loss立刻平滑了。挑脏标注有一个省力的办法训练完第一个模型后用模型去预测训练集把confidence高但和标签的IoU低于0.3的样本全部导出检查。这些大概率是错标或者漏标。我的最终训练结果类别PrecisionRecallmAP50mAP50-95safetybelt_worn0.9530.9470.9780.833safetybelt_notworn0.9140.8760.9310.742safetybelt_misplaced0.8820.8240.9010.695整体mAP50-95在0.75左右够用。misplaced这个类别天然难因为它的视觉特征太依赖上下文——同样一条带子的走向有人系对了有人系错了差异可能只有十几度角度。后续如果想继续提升可以从两个方向走一是专门针对misplaced收集更多数据二是把检测头改成旋转目标检测的思路因为安全带本质是一个有朝向的细长矩形水平框的信息利用率不高。这个改进目前还在试。4.4 Confusion Matrix分析训练完之后一定要看confusion matrix。我这次发现的主要问题是notworn被误判成worn的数量不少但真正影响体验的是misplaced被误判成worn。这会直接导致系统对“系错位置”无动于衷。解决办法我前面说了降低misplaced的告警阈值同时在后处理逻辑里对worn类别增加了置信度要求。5. PyQt界面开发从模型到可视化告警的工程细节模型训好了不做成界面就对不起前面做的工作。PyQt这部分看起来是“锦上添花”但真正做进去会发现它承担了一个关键职责把模型推理和用户交互解耦让不懂算法的人也能直接使用这个系统。5.1 界面模块划分我的界面结构分成三块视频输入区支持本地视频文件和USB摄像头实时流。检测结果展示区显示原始画面、检测框、类别标签、置信度。告警区记录未系安全带的截图和发生时间支持手动导出。这三块在PyQt里对应三个QWidget用QSplitter做布局底部的QListWidget显示历史告警记录。整体结构不复杂但写起来要注意的东西不少。5.2 多线程处理千万不能在UI线程里跑模型这是我第一次用PyQt做视觉应用时踩过最大的坑。一开始我图省事直接在QTimer的timeout回调里调用model.predict()结果画面卡得没法看拖拽窗口都费劲。原因很简单模型推理是CPU/GPU密集操作会阻塞Qt的事件循环整个界面就假死了。正确的做法是用QThread 信号槽。工作线程负责从VideoCapture读帧、跑模型推理、把结果打包成QImage发射信号主线程只负责接收信号并更新UI。这里有一个细节QImage的构造一定要拷贝数据因为OpenCV的Mat指向的内部buffer可能会被下一帧覆盖如果你直接传Mat的data指针构造QImage显示出来的画面就是花屏或闪烁的。我的推理线程核心逻辑大概是这样的class DetectThread(QThread): update_frame pyqtSignal(QImage, list) def run(self): cap cv2.VideoCapture(self.video_path) while not self.isInterruptionRequested(): ret, frame cap.read() if not ret: break results self.model(frame, verboseFalse) annotated results[0].plot() rgb cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape bytes_per_line ch * w qimg QImage(rgb.data, w, h, bytes_per_line, QImage.Format_RGB888).copy() self.update_frame.emit(qimg, results) if cv2.waitKey(1) 0xFF ord(q): break那个.copy()是关键不加就是灵异花屏。5.3 告警策略的实现有了检测结果怎么决定要不要告警我这里的逻辑并不复杂设定一个兴趣区域ROI只检测画面里驾驶员上半身那块区域通常是画面的左下四分之一到中间。对每一帧统计该ROI内的所有检测框取置信度最高的那个类别作为当前帧状态。如果连续5帧都判定为未系或系错才触发告警截图。告警后进入30秒静默期防止同一段违规被反复弹窗刷屏。连续5帧这个设计很关键。直接单帧判定会导致偶尔的误检变成告警太烦人。用“连续多帧确认”可以滤掉大部分偶发噪声代价是响应延迟一秒钟左右在驾驶监控场景下完全可接受。5.4 PyQt里的模型加载优化模型加载也有讲究。如果你用PyTorch直接torch.load(best.pt)每次启动大概要3~5秒这对一个桌面工具来说有点慢但能忍。但如果你用的是CPU推理而且机器性能一般我建议在初始化时把模型转换成半精度FP16或者导出ONNX再加载。ONNX在CPU上的推理速度能快一倍左右。不过ONNX的有一些问题动态尺寸支持不如PyTorch原生方便如果你需要在运行过程中切换不同分辨率输入ONNX会重新做graph优化反而更慢。所以我的方案是默认用PyTorch原生推理同时写了一个导出脚本给需要部署到低配机器上的用户做ONNX转换。6. 模型部署与打包从Python脚本到独立exe的实战记录开发完界面之后一个绕不过去的需求出现了——你不能让用户装一个Python环境再跑你的代码吧尤其是驾驶安全监控这个场景使用者可能是车队管理员或者安全负责人他们只想要一个双击就能用的工具。所以封装exe是必须的。6.1 PyInstaller打包基础流程我用的打包工具是PyInstaller命令很简洁pyinstaller -D -w main.py --name SafetyBeltDetector --hidden-import PyQt5.sip-D 生成的是文件夹模式不是单个exe。虽然单文件模式-F更干净但启动的时候需要把所有依赖解压到临时目录启动速度慢3倍以上而且容易被杀毒软件误报。我后来果断选择了文件夹模式用Inno Setup再封装成安装包体验差别不大但启动速度和稳定性好很多。打包过程中那几个经典的坑我逐一碰上过OpenCV的DLL找不到。PyInstaller对cv2的支持不算完美有时候需要手动把opencv的bin目录加进去。PyQt5的插件目录被漏掉。具体表现是打包出来的exe一运行就报“could not find or load the Qt platform plugin windows”这个几乎100%会遇到。解决办法是在main.py里设置环境变量import os if hasattr(sys, _MEIPASS): os.environ[QT_QPA_PLATFORM_PLUGIN_PATH] os.path.join(sys._MEIPASS, PyQt5, Qt, plugins, platforms)模型权重文件路径问题。打包后sys._MEIPASS和源码目录的路径不一样如果用相对路径加载best.pt会报FileNotFoundError。正确做法是把模型文件放到资源目录用resource_path函数转换。6.2 推理性能优化实测数据我针对“1080P视频CPU推理”这个场景做了一组性能对比方案推理耗时(ms/帧)备注PyTorch FP32 CPU78基线PyTorch FP16 CPU67提升约15%ONNX FP32 CPU58提升约26%ONNX FP16 CPU52有轻微精度损失TensorRT FP16 GPU9需NVIDIA显卡如果你面向的是普通Windows机器建议直接上ONNX FP16如果用户有NVIDIA显卡TensorRT是质的飞跃。不过TensorRT的部署复杂度会上一个台阶而且要针对具体显卡重新构建engine不适合做通用分发。我目前的分发版本是ONNX FP16同时保留了PyTorch GPU选项。6.3 模型量化的小提醒热搜词里有人问“yolo26量化”我顺带说一句。YOLO26直接转INT8量化精度下降比YOLOv8明显尤其是在细长小目标上的表现。如果你非要做INT8建议量化后单独评估mAP50-95不要只看mAP50。我实测下来INT8的mAP50-95降了大概0.06在这种安全告警场景里属于不可接受所以最终没有用INT8。7. 驾驶安全监控场景中常见的误检与处理策略模型和界面都跑通了不等于项目就结束了。真实场景里你会遇到很多训练时根本想象不到的干扰这里分享一下我实际碰到过的几类误检案例和处理思路。7.1 衣物纹理和图案干扰深色条纹衬衫特别是条纹方向和安全带走向平行的最容易触发误检。模型会把衣服的纹理当成安全带结构。这个问题的根源是模型学到的是“斜向条状纹理”而不是“安全带的空间几何关系”。我的处理办法有两个方向增加负样本专门收集驾驶员穿条纹、格子衫的画面标注为空背景让模型学会区分。后处理限制结合座位位置把检测框限定在驾驶位上半身的区域衣物纹理就算被识别出来也不在告警逻辑的触发范围内。后者对于界面层面更好做因为你不改模型只改规则。7.2 逆光与夜间场景夜间行车时车内光线不足安全带本身的可见度大幅度降低。我的数据集里夜间样本只占不到15%导致夜间recall明显偏低。后来补充了一批夜间IR摄像头的训练样本同时做了亮度抖动的数据增强夜间的误报率才下来一些。这里提醒一句如果最终部署用的是红外摄像头训练数据里一定要有红外图像不能只用普通RGB图像。两者在纹理特征上差异很大。7.3 摄像头安装角度差异不同的车摄像头的安装高度和角度差别很大。有的装在挡风玻璃上方拍的是俯视角度有的装在仪表盘拍的是平视角度。同一个模型在不同角度下表现会差很多。我最终用了一个简单的办法在界面中加入一个“画面校准”步骤让用户手动框选驾驶位区域。区域框选结果会作为ROI传入告警逻辑。这样模型不需要重新训练只是缩小检测范围就能兼容大部分安装角度。8. 项目交付之后的事一个更现实的版本演进思路目前这套安全带检测系统已经能稳定运行但你要说它完美那肯定没有。我在收尾阶段整理了三个后续版本明确要做的方向也分享给想在这个项目基础上继续拓展的人。第一是多路摄像头支持。当前版本只支持单路视频流但一辆营运车辆至少需要看主驾和副驾甚至还有后排。多路推理可以采用“共享模型实例 独立视频流线程”的方式没必要每个摄像头各加载一个模型显存和内存都扛不住。第二是和司机的互动能力。目前系统只能“检测告警”但实际场景里最好能在检测到未系安全带后通过语音播报提醒司机。PyQt里接入一个简单的语音合成模块比如pyttsx3很容易但要注意告警频率避免噪音污染。一次违规只播报两次是我目前觉得比较合理的策略。第三是把系统往嵌入式设备迁移。热搜词里有“yolov8 训练好的模型怎么部署到嵌入式设备”YOLO26面临的部署问题完全一样。我的规划是导出ONNX后用RKNN-Toolkit转成Rockchip平台的格式在RK3588上跑。不过前面也说过了INT8量化对安全带这类小目标不友好需要小心评估。如果性能确实不够另一个低成本方案是在边缘设备上做目标检测的“预筛选”先用轻量模型检测“是否有人”再在有人且画面清晰时传一帧回服务器做精细判断。这个方案对带宽需求也很低适合车队多个车辆统一的远程监管平台。这些方向不是说一次都要做完而是你在做类似项目时心里要清楚“当前版本解决了什么、哪些东西是留给下一版的”。从我自己的体会来说安全带检测这个项目最大的收获不是“跑通了一个YOLO模型”而是养成了“从标注到部署再到用户反馈”的完整闭环思维。模型只是链条里的一环真正让用户觉得“好用”的往往是数据质量、告警策略、打包部署这些看起来不起眼的细节。希望这篇内容能帮你少走一些弯路。本文还有配套的精品资源点击获取