ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于YOLOv8的驾驶员疲劳监测系统:从检测到UI的完整实现

基于YOLOv8的驾驶员疲劳监测系统:从检测到UI的完整实现 简介这是一套面向毕业设计、课程设计与项目开发场景的疲劳驾驶图像检测完整方案基于YOLOv8实现驾驶员状态监测可识别闭眼、张嘴、睁眼、闭嘴四类状态适合具备一定Python与深度学习基础、需要快速搭建可运行检测系统的读者。资源包共约2000个文件以txt标注与说明、py训练推理脚本、md文档为主另含少量cpp、h、hpp等C推理代码压缩包约245.39MB数据规模约3000张并附标签同时提供预训练权重便于按不同检测任务微调以提升精度。训练自定义数据集时只需调整mydata.yaml再运行对应train与predict脚本即可完成训练或推理。目前已有30人学习读者可据此掌握从数据组织、模型训练到界面展示的完整流程并参考配套改进与训练说明进一步优化效果。1. 从一张疲劳驾驶罚单说起这套 YOLOv8 驾驶员监测源码到底能跑出什么前阵子帮一个做车队管理的老哥看事故复盘视频凌晨三点那段画面里司机眼皮已经连续闭合超过两秒方向盘几乎没动但车载的所谓疲劳预警一声没吭。他问我能不能自己搞一套能看眼睛、能看打哈欠、还能看脑袋低没低下去的东西别整那些只会响喇叭的花架子。这就是我拆这套 Python YOLOv8 智能驾驶员状态监测系统的起点——它不是那种只跑一张图的 demo而是把目标检测、状态判定、UI 界面串成了一条能落地的链路。这套资源的核心价值在于用 YOLOv8 做驾驶员面部与手部关键目标的检测再叠加闭眼、哈欠、低头等状态逻辑最后套一个能实时显示画面的 UI。适合谁做课程设计的学生、想快速验证车载 DMS 思路的嵌入式工程师、以及需要一套可改可调的 Python 视觉项目做二次开发的人。源码和界面都给了省掉的是从零搭框架的时间留下的是调参和适配的活。2. 拆开看结构YOLOv8 检测层与状态判定层怎么分工2.1 为什么选 YOLOv8 而不是自己搭 CNN 分类驾驶员状态监测本质上要同时解决两个问题一是人在哪、脸在哪、眼睛在哪二是眼睛闭了多久、嘴巴张多大。如果只用普通 CNN 做分类输入整张图输出疲劳/不疲劳遇到副驾驶入镜、后排乘客干扰、或者司机侧脸误判率会高得离谱。YOLOv8 在这里承担的是定位任务先把驾驶员的脸部区域、眼睛、嘴巴、手部框出来后续的状态判定只在这些框内做文章抗干扰能力完全不是一个量级。YOLOv8 相比前几代在驾驶员场景下的实际优势我体感最明显的有三点。第一是 anchor-free 解耦头小目标如眼睛、嘴巴的召回率比 YOLOv5 稳尤其是戴眼镜反光的情况下。第二是训练时 Mosaic 增强默认开着对夜间、逆光、部分遮挡的泛化帮助很大。第三是导出 ONNX 和 TensorRT 的链路成熟后面想上 RK3588 或者 Jetson 这类边缘板子不用重写推理代码。热词里有人搜rk3588部署yolov8这套源码的检测部分就是按可导出结构写的不是纯 PyTorch 死跑。2.2 状态判定层的三个核心指标与阈值检测框出来之后判定逻辑才是决定这套系统灵不灵的关键。源码里主要看三个指标指标计算方式常见阈值说明闭眼时长眼睛纵横比 EAR 连续低于阈值EAR 0.2 持续 1.5s眨眼正常持续闭合才算疲劳哈欠频率嘴巴纵横比 MAR 高于阈值MAR 0.6 持续 1.0s单次哈欠不算看时间窗口内次数低头角度头部姿态 pitch 角pitch 25° 持续 2s结合人脸关键点或检测框比例估算这里要强调一个血泪经验阈值千万别照搬论文。我见过有人直接拿 EAR 0.25 去跑结果司机正常看后视镜就被判疲劳。正确做法是先用源码里的调试模式把 EAR、MAR 实时曲线打出来看这个司机、这个摄像头角度下的基线在哪再往下压 15% 到 20% 作为触发线。源码的 UI 界面里留了参数调节入口就是干这个用的。2.3 从视频流到判定结果的完整数据流整个链路我画不出图但可以用文字说清楚摄像头或视频文件 → OpenCV 逐帧读取 → YOLOv8 推理得到人脸/眼睛/嘴巴/手部框 → 对眼睛和嘴巴区域计算 EAR/MAR → 滑动窗口统计闭眼和哈欠时长 → 头部姿态估算 → 综合判定疲劳等级 → UI 刷新显示并触发报警。每一步都有可调参数。比如滑动窗口大小源码默认是 30 帧对应 1 秒左右的视频30fps。如果你用 15fps 的低帧率摄像头这个窗口就得改成 15否则判定会延迟一倍。再比如 YOLOv8 的置信度阈值默认 0.25夜间画面噪点多的时候可以降到 0.15 提高召回但误检也会上来需要配合 NMS 的 IoU 阈值一起调。3. 把环境跑起来从 Python 安装到第一帧检测结果3.1 环境配置的版本对齐问题这套源码对版本比较敏感我踩过的坑是 ultralytics 版本和 torch 版本不匹配导致推理结果全乱。推荐一套我实测稳定的组合# 创建独立环境别用系统 Python 直接装 conda create -n dms python3.9 -y conda activate dms # 安装 PyTorchCPU 版本先用着验证逻辑 pip install torch2.0.1 torchvision0.15.2 --index-url https://download.pytorch.org/whl/cpu # 安装 ultralytics 和 UI 依赖 pip install ultralytics8.0.196 opencv-python4.8.1.78 pip install pyqt55.15.9 numpy1.24.3逻辑说明Python 3.9 是兼容性最好的版本3.11 以上有些 PyQt5 轮子还没跟上。ultralytics 锁 8.0.196 是因为再新的版本改了推理接口的返回格式源码里的解析代码会报 KeyError。torch 用 CPU 版先跑通逻辑有显卡再换 CUDA 版换的时候注意 torch 和 torchvision 版本要对应别一个 2.0 一个 0.16。参数说明--index-url指定 PyTorch 官方源国内下载慢的话换清华镜像但注意镜像有时候同步滞后找不到指定版本就换回官方源。opencv-python 用 4.8 是因为 4.9 之后 VideoCapture 在某些 USB 摄像头上会抽风读帧返回空。3.2 加载模型与推理第一帧环境好了之后先别急着开 UI用一段最小代码验证模型能不能正常出框from ultralytics import YOLO import cv2 # 加载源码自带的权重路径按实际解压位置改 model YOLO(weights/driver_state.pt) # 打开摄像头0 是默认设备外接 USB 摄像头试 1 或 2 cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while True: ret, frame cap.read() if not ret: print(读帧失败检查摄像头占用或索引) break # 推理conf 调低一点先看召回 results model(frame, conf0.2, iou0.45, verboseFalse) # 把检测框画回原图 annotated results[0].plot() cv2.imshow(DMS Test, annotated) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()逻辑说明model(frame)直接传 numpy 数组ultralytics 会自动做 letterbox 预处理。results[0].plot()返回画好框的图省得自己写绘制逻辑。verboseFalse关掉每帧的日志刷屏不然控制台没法看。参数说明conf0.2比默认 0.25 低是为了先确认模型能检出目标宁可多检也别漏检。iou0.45是 NMS 的阈值两个人脸靠得近的时候调高到 0.5 以上能减少误合并。摄像头分辨率设 640x480 是速度和精度的平衡点1080p 在 CPU 上跑 YOLOv8n 大概只有 5 到 8 帧体验很差。3.3 启动完整 UI 与参数调节验证检测没问题后启动源码里的主界面# 进入源码根目录 cd driver_monitor_system # 启动主程序具体入口文件名看源码里的 README python main.pyUI 起来之后重点看三个地方。一是视频显示区有没有卡顿如果卡把推理分辨率降到 416 或者换 YOLOv8n 权重。二是右侧的参数面板EAR 阈值、MAR 阈值、报警持续时间都在这里调调完立即生效不用重启。三是底部的状态栏会显示当前 FPS 和检测到的目标数量FPS 低于 15 的时候判定延迟会很明显需要优化。常见做法是先用一段自己录的测试视频跑别直接上摄像头。视频文件路径在 UI 里选这样能反复回放同一段疲劳片段来调阈值比对着摄像头做表情高效得多。4. 避坑与排查那些让系统看起来能跑其实没用的细节4.1 摄像头读帧返回空但程序不报错现象程序正常运行UI 也显示窗口但画面全黑或者卡在第一帧不动控制台没有异常。原因OpenCV 的 VideoCapture 在某些 USB 摄像头或虚拟摄像头上read()返回(False, None)但不抛异常如果代码里没检查ret就直接用 frame会一直处理空数据。解决每次read()后强制判断if not ret: continue或break并且在打开摄像头后加一个cap.isOpened()检查。另外 Windows 上摄像头索引可能被其他程序占用换个索引或者重启摄像头服务。4.2 白天正常夜间疯狂误报疲劳现象白天跑得好好的一到晚上或者进隧道闭眼报警频繁触发。原因夜间红外补光下眼睛区域对比度下降YOLOv8 检测框会抖动导致 EAR 计算值忽高忽低滑动窗口统计时被误判为持续闭眼。解决一是夜间把 YOLOv8 的 conf 阈值提到 0.4 以上宁可漏检也别让抖动框进来。二是在 EAR 计算前加一个中值滤波对连续 5 帧的 EAR 取中位数再判定。三是如果摄像头支持强制切到灰度模式红外下灰度比彩色稳。4.3 UI 界面卡顿导致判定延迟现象视频显示一卡一卡的报警总是慢半拍FPS 显示只有个位数。原因PyQt5 的主线程里同时做推理和界面刷新YOLOv8 推理本身就要几十毫秒再加上绘制主线程被堵死。解决把推理放到独立线程里用信号槽把结果传回 UI 线程刷新。源码里如果没做线程分离自己加一个 QThread 包住推理循环。另外 UI 刷新不用每帧都刷隔一帧刷一次视觉上没区别但能省不少时间。4.4 换自己的数据集后模型完全不收敛现象用 labelme 标了自己的数据按 YOLOv8 格式转好训练 loss 不降反升。原因最常见的是类别索引对不上。源码预训练权重是 4 类face、eye、mouth、hand你自己标的时候如果只标了 eye 和 mouth类别数变了但没改 data.yaml 里的 nc或者改了 nc 但没去掉预训练权重的分类头。解决改 data.yaml 的nc和names训练时加pretrainedFalse或者只加载 backbone 权重。另外标注框别贴着眼睛边缘画留 2 到 3 个像素的余量YOLOv8 的 letterbox 会裁边贴太紧的框容易被裁掉一半。4.5 导出 ONNX 后推理结果和 PyTorch 不一致现象PyTorch 下检测正常导出 ONNX 用 onnxruntime 跑框的位置偏移或者置信度差很多。原因导出时的输入尺寸和推理时的输入尺寸不一致或者 dynamic 轴设置有问题。YOLOv8 默认导出 640x640如果你推理时传 480x480letterbox 的缩放比例对不上。解决导出时明确指定imgsz640推理时也用 640。如果要用动态尺寸导出加dynamicTrue但推理时要做同样的预处理。另外 ONNX 的 NMS 如果没导出进去需要自己后处理别指望模型输出直接是最终框。5. 进阶调优让判定更准的几个实操技巧5.1 用 EAR 滑动窗口替代单帧判定单帧 EAR 低于阈值就报警那是玩具。真正能用的是滑动窗口统计。我一般会维护一个长度为 30 的队列每帧算出的 EAR 入队然后统计队列里低于阈值的帧数占比。占比超过 60% 才触发闭眼报警这样能过滤掉眨眼和短暂遮挡。from collections import deque class FatigueJudge: def __init__(self, ear_thresh0.2, window30, ratio0.6): self.ear_thresh ear_thresh self.window deque(maxlenwindow) self.ratio ratio def update(self, ear): # 低于阈值记 1否则记 0 self.window.append(1 if ear self.ear_thresh else 0) if len(self.window) self.window.maxlen: return False # 闭眼帧占比超过阈值才判定疲劳 return sum(self.window) / len(self.window) self.ratio逻辑说明deque固定长度自动淘汰旧数据。ratio0.6意味着 30 帧里有 18 帧闭眼才报警对应 30fps 下约 0.6 秒比单帧判定稳得多。参数说明window根据帧率调15fps 就用 15保证窗口覆盖 1 秒左右。ratio别低于 0.5否则正常眨眼也会触发。ear_thresh一定要用调试模式看基线不同人眼型差异很大。5.2 头部姿态用检测框比例估算的土办法没有人脸关键点模型的时候可以用 YOLOv8 检测到的人脸框宽高比来粗略估低头。正常平视时人脸框宽高比大概在 0.75 到 0.85低头时高度被压缩比值会升到 1.0 以上。这个方法精度不高但胜在不增加模型适合算力紧张的板子。具体做法是记录连续 10 帧的人脸框宽高比取均值超过 0.95 且持续 2 秒就判低头。注意这个方法对侧脸无效侧脸时宽高比会剧烈变化需要配合眼睛检测框是否可见来排除。5.3 模型量化与 RK3588 部署的衔接如果后面要上 RK3588 这类 NPU 板子PyTorch 权重不能直接跑需要转 RKNN。链路是 PyTorch → ONNX → RKNN。转 ONNX 的时候注意把后处理NMS留在 CPU 侧别塞进模型RKNN 对动态 shape 的支持有限。量化用 RKNN Toolkit 的混合量化眼睛和嘴巴这些小目标对量化误差敏感建议这几类保持 FP16人脸和手部可以 INT8。我一般会在 PC 上先用 ONNX Runtime 验证一遍精度确认和 PyTorch 输出一致再转 RKNN。转完在板子上跑如果发现小目标漏检严重就把输入分辨率从 640 提到 800RK3588 的 NPU 扛得住帧率掉个五六帧但召回能回来。从那以后我每次拿到新的视觉项目都强制先跑一遍单帧验证 → 视频回放调参 → 摄像头实测这三步绝不跳过中间那步直接上摄像头。这套 YOLOv8 驾驶员监测源码的价值不在代码本身多复杂而在于它把检测、判定、界面这条链路完整摆出来了你可以在上面改阈值、换模型、加逻辑省掉的是搭架子的时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表