
简介这份资源面向计算机视觉学习者、交通安全方向研究者及需要实战项目的开发者提供一套基于YOLOv8与面部特征检测的驾驶员疲劳瞌睡检测完整方案可用于长途与夜间驾驶场景下的实时疲劳监控。压缩包共16个文件约24.81MB包含8个Python脚本、2个模型权重文件、2张示意图、1个音频文件及README、YAML、XML等配置说明覆盖数据预处理、模型训练、推理引擎、声音提醒与界面管理等模块。项目围绕目标检测定位面部区域再通过眼睛开闭状态与眨眼频率判断疲劳程度源码结构清晰便于理解YOLOv8在实时检测中的落地流程。目前已有616人学习下载适合希望掌握目标检测与面部特征融合应用、并在此基础上二次开发或改进疲劳检测算法的读者参考。1. 疲劳驾驶检测这套源码到底能不能直接跑起来高速上连续开三小时眼皮开始打架的那一瞬间方向盘偏个几度就是事故。疲劳驾驶检测这个方向之所以年年有人做核心就一句话用摄像头判断驾驶员是不是快睡着了然后报警。这份资源给的是基于 YOLOv8 加面部特征检测的完整项目源码不是那种只丢一个模型权重的半成品而是把目标检测和面部关键点两套逻辑串起来的实战包。它解决的是「从零搭一套能演示、能改、能写进毕设或产品原型的疲劳检测流程」这件事。适合三类人一是做毕业设计需要完整可跑代码的学生二是想快速验证疲劳检测可行性的算法工程师三是手里有 RK3588、Orin 这类边缘板子、想把模型往端侧搬的嵌入式开发者。不适合只想调个 API 就完事的人因为这套东西的价值在于你能拆开每一层看它怎么算的。2. YOLOv8 与面部特征检测的分工为什么不是单模型硬扛2.1 两阶段检测的选型逻辑很多人第一反应是训一个模型直接输出「疲劳/清醒」二分类。我试过翻车概率极高。原因很简单疲劳是一个时序累积状态单帧图像里「闭眼」和「眨眼」长得几乎一样模型根本分不清。这套源码的思路是拆成两阶段——YOLOv8 先负责把人脸框出来再在裁剪出的人脸区域上做面部特征检测拿到眼睛、嘴巴的关键点或开合状态最后用连续多帧的状态做疲劳判定。这个分工的好处是每一层都可解释、可单独替换。YOLOv8 换成 yolov8n 还是 yolov8s只影响检测速度和精度面部特征那层换成 MediaPipe 还是自己训的关键点模型也只影响特征质量。整条链路里YOLOv8 承担的是「定位」面部特征承担的是「读数」疲劳判定承担的是「下结论」。三者解耦调试的时候能快速定位是哪一层出了问题。从工程角度看YOLOv8 这一层用现成的预训练权重就能有不错的人脸检测效果不一定非要自己从头训。常见做法是先用 COCO 或 WIDER FACE 上预训练好的权重跑通再根据你的场景比如夜间红外、戴眼镜、侧脸决定要不要微调。这一点对新手很友好不用一上来就被数据集标注卡住。2.2 环境搭建CPU 版本先跑通再上 GPU热词里「ubuntu20.04 搭建 yolov8 环境 cpu 版本」出现频率很高说明很多人卡在环境这一步。我的建议是先用 CPU 版本把整条链路跑通确认代码逻辑没问题再换 GPU 加速。下面是我一般会用的环境配置流程。# 创建独立环境避免和系统 Python 打架 conda create -n fatigue python3.9 -y conda activate fatigue # 安装 PyTorchCPU 版本先跑通逻辑 # 如果你有 GPU去官网查对应 CUDA 版本的安装命令替换这一行 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 安装 ultralyticsYOLOv8 的官方库 pip install ultralytics # 面部特征检测常用依赖按项目实际 import 补 pip install opencv-python numpy scipy这段命令的逻辑是先隔离环境再装推理框架最后补视觉处理库。参数上唯一要注意的是 PyTorch 版本和 CUDA 的对应关系CPU 版本用上面的 index-url 就行GPU 版本一定要去 PyTorch 官网复制对应命令别自己猜版本号这是血泪经验。装完之后跑一句yolo checks能打印出环境信息就说明 YOLOv8 这层通了。2.3 用预训练权重验证 YOLOv8 这一层环境通了之后别急着上疲劳逻辑先确认 YOLOv8 能正常检测人脸。下面这段代码是最小验证单元。from ultralytics import YOLO import cv2 # 加载预训练权重n 是最小模型速度快适合先验证 model YOLO(yolov8n.pt) # 读一张驾驶员图片换成你自己的测试图路径 img cv2.imread(driver_test.jpg) # conf 是置信度阈值0.5 是常用起点 # classes 可以限定只检测人COCO 里人的类别 id 是 0 results model(img, conf0.5, classes[0]) # 把检测框画出来看一眼 annotated results[0].plot() cv2.imwrite(detected.jpg, annotated) print(检测到目标数量:, len(results[0].boxes))逻辑说明YOLO(yolov8n.pt)会自动下载预训练权重第一次运行需要联网。conf0.5控制的是「多确定才算检测到」调低会检出更多但误检增加调高则相反。classes[0]是只保留人类别减少无关框干扰。跑完看detected.jpg如果人脸被框住了说明检测层没问题。如果框歪了或者漏检先别改代码换几张不同光照的图试试判断是模型泛化问题还是你的图太特殊。3. 面部特征提取与疲劳判定的落地细节3.1 从人脸框到眼睛嘴巴状态YOLOv8 给出人脸框之后下一步是在框内做面部特征检测。这一步的实现方式取决于源码里用的是哪种方案常见的有三种MediaPipe FaceMesh 直接给 468 个关键点、Dlib 的 68 点模型、或者自己训一个关键点回归网络。不管哪种最终要拿到的是眼睛纵横比和嘴巴纵横比这两个量。眼睛纵横比的计算逻辑是眼睛上下关键点距离除以左右关键点距离。睁眼时这个比值大闭眼时趋近于零。嘴巴纵横比同理打哈欠时比值会明显升高。下面是一个通用的计算函数你可以根据源码里实际的关键点索引调整。import numpy as np def eye_aspect_ratio(eye_points): # eye_points 是 6 个点的坐标顺序为 [左角, 上左, 上右, 右角, 下右, 下左] # 垂直距离上下两组点的欧氏距离 vertical_1 np.linalg.norm(eye_points[1] - eye_points[5]) vertical_2 np.linalg.norm(eye_points[2] - eye_points[4]) # 水平距离左右眼角 horizontal np.linalg.norm(eye_points[0] - eye_points[3]) # 加 1e-6 防止除零 ear (vertical_1 vertical_2) / (2.0 * horizontal 1e-6) return ear def mouth_aspect_ratio(mouth_points): # 嘴巴用上下内唇距离除以左右嘴角距离 vertical np.linalg.norm(mouth_points[0] - mouth_points[1]) horizontal np.linalg.norm(mouth_points[2] - mouth_points[3]) mar vertical / (horizontal 1e-6) return mar参数说明eye_points的索引顺序必须和你的关键点模型输出一致这是最容易出错的地方。不同模型给的点的排列不一样直接套公式会得到完全错误的比值。我一般会先把关键点画在图上肉眼确认索引对应的是哪个部位再写计算逻辑。1e-6是防止水平距离为零导致除零错误虽然实际中很少出现但加上不亏。3.2 时序判定单帧不算数连续帧才作准拿到每帧的眼睛和嘴巴比值之后不能单帧就报警。眨眼是正常的单帧闭眼太常见了。这套源码里疲劳判定的核心是计数器逻辑连续 N 帧眼睛比值低于阈值判定为闭眼疲劳连续 M 帧嘴巴比值高于阈值判定为打哈欠。# 阈值和计数器参数需要根据实际场景调 EAR_THRESHOLD 0.25 # 眼睛比值低于此值算闭眼 MAR_THRESHOLD 0.6 # 嘴巴比值高于此值算张嘴 CONSEC_FRAMES 20 # 连续多少帧闭眼触发疲劳 YAWN_FRAMES 15 # 连续多少帧张嘴触发哈欠 eye_counter 0 yawn_counter 0 fatigue_alarm False def judge_fatigue(ear, mar): global eye_counter, yawn_counter, fatigue_alarm # 闭眼计数 if ear EAR_THRESHOLD: eye_counter 1 else: eye_counter 0 # 睁眼就清零必须是连续的 # 哈欠计数 if mar MAR_THRESHOLD: yawn_counter 1 else: yawn_counter 0 # 任一条件满足就报警 if eye_counter CONSEC_FRAMES or yawn_counter YAWN_FRAMES: fatigue_alarm True else: fatigue_alarm False return fatigue_alarm逻辑说明eye_counter在睁眼时立刻清零保证计数的是「连续闭眼帧数」而不是累计闭眼帧数。这个区别很关键累计计数会把正常眨眼也攒进去导致误报。CONSEC_FRAMES设成 20 是按 30 帧每秒估算的大约 0.67 秒实际要根据你的摄像头帧率和驾驶员状态调。设太小会频繁误报设太大又反应迟钝这个参数没有标准答案得在你的场景里试。3.3 把检测结果画到画面上调试阶段一定要把中间结果可视化否则你根本不知道是哪一层出了问题。下面这段把眼睛嘴巴状态和报警信息叠加到视频帧上。import cv2 def draw_status(frame, ear, mar, alarm): # 左上角显示实时比值方便观察阈值是否合理 cv2.putText(frame, fEAR: {ear:.2f}, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) cv2.putText(frame, fMAR: {mar:.2f}, (20, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) # 报警时整屏加红字 if alarm: cv2.putText(frame, FATIGUE ALERT, (20, 140), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 0, 255), 3) return frame参数说明(20, 40)是文字左下角坐标0.8是字体缩放(0, 255, 0)是 BGR 颜色。这些数值随便调不影响逻辑。关键是先把 EAR 和 MAR 的实时值显示出来你盯着看几分钟就知道阈值该往哪调了。这比盲猜阈值靠谱得多。4. 避坑与排查那些让项目跑不起来的常见问题4.1 权重文件下载失败或路径找不到现象运行时报错找不到yolov8n.pt或者卡在下载不动。原因通常是网络问题或者工作目录不对。解决方式是手动下载权重放到项目根目录或者用绝对路径加载。常见做法是先去 ultralytics 的 release 页面把权重下下来然后YOLO(/绝对路径/yolov8n.pt)。别在代码里写相对路径然后换个目录跑这是新手最容易踩的坑。4.2 关键点索引对不上导致比值全错现象EAR 和 MAR 的数值一直在异常范围比如 EAR 始终大于 1。原因是你用的关键点模型输出顺序和计算函数里的索引不匹配。解决方式是先把关键点画在图上逐个确认索引对应的部位再改计算函数里的下标。这个排查过程花十分钟能省你两小时瞎调阈值。4.3 摄像头帧率不稳导致计数逻辑失效现象明明闭眼了但报警不触发或者睁着眼也报警。原因是帧率波动导致「连续帧」的时间长度不一致。解决方式是不要用固定帧数做阈值改成用时间窗口比如「连续 0.5 秒闭眼」。实现上记录每帧的时间戳用时间差累加代替帧计数。这个改动不大但稳定性提升明显。4.4 光照变化让检测时好时坏现象白天跑得好好的晚上或者进隧道就失效。原因是可见光摄像头对光照敏感YOLOv8 和关键点模型都会受影响。解决方式分两种一是加图像预处理比如直方图均衡化或者自适应亮度调整二是换红外摄像头从硬件层面解决。如果只是做演示预处理就够了如果要上车红外方案更稳。4.5 误报太多导致报警失去意义现象正常驾驶时频繁报警。原因通常是阈值太激进或者没有做状态平滑。解决方式是先放宽阈值观察一段时间的 EAR 和 MAR 分布再取一个能区分正常和疲劳的值。另外可以加一个「报警后冷却时间」避免连续报警。我一般会把冷却设成 3 到 5 秒给驾驶员一个反应窗口。5. 进阶调优让这套源码在你手里更好用5.1 用自定义数据微调 YOLOv8 人脸检测预训练权重通用性强但在你的场景里可能不够准。比如驾驶员戴墨镜、侧脸、夜间红外这些情况预训练模型容易漏检。微调的流程是用 labelme 标注一批你场景下的图片导出 YOLO 格式然后跑训练。热词里「labelme 标注用于 yolov8」和「yolov8 训练自己的数据集」都是这个环节。# 标注完的数据集目录结构应该是这样 # dataset/ # images/train/ images/val/ # labels/train/ labels/val/ # data.yaml 里写清楚路径和类别 yolo detect train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch16参数说明epochs100是训练轮数数据少的话可以降到 50imgsz640是输入尺寸和推理时保持一致batch16根据显存调显存不够就降到 8 或 4。训练完看损失曲线如果验证集损失还在降就继续训如果开始上升就是过拟合了早停。热词里「yolov8 画损失函数曲线图」说的就是这个观察过程ultralytics 训练完会自动生成曲线图在 runs 目录下。5.2 往边缘设备迁移的注意点如果你打算把模型部署到 RK3588 或 Orin 这类板子上有几个点提前注意。第一导出模型时用 ONNX 或 TensorRT 格式别直接拿 pt 文件上板。第二输入尺寸尽量用 640 或 320 这种常见值方便板端推理引擎优化。第三面部特征那层如果用的是 MediaPipe要确认板子上有没有对应的推理支持没有的话得换成轻量关键点模型。热词里「rk3588 部署 yolov8」和「orin 部署 yolov8 分割」都是这个方向核心思路是先导出再转换再验证每一步都要单独测通再往下走。5.3 一个我常用的验证习惯每次改完阈值或者换了模型我不会直接上车测而是先录一段包含正常驾驶、眨眼、打哈欠、闭眼四种状态的视频离线跑一遍把 EAR 和 MAR 的曲线画出来。看曲线比看实时画面直观得多阈值该定在哪一目了然。这个习惯帮我省了很多次来回折腾。从那以后我每次调疲劳判定参数都强制走一遍离线曲线验证再上实时。希望帮到你。本文还有配套的精品资源点击获取