ARTICLE DETAIL

资讯详情

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

疲劳驾驶检测系统实战:从人脸关键点到EAR/PERCLOS的完整工程链路

疲劳驾驶检测系统实战:从人脸关键点到EAR/PERCLOS的完整工程链路 简介一个完整的疲劳驾驶检测系统设计方案面向单片机课程设计与嵌入式开发学习者。方案基于STM32微控制器融合摄像头图像采集、面部特征识别、机器学习疲劳判定及声光报警覆盖原理讲解、硬件连接、软件编码和实际测试适合需要系统化课设参考的读者。 压缩包内共217个文件以程序源码、头文件、编译中间文件与Keil工程配置为主并包含原理图、硬件清单、串口输出txt调试记录等可支撑从电路设计到程序烧录的完整流程。整个资源包仅6.21MB轻量易获取。已有2207人浏览学习。 资料中提供了图像预处理、眼睛闭合程度提取等关键代码以及SVM、神经网络等算法应用的工程实现。通过研读源码与工程结构可以快速掌握嵌入式视觉检测系统的设计思路提升硬件选型、代码调试与系统集成能力是完成课程设计或深入理解疲劳驾驶检测技术的高价值参考。1. 一份zip装下的不只是代码更是整套工程思维先说结论一份真正能叫“全套”的疲劳驾驶检测资料绝不只是把几个Python文件压缩到一起。我拆过很多网上流传的资料包大部分要么是给论文复现用的半成品要么就是把开源仓库down下来改个名。真正值钱的是那套从数据到特征、从模型到决策的完整链路。这套资料打开之后会看到几个固定模块标注好的疲劳驾驶数据集、人脸关键点检测模型、眼睛与嘴部状态特征提取代码、头部姿态估计脚本、多特征融合判疲劳的决策逻辑以及一整套可在本地摄像头或车载录像上跑通的demo。围绕这些模块车端能做的事情基本被覆盖全了检测驾驶员是否频繁闭眼、打哈欠、头部低垂、视线偏移并输出对应的疲劳等级和告警信号。它解决的痛点很明显。如果从零开始做疲劳驾驶检测你需要自己啃论文找PERCLOS定义自己标数据自己挑backbone自己处理光照变化、眼镜遮挡、夜间红外这些现实问题。有了这份资料相当于别人把最容易卡住的前半程跑通了你拿到的是一张带路标的地图。适合谁正在做ADAS感知、车内DMS功能开发的工程师还有那些毕业论文选了这个方向、需要快速出demo的学生。前者用它做对标和方案选型后者拿它做baseline再往上加创新点。我自己的习惯是拿到这种包先不看代码先把目录结构读透。一个结构混乱的资料包后面一定会让你在找文件和改接口上浪费大量时间。下面是我整理这套资料时坚持的目录结构可以直接当模板用fatigue_detection_full/ ├── dataset/ │ ├── YawDD/ │ ├── NTHU-DDD/ │ └── self_collected/ ├── models/ │ ├── shape_predictor_68_face_landmarks.dat │ └── face_detector.onnx ├── src/ │ ├── face_engine.py │ ├── features/ │ │ ├── eye_aspect_ratio.py │ │ ├── mouth_aspect_ratio.py │ │ └── head_pose.py │ ├── fusion/ │ │ ├── rule_engine.py │ │ └── fatigue_state.py │ └── alert/ │ └── alarm_handler.py ├── configs/ │ └── config.yaml ├── demos/ │ ├── realtime_cam.py │ └── video_offline.py └── docs/ ├── 数据标注规范.md └── 阈值标定说明.md为什么要这样分dataset 和 models 不动src 按特征提取、融合判断、告警三块解耦这样后期换算法、换告警方式都不需要动整条链路。demos 单独放方便验证单个场景。docs 里专门放阈值标定说明这部分最容易被忽略但它恰恰是后面所有调试工作的依据。2. 疲劳判定背后的原理别急着上深度学习先算脸上这几个数很多人一听到疲劳检测第一反应就是“堆模型”。实际上工业界跑得最稳的方案反而不是端到端深度学习输出“疲劳/清醒”二分类而是先做人脸关键点检测再手工设计几何特征。这套资料的核心思路也在这里用一个轻量的人脸关键点模型拿到眼睛、嘴巴、头部姿态的关键坐标然后用规则去判断疲劳状态。这样做的原因很实在单纯端到端分类模型需要大量疲劳样本而疲劳状态主观性又强边界很难划清。相比之下眼睛闭合时间长短、嘴巴张合频率、点头角度这些中间量不仅可解释而且容易调到能用的精度。车规产品尤其看重可解释性出事故后要能追溯“当时为什么判定疲劳”规则系统在这点上比黑盒模型有优势。2.1 EAR眼睛纵横比到底怎么算疲劳检测里最经典的几何特征就是EAR全称Eye Aspect Ratio。它的原理是用人脸68个关键点里表示左眼和右眼的6个坐标点计算一个与图片尺度无关的比值。假设左眼为第36到41个点右眼为第42到47个点EAR定义为EAR (|P2 - P6| |P3 - P5|) / (2 * |P1 - P4|)P1是内眼角P4是外眼角P2、P3是上眼皮的两个点P5、P6是下眼皮对应的两个点。睁眼时这个值大约在0.25到0.35之间闭眼时会快速掉到0.2以下。实际工程里我不会只算一帧而是对连续几帧取平均避免眨眼瞬间误判成闭眼。最早Soukupová和Čech提出用EAR做眨眼检测原论文里给了一个经验阈值0.2。但我建议拿到资料后先不要直接用0.2而是用人脸正对摄像头的50帧正常睁眼、闭眼视频自己统计一下上下眼睑距离的分布。不同分辨率、不同摄像头安装角度下0.2这个值不一定适用。我在车机上遇到过一种情况驾驶员座椅调得太靠后人脸在画面里偏小关键点抖动导致EAR整体被压低一截这时候再死守0.2就会疯狂误报。2.2 MAR和打哈欠判定打哈欠检测用同样思路换成嘴部纵横比简称MAR。取嘴部外轮廓的6个关键点算式和EAR几乎一样MAR (|Q2 - Q6| |Q3 - Q5|) / (2 * |Q1 - Q4|)这里的Q1到Q4分别对应右嘴角、左嘴角、上嘴唇中点和下嘴唇中点。平时闭嘴状态下MAR一般在0.2以下打哈欠时会明显超过0.4甚至0.5。但因为说话、吃东西也会让嘴张开所以单帧张嘴不能算打哈欠。实操中我一般要求MAR连续高于0.45并至少持续1.5秒才开始积累一次哈欠事件。有个细节容易被忽略打哈欠往往伴随着深吸气鼻尖和下巴的3D角度会有细微变化。如果不想让喝水、吃零食这种动作频繁触发可以把嘴部开合和头部后仰的幅度做一个联合判断。这也是资料里把嘴部和头部特征放在一起融合的原因。2.3 头部姿态用solvePnP解决头部姿态估计的核心是把人脸二维关键点和标准三维人脸模型做对应然后求解旋转矩阵。OpenCV里的solvePnP就是干这件事的。我们需要一个通用3D人脸模型坐标比如鼻尖、下巴、左眼外角、右眼外角、嘴角等位置的三维坐标然后把dlib或MediaPipe输出的2D点传进去就能得到pitch、yaw、roll三个角度。疲劳状态下最明显的头部姿态是点头也就是pitch角持续向下偏移。我在实车标定中发现正常驾驶时pitch角在人脸基本朝前的范围内波动超出某个角度阈值并持续几秒基本就是司机在打瞌睡了。当然也有司机习惯性低头看仪表盘这种场景要配合车速、方向盘转角一起判断纯视觉会有不少难缠的case。3. 实操落地从数据集清洗到模型封装一条能跑通的链路资料里如果只是理论分析那不值钱。真正考验人的是在真实机器上把demo跑起来。下面这条链路是我基于这套资料整理出的推荐流程每一步都有明确的输入输出。3.1 数据准备与样本平衡第一步是确认数据集能不能用。YawDD是装在车内后视镜下方拍摄的公开数据集包含不同人种、不同光照条件最常见NTHU-DDD则是台湾清华大学做的驾驶员分心数据集动作种类更多但有些样本的标注粒度比较粗。如果资料里没有原始视频只有裁剪好的人脸图要特别注意类别是否均衡。疲劳样本天然是长尾分布清醒帧占了绝大多数闭眼、打哈欠、点头的样本占比可能不到5%。这种情况我一般会做两件事。第一对少数类做帧级过采样把闭眼、打哈欠片段重复参与训练或标定。第二对清醒帧做随机下采样不让它把特征均值拉偏。还有个更省事的办法直接不训练分类模型而是用关键点特征建模这样样本均衡问题会轻很多这也是这套资料最讨巧的地方。3.2 特征提取与阈值标定特征提取的代码结构很简单。每一帧图像先做人脸检测再用关键点模型输出68个点然后分别计算EAR、MAR和头部角度。关键是要把这些特征做成时间序列因为疲劳本身是时序事件不是瞬间状态。在工程上我通常维护一个长度为30的环形缓冲区按帧率25fps算刚好覆盖1.2秒。每次新特征进入缓冲区就计算这段时间内的闭眼比例也就是PERCLOS指标。PERCLOS的定义是单位时间内眼睛闭合程度超过某一阈值的时间占比业内常用的判定标准是P80即眼睛闭合超过80%的时间比例。当PERCLOS连续多个时间窗口都超过0.4就认为进入疲劳状态。这个阈值同样需要标定不能拍脑袋。3.3 多特征融合与告警逻辑单靠EAR容易误报单靠MAR又扛不住说话动作。所以要把闭眼时长、哈欠频率、头部点头幅度三项特征做一个加权投票。资料里用了一个很简单的规则引擎短时间内EAR低占比超过40%记1分哈欠检测累计超过2次记1分pitch角低头持续超过3秒记1分。总分大于等于2才输出初级疲劳告警持续一段时间的初级告警则会升级成强告警触发声音或座椅振动。这个逻辑的巧妙之处在于单项误判很难触发告警因为三个信号同时误判的概率很低。而一旦真的疲劳这三项会在时间上有联动闭眼频次上来以后哈欠和点头往往也会跟着出现所以加权投票不会错过真实疲劳状态。4. 真实场景里最容易翻车的五个坑跑demo和上实车是两码事。demo在办公室跑得再顺拿去做车载测试一样会翻车。下面这五个问题几乎每个人都会遇到。问题现象排查方向逆光或隧道口强烈光照人脸检测框跳动EAR明显失真换带宽动态的车载摄像头前置自动曝光策略必要时加红外补光戴眼镜/墨镜关键点落在镜框上眼睛闭合特征失效优先用红外摄像头或改用人眼关键点的相对位置而不是绝对距离司机脸偏小关键点抖动导致特征毛刺限制关键点检测的最小人脸尺寸或者把检测框放大后再送关键点模型座姿变化大头部姿态角度漂移误报率高初始化时做人脸居中位置标定增加角度偏移的动态基线算力不足帧率低于15fps疲劳检测滞后严重量化模型到INT8关键点模型裁剪人脸检测改成每5帧做一次tracking戴眼镜这件事很多新人最容易踩。传统RGB摄像头在强反光下眼睛那6个关键点经常飞掉。解决方向有两个一个是改用940nm红外摄像头配合主动红外补光墨镜在红外下几乎是透明的另一个是算法层面做关键点置信度判断如果眼睛区域被镜框覆盖太多就降低EAR的权重更多依赖哈欠和头部姿态。另外阈值不能全局固定建议根据人脸的检测框大小和质量动态缩放尤其是后装设备摄像头安装位置五花八门固定阈值肯定吃力。还有一个不起眼但很致命的坑时间戳。特征提取是一帧一帧算的但告警决策是累积事件如果中间帧率波动拿帧数当时间用会严重不准。正确做法是记录每帧的系统时间戳PERCLOS和哈欠持续时间都按时间戳计算而不是数帧数。我在资料里特意改掉了用frame_count做计时的写法这一点建议大家都检查一下。5. 如何把demo变成能上车的产品资料里的demo能跑但离产品还差好几步。首先是模型优化。如果在Jetson Nano或者RK3588上跑原来用dlib的68点模型在CPU上基本只有几帧必须换成更轻的方案。MediaPipe Face Mesh在移动端优化得不错但输出的是468个点坐标定义和dlib不一样做EAR计算时选点的逻辑要重新映射。或者直接用ONNX导出的MobileNetV3关键点模型量化成INT8在RK3588上能做到实时。其次是摄像头选型。车规级DMS摄像头一般要求具备宽动态至少120dB分辨率在720p到1080p之间就够用不需要太大大了纯粹浪费算力。如果做成夜视方案还要加上红外LED补光波长940nm比850nm更隐蔽不会在夜间产生可见红点影响驾驶员。第三是告警方式。疲劳告警不能只是屏幕上弹个框车端用户低头看屏幕本身就有安全风险。常见做法是分级告警初级告警用短促提示音中级告警用方向盘振动高级告警才介入语音提示。我在实际项目里还接到过客户需求要求告警声音可以区分“前方有障碍”和“驾驶员疲劳”避免语音提示反而让司机分心。另外别忘了系统鲁棒性测试。把摄像头对准一个假人脸跑几百小时或者用仿真场景注入极端光照能提前暴露很多边界问题。产品化阶段还有一个容易忽略的点告警策略要能配置不同车型、不同客户对疲劳等级的定义不一样最好把阈值和策略放到配置中心而不是写死在代码里。6. 这套资料后续还能怎么扩展疲劳检测做完之后如果还想往上加功能空间其实很大。最自然的方向是驾驶员分心检测把打电话、看手机、低头拿东西这些行为都纳入进来。现有的人脸关键点已经能提供头部位姿只要再加上手部检测和视线估计就能实现一套基础的DMS功能。视线方向检测是另一个高价值模块。通过眼球的虹膜位置和头部姿态可以估计驾驶员的注视区域。这个在后装市场上需求很旺可以用来做防疲劳、防走神也能做个性化的交互提醒。不过视线估计的精度受制于摄像头安装位置普通后视镜位置的摄像头只能做到区域级判断达不到像素级注视追踪。如果算力允许还可以把生理信号相关的方案加进来比如基于视频的心率估计或者用方向盘转角传感器、车道偏离数据做多模态融合。这些信息单独看不那么准但组合在一起疲劳判断的置信度会明显提高。从我自己的体会来说做这类项目最怕的不是算法不行而是拿到资料后直接跑demo跑通了就觉得自己会了。真正有价值的部分是理解每一个阈值为什么这么定、哪些参数在什么条件下会失效、如何在算力和精度之间做取舍。资料包只是入场券把这些东西消化成自己的判断力才算是真的把项目做完了。如果你正准备开始一个疲劳驾驶检测项目希望这篇拆解能让你少走几个弯路。本文还有配套的精品资源点击获取
返回列表