尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于YOLOv5的驾驶员分神检测系统设计与PyQt部署实战

基于YOLOv5的驾驶员分神检测系统设计与PyQt部署实战 简介本资源面向智能交通、车载视觉与AI安全监测领域的开发者及高校研究者提供一套完整的DMS驾驶员状态监控分神行为检测方案聚焦抽烟、打电话、喝水、吃东西四类高危驾驶行为识别。资源包含5000余张高质量标注图像构成的数据集已按标准YOLO格式组织为train/val/test三级目录并配备data.yaml配置文件nc4names明确对应四类行为支持YOLOv5/v7/v8/v9等主流版本直接训练同时集成PyQt5可视化界面脚本与三份环境配置PDF教程覆盖模型部署与交互式检测全流程。压缩包共2000个文件以1994个txt标签文件为核心辅以3个Python主程序含界面启动与测试逻辑及3份PDF说明文档整体大小356.88MB。目前已有628人学习下载数据集结构规范、开箱即用配套资料兼顾算法训练、工程部署与实操指导显著降低DMS系统原型开发门槛。 做DMS驾驶员监控这套YOLOv5项目时我最直观的感受是检测本身不算难难的是让它在真实驾驶环境里不瞎报。这个项目我从数据集清洗、模型训练到PyQt界面封装前前后后折腾了快三个月踩的坑比想象中多得多。今天把完整的实现思路、选型原因、踩坑过程和调优心得整理出来给正在做或准备做同类DMS分神检测项目的朋友一个参考。先明确这套东西解决什么问题通过一个车载摄像头实时采集驾驶员画面用YOLOv5识别出抽烟、打电话、喝水、吃东西四类分神行为再配合一个PyQt界面做实时预览、报警和截图记录。硬件成本就是一台带摄像头的工控机或者开发板软件端是YOLOv5加PyQt数据集主要靠公开数据加自采数据混合。适合的场景包括驾驶培训考试系统、网约车安全管理、车队风险监控、汽车电子Demo演示当然也是毕设和竞赛的常客。1. 分神检测到底在检什么DMS需求拆解1.1 从事故场景说起为什么DMS盯着人而不是盯着路DMS的全称是Driver Monitoring System也就是驾驶员监控系统。和市面上那些做车道线检测、前碰撞预警的ADAS不一样DMS看的不是路而是人。它要回答一个问题驾驶员现在到底有没有在专心开车。这个项目里的四类行为——抽烟、打电话、喝水、吃东西——在交通安全研究里统称“分神行为”。人分神的瞬间反应时间会明显变长。一个很简单的逻辑当驾驶员双手离开方向盘、视线偏移、或者单手操作手机时哪怕前方出现紧急情况他也没有能力在第一时间做出正确反应。所以DMS要做的事情本质上就是把“驾驶员正在做什么”这件事从连续的视觉信息里转成离散的行为标签。这个“标签化”的过程就是这套系统的核心价值。1.2 技术选型为什么是YOLOv5而不是姿态估计或图像分类这里我只说结论行为检测有三条常见路线YOLOv5这种“目标检测行为标签”的方案在DMS场景下是性价比最高的。第一条路线是整图分类。就是把摄像头画面整张丢给一个ResNet输出“抽烟/打电话/喝水/吃东西”的类别。优点是实现极简不用标注边界框跑起来也快。缺点是它根本不告诉你在画面哪个位置发生了行为一旦画面里出现乘客、遮阳板、窗外物体分类器很容易被带偏而且出问题的时候你很难定位到底是哪里的特征判断错了。第二条路线是姿态估计加规则判定。用OpenPose或者MediaPipe先提取人脸关键点、手部关键点然后通过“手和嘴的距离”“手和耳的距离”这类几何关系去推断行为。听起来很聪明实际落地会非常痛苦姿态估计在低分辨率下对手部关键点的检测本来就脆一旦手部被方向盘遮挡关键点直接飘再加上不同人的体型差异极大规则阈值很难用一个固定值覆盖所有情况。第三条路线就是目标检测。用YOLOv5把“驾驶员的上半身”或者“手部嘴部交互区域”框出来并直接给这个框一个行为类别标签。优点很直接端到端训练不用手写规则框在什么地方一眼就能看到而且YOLOv5的推理帧率足够高在车载环境下跑得起来。那为什么是YOLOv5而不是YOLOv8、YOLOv11核心原因是生态成熟度。Ultralytics维护的YOLOv5从2020年到现在迭代了很长时间社区资料最全超参数文档清晰后端导出方案丰富遇到问题基本都能搜到答案。虽然YOLOv8的C2f结构和Anchor-Free设计在精度上有优势但这个项目的四类行为目标在画面里都算中大型目标YOLOv5s级别的模型已经足够没必要为了追新去增加调试成本。1.3 摄像头位置是隐含需求决定你后面所有工作DMS项目里最容易被新手忽略的一点是摄像头安装位置。车载环境里摄像头一般装在仪表台中央、方向盘管柱、或者内后视镜附近视角从上往下倾斜30到45度需要同时拍到驾驶员的脸部、手部、上半身。为什么这个小细节这么重要因为目标检测模型对视角分布非常敏感。如果你用网上找的公开数据集训练那些数据大多用的是正对着驾驶员的摄像头视角但你的实车摄像头装在斜上方拍出来的手部、嘴部形态和公开数据集差异非常大。你在公开数据集上练出一个看似很准的模型装到车上一测性能直接掉一截。我建议的做法是先确定摄像头最终的安装位置再按照这个视角去收集数据或者拍摄自采数据。如果项目还在原型阶段至少要在训练集里混入不同角度的数据保证模型见过的视角足够多。2. 数据决定上限DMS数据集的来源、清洗与标注2.1 公开数据集怎么选State Farm、AUCD2到底能不能直接用DMS相关的公开数据集最经典的是Kaggle上的State Farm Distracted Driver Detection竞赛数据集。它包含10个类别正常驾驶、发短信左手/右手、打电话左手/右手、操作收音机、喝水、拿后座物品、整理头发化妆、和乘客说话。数据量很足每类有几千张图画质也还行。但这个数据集有个致命问题它不是YOLO格式的目标检测数据而是整图分类数据。也就是说每张图只有一个类别标签没有边界框。要拿来做YOLOv5训练必须人工重新标注所有框工作量非常大。我当时的做法是先跑一个预训练的YOLOv5检测出驾驶员再用标注工具微调边界框能省一部分时间但依然属于重体力活。还有一个数据集是AUCD2AUC Distracted Driver Dataset它有超过17万张图像覆盖了10种驾驶行为同样是整图分类标签也需要转换和标注。公开数据集另一个问题是场景偏差。国外数据集的驾驶员体型、座椅位置、方向盘设计、车内光线都跟国内实际场景有差异。直接用了模型在实车测试时容易水土不服。所以我的结论是公开数据集可以用于预训练和验证算法流程但要真正部署必须结合自采数据混合训练。2.2 自采数据怎么录、怎么标一定要把标准定在前面自采数据的流程看起来很简单找几个人架好摄像头录他们开车时抽烟、喝水、打电话、吃东西的视频然后抽帧标注。但实际操作中有几个容易犯的错。第一动作多样性不够。很多人拍数据的时候就拍了一个标准姿势抽烟就是右手夹烟放在嘴边打电话就是手机贴耳朵。结果模型学到的全是“标准动作”一旦驾驶员用左手夹烟、电话放耳边角度偏一点、或者喝水时瓶子先停在空中再喝模型就懵了。要尽量把动作拍全左右手交替、坐着往前倾、靠着座椅后背、转头看后视镜时手上还拿着东西这些都要覆盖。第二连续帧高度相似。如果从视频里逐帧抽取相邻帧基本长得一样这些数据扔进训练集不但不增加信息量还会让模型对相似帧过拟合。正确做法是隔几帧抽一张或者按场景剪辑后随机抽帧。我当时是按视频每秒抽2到3帧抽完肉眼扫一遍去掉几乎重复的图像。第三标注框的尺度标准不统一。这一点是血泪教训。你到底是框住“整个人”还是框住“手部嘴部烟/手机/水杯”还是只框物体我最终的方案是框“驾驶员上半身区域”并且保证这个框包含手部和嘴部交互细节。理由是模型需要同时看到手和嘴的位置关系才能区分“喝水”和“吃东西”如果框得太小只看手部模型就失去了判断依据。标注时还要保持一致类别是“手在嘴边的动作”和“身体姿态”的综合标签不是单纯“物体检测”的标签。标注工具我用的labelImg直接导出YOLO格式的txt文件每行是“类别编号 中心点x 中心点y 宽度 高度”所有坐标值归一化到0到1之间。2.3 数据增强哪些能开哪些建议关YOLOv5自带的超参数文件里数据增强默认是全部打开的。但DMS场景下有几个增强参数需要特别留意。HSV色彩增强建议调低调。真实车内环境的光线变化主要来自自然光和车灯颜色偏移太夸张会让模型学到不真实的色调特征。尤其是手机屏幕反光、香烟烟雾这类细节颜色过度偏移后模型容易把注意力放到错误的纹理上。Mosaic增强可以开效果很好。它把四张图拼成一张让模型看到更多样化的背景和位置组合对提升鲁棒性有帮助。不过如果数据集本身的标注比较干净Mosaic默认的0.5到1.0概率不用调太多。水平翻转建议开。左右手行为在真实驾驶中都会出现翻转能直接让样本量翻倍而且不会引入语义错误。注意翻转后如果你后续要做手部左右侧的逻辑分析要小心标签翻转导致的手性变化但纯检测场景没有这个问题。Mixup增强看情况。它会让两张图的像素混合在一起对类别边界清晰的场景很有用但DMS里“喝水”和“吃东西”的边界本来就模糊Mixup可能进一步混淆特征。我最终把它关了。3. YOLOv5训练实战从环境安装到模型收敛3.1 环境搭建和最容易翻车的几个点YOLOv5的环境搭建本身并不复杂官方README写得清楚但我在给不同机器装环境时还是遇到过不少问题列几个典型的。Python版本建议3.8到3.10之间太新的版本有些依赖没有编译好的wheel装起来很痛苦。PyTorch的安装需要先确认CUDA版本用nvidia-smi查看驱动支持的CUDA版本再去PyTorch官网选对应的安装命令。如果只是CPU环境测试代码流程可以直接装CPU版训练再换GPU机器。克隆完代码后执行pip install -r requirements.txt。这个文件里有可能装失败的是pycocotools在Windows上经常编译失败。解决办法是直接安装pycocotools-windows这是一个第三方编译好的替代包。还有一个容易忽略的点YOLOv5对numpy和opencv-python的版本有隐式依赖。版本太新或者太旧可能在训练时报奇怪的AttributeError。如果遇到这类问题不要急着查代码先看版本号。3.2 数据集目录、data.yaml与关键超参数YOLOv5训练自定义数据集的标准目录结构是这样的datasets/dms/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml注意images和labels目录必须同级且train和val里的文件名一一对应。训练时YOLOv5会按文件名去匹配标签文件匹配不上会在日志里警告但不会中断。这个警告很容易被忽略一旦标签缺失过多模型就变成“有图无监督”状态指标会非常诡异。data.yaml的内容很直接path: datasets/dms train: images/train val: images/val nc: 4 names: [smoking, calling, drinking, eating]类别编号从0开始name的顺序必须和标注txt里的类别编号完全一致。比如txt第一行的第一个数字是1就代表calling。很多人把类别顺序改了但忘了同步标注文件模型训练的标签就全乱了。超参数这块默认的hyp.scratch-low.yaml已经足够。几个重要参数的理解lr0初始学习率默认0.01。数据量小的时候不需要调大反而要留意学习率过大导致loss震荡。mosaicMosaic增强概率默认1.0。前面提过DMS场景开着就好。warmup_epochs热身轮数默认3.0。让模型先用小学习率稳定初始化不然一开始loss容易爆。weight_decay默认0.0005防过拟合用的。训练命令长这样python train.py --data datasets/dms/data.yaml --weights yolov5s.pt --img 640 --batch 32 --epochs 150 --name dms_v1如果显卡显存不够比如只有8GB把--batch降到16--img降到512或者416模型换成yolov5n一样能训练只是精度会低一些。3.3 训练过程监控和典型问题排查训练过程中要盯的东西不多loss曲线、验证集的P和R、mAP0.5、mAP0.5:0.95。我习惯用TensorBoard训练开始后执行tensorboard --logdir runs在浏览器里看曲线。先说正常情况train loss应该稳步下降val loss在初期同步下降中后期趋于平稳。如果val loss一开始就很高而且怎么都降不下来问题大概率不在模型而在数据。我遇到过几次这种情况现象可能原因排查方法train loss正常下降val loss异常高训练集和验证集分布不一致比如数据按人分不是按帧混洗重新划分数据集确保同一人的不同画面只出现在一边mAP0.5很高mAP0.5:0.95很低框的定位质量差检查标注框是否整齐有没有大量漏标小框某类别P高R低这个类别的样本太少或者姿势变化太大增加该类别样本量尤其是不同角度的样本训练loss下降但验证集几乎为0学习率太高或者标签文件类别编号错位降学习率重训检查category id与names对应这里重点说一下“按人划分”这个坑。如果同一个人的视频被同时抽进训练集和验证集模型相当于“见过这个人”了验证集分数虚高。真实的DMS部署场景是面对一个陌生驾驶员所以我的建议是按驾驶员区分训练集和验证集也就是说训练集里的人和验证集里的人完全不重叠。这样测出来的指标才有参考价值。还有一个小技巧是类别权重。如果calling类别样本明显少于smoking可以在训练时加载类别权重或者简单粗暴地从原始视频里多抽一些calling帧。目标检测不像分类问题那么好做类别重采样但至少要保证每个类别不低于800到1000张图。4. PyQt界面把模型变成能给人用的检测工具4.1 界面布局和功能划分别把界面做成“只有一个播放器”PyQt界面不是简单地显示一个视频流就完事。实际交付给客户或者作为演示工具界面需要承载三个方面实时画面、状态反馈、记录回溯。我常用的布局是左边一大块视频显示区右边一个控制面板底部一个日志区。控制面板里有几个核心按钮打开摄像头、打开视频文件、开始检测、停止检测、退出。状态区显示当前帧率、当前检测到的行为、累计报警次数。日志区用QPlainTextEdit显示检测事件的时间戳和类别。这里有个细节模型推理结果不要在一个QLabel上直接覆盖绘制。正确做法是YOLOv5推理得到带框的帧再把整帧转成QImage显示在QLabel上。这样界面代码和检测逻辑完全解耦后续要加功能也方便。4.2 QThread多线程解决界面卡死的关键如果不做多线程PyQt界面跑YOLOv5只有一个结果卡死。因为YOLOv5推理一次大约50到100毫秒如果这个推理过程放在UI主线程里画面会像幻灯片一样一卡一卡的按钮点下去半天没反应。解决方案是用QThread。我一般开两个工作线程一个专门读视频流一个专门做推理。读帧线程拿到frame后通过信号把numpy数组发给推理线程推理线程拿到图像跑模型得到结果后把绘制好的图像通过信号传回主线程刷新UI。主线程只负责接收信号、更新QLabel不做任何耗时操作。伪代码大概是这样class VideoThread(QThread): frame_ready pyqtSignal(np.ndarray) def run(self): cap cv2.VideoCapture(0) while not self.isInterruptionRequested(): ok, frame cap.read() if ok: self.frame_ready.emit(frame) self.msleep(30)class DetectThread(QThread): result_ready pyqtSignal(np.ndarray) def run(self): while not self.isInterruptionRequested(): frame self.frame_queue.get() results self.model(frame) drawed self.draw_results(frame, results) self.result_ready.emit(drawed)pyqtSignal(np.ndarray)传numpy数组是可行的不需要额外转成QImage再传。等到主线程收到信号后再一次性转成QImage显示。这里有个性能问题信号传大数组有拷贝开销实测下来对640x640的图影响不大不用过虑。4.3 报警去抖如何让系统不“烦人”又不错漏纯单帧检测直接触发报警绝对是DMS项目的灾难。驾驶员只是摸了一下嘴系统就报“抽烟”只是拿起水杯还没喝就报“喝水”。这种误报会让使用者迅速失去对系统的信任。我用的方案是“连续N帧确认制”。具体逻辑维护一个状态字典记录每个行为类别的连续命中帧数。只有当某个类别的连续命中帧数超过阈值比如5帧才正式判定为“正在发生该行为”并触发一次报警。同样当行为消失时也需要连续若干帧比如3帧都没有检测到才将状态切回正常驾驶。这个机制带来的好处是短暂的手部动作不会触发不必要的报警而持续性的危险行为不会被漏掉。阈值的设定需要调试阈值太高真实的短促抽烟动作可能漏报阈值太低误报又压不住。我用5帧作为默认值在20到30FPS的帧率下大约对应0.2到0.25秒的判定窗口效果还可以。报警触发后我会在日志区记录一行时间戳和类别同时把当前帧截图保存到本地alarm/目录文件名用时间戳命名。这个功能在演示和事后审查时特别有用客户追问“刚才那个报警是什么情况”你可以直接把截图翻出来给他看。4.4 pyinstaller打包成exe的实操经验用pyinstaller把PyQt界面和YOLOv5模型打包成exe是很多人的痛。我踩过的坑主要有四个。第一不要上来就用--onefile。单文件模式启动时要把所有资源解压到临时目录启动非常慢而且排查问题特别困难。先用--onedir模式打包跑通了再考虑要不要转成单文件。我的项目最终就是目录模式的exe虽然是一堆文件但启动速度和稳定性都好很多。打包命令大概是这样的pyinstaller -D --windowed --name DMS main.py--windowed是去掉控制台窗口如果界面里没有专门的日志输出这个选项很干净。如果程序有报错害怕看不到可以先不加调试完成后再加。第二模型权重文件.pt要处理好路径。pyinstaller打包后程序运行目录可能和源码目录不一致直接用相对路径加载权重很容易失败。最简单可靠的方式把权重文件放在exe同级的models/目录下程序里用os.path.join(os.path.dirname(sys.executable), models, dms.pt)来定位。这里不建议把权重打进去因为权重文件可能有几百MB嵌进exe会让打包变得极慢。第三OpenCV的DLL问题很典型。打包后提示找不到opencv_videoio_ffmpeg*.dll这类的错误通常是因为OpenCV的版本和pyinstaller的收集机制不匹配。一个可行的方案是改用opencv-python-headless替代opencv-python它在无GUI环境下不会引入Qt插件冲突打包体积也更小。第四缺hidden import。PyQt5有时候需要显式声明一些模块比如PyQt5.sip。如果打包后运行报错找不到某个模块用--hidden-import把它加进去。最直接的办法是看报错信息缺什么补什么。整个打包流程我建议这样做先最小化测试——只打包一个空窗口的PyQt程序确认能跑再在这个基础上加上模型推理确认能加载权重、能推理最后再一步步加上其他功能。不要等全部写完才去打包那样遇到问题会很难定位是代码问题还是打包配置问题。5. 从能跑到能用鲁棒性、性能与部署优化5.1 摄像头安装角度、光照与画面质量对检测的直接影响训练时模型看到的是“接近正对驾驶员”的画面实车装上后如果摄像头角度偏低或者偏侧检测效果会立刻打折。这个问题没法靠调模型参数完全弥补最好的办法是在采集数据集时就模拟实际安装视角。项目里我一开始用的是普通USB摄像头装在屏幕上方后来换到了方向盘管柱位置视角变了模型的mAP掉了将近5个点。后来我重新录了一批新视角的数据混到原数据集里重训才恢复过来。光照是另一个大变量。逆光、隧道内灯光忽明忽暗、夜间行车灯光昏暗——这些场景下RGB摄像头的画面噪点多、对比度低检测性能会明显下降。目前我用的方案是在夜间环境降低检测置信度阈值因为低光照下模型的输出置信度普遍偏低阈值还是0.5的话很多真实行为会被漏掉。更专业的做法是使用带红外补光的DMS摄像头模组比如850nm或940nm红外LED补光这类模块在黑暗环境下依然能输出清晰的灰度图像对检测效果稳定性的提升非常大。画面质量方面摄像头的分辨率不是越高越好。1080p的帧率低、处理开销大720p已经够用。再配合--img 640的输入分辨率整体性价比最高。5.2 误报和漏报的典型场景摸脸、扶眼镜、玩手机调试过程中最常见的误报场景是摸脸和扶眼镜。手部在面部附近停留模型很容易把它当成“吃东西”或者“抽烟”。另一个高发误报是“玩手机”驾驶员只是拿起手机看一眼导航模型就可能判成“打电话”。对于摸脸、扶眼镜这类误报提高置信度阈值能滤掉一部分但会把真正抽烟的置信度也压下去。更好的办法是从数据层面解决在训练集里加入大量“摸脸、扶眼镜、整理头发”的负样本并给它们一个独立的类别标签比如other_action。这样模型就能看到“手在脸上但和抽烟/吃东西有区别”的样本误报率会明显下降。对于玩手机和打电话的区分本质是“手机是否放在耳边”。如果只靠检测框模型很难区分“手机拿在手里看”和“手机贴在耳朵上打电话”。一个可行的办法是加一个人脸关键点模型检测到calling类别时额外判断手部框中心点是否在人脸框上部区域如果不在就判为“观看手机”而非“打电话”。但这会增加工程量如果没有硬性要求建议在类别定义里把“看手机”也算成分神行为统一归为一个类别这样模型训练也更简单。漏报方面喝水动作非常典型。驾驶员低头喝了一口水手部离开方向盘整个过程可能只有1到2秒。如果报警去抖阈值是5帧在低帧率下可能5帧还没凑齐动作已经结束了。解决办法是提高摄像头帧率到25到30FPS并把去抖阈值下调到3帧配合行为结束后3到5秒的“持续报警”窗口来覆盖这类短促动作。5.3 推理加速从PyTorch到TensorRT和边缘设备在PC上跑YOLOv5s1080Ti显卡能做到实时。但如果要部署到便宜的工控机或者开发板需要把模型从PyTorch推理换成更轻量的引擎。最简单的一步是用FP16半精度推理。PyTorch下把模型转成halfmodel.half()在支持FP16的GPU上能获得明显提速精度损失很小。再进一步是导出ONNXpython export.py --weights runs/train/dms_v1/weights/best.pt --include onnx拿到ONNX后可以转TensorRT在NVIDIA平台上跑或者转RKNN在瑞芯微平台比如RK3588上跑。热搜词里提到的RK3568、RV1106这些芯片也都支持YOLOv5的模型转换部署。在RK3588上用RKNN的NPU推理YOLOv5s的单帧耗时能压到几十毫秒以内完全满足车载实时性要求。这里有个提醒边缘设备的内存普遍只有2到4GB模型输入分辨率建议从640降到512甚至416batch固定为1。速度提升明显mAP会有少量下降但对DMS这类大目标场景影响不大。模型轻量化方面还有一个选择从头训练一个yolov5n版本。yolov5n的参数只有yolov5s的1/3左右在边缘设备上更友好。如果精度不达标再换回yolov5s硬件方案取舍就看你的部署需求了。最后再分享一个我在项目后期学到的教训报警截图和日志的时间戳一定要用系统时间而不是模型检测的帧计数时间。当时我用帧计数作为截图文件名后期根据报警记录回看录像时对着时间轴找半天非常痛苦。改成time.strftime生成的时间戳后排查问题效率高多了。这套DMS项目能做到“能跑”不算难但能做到“替使用者省心、不误报、可追溯”才是真正把它做成一个合格产品的地方。本文还有配套的精品资源点击获取
返回列表