基于YOLOv5的疲劳驾驶检测:从模型训练到实时预警的完整实践

基于YOLOv5的疲劳驾驶检测:从模型训练到实时预警的完整实践 简介本资源是一套完整的基于YOLOv5的疲劳驾驶检测识别毕业设计项目面向计算机、人工智能及相关专业本科生解决驾驶员实时状态监测与安全预警的实际问题适用于毕业设计、课程设计及期末大作业等实践场景。压缩包共93个文件涵盖31个Python源码含main.py、train.py、smoke.py等核心模块、24个YAML配置文件定义模型结构与训练参数、2个PT模型文件best.pt与yolov5s.pt、2个MP4演示视频、2个Markdown说明文档及配套数据集、Dockerfile、Flask API接口、人脸关键点检测dat模型等整体大小为136.48MB。已有972人学习下载。项目经导师指导并高分通过评审97分包含全部可运行源码、预训练模型、详细使用说明txt、环境配置requirements.txt及实测图像/视频样例目录结构规范模块划分清晰支持一键训练、检测与Web API部署显著降低毕设开发门槛与调试成本。1. 项目概述从毕业设计到实用工具的跨越最近在整理硬盘时翻出了一个压箱底的“宝贝”——一个名为“基于yolov5的疲劳驾驶检测识别项目”的完整压缩包。这让我想起了几年前带学生做毕业设计时为了让他们能快速上手并做出有实际价值的成果我花了不少心思搭建的这个项目框架。如今yolov5虽然已不是最前沿的模型但其在目标检测领域的经典地位、出色的易用性和丰富的社区资源使其依然是入门计算机视觉、特别是想快速实现一个可演示应用的绝佳选择。这个项目不仅仅是一堆代码和模型文件它更像是一个精心设计的“脚手架”旨在帮助学习者避开初期那些令人头疼的坑直接触及疲劳驾驶检测这个应用场景的核心逻辑。这个项目能做什么简单说它利用摄像头实时捕捉驾驶员的面部图像通过yolov5模型快速定位眼睛和嘴巴等关键区域然后基于这些区域的动态特征如眼睛闭合时长、打哈欠频率来判断驾驶员是否处于疲劳状态并发出预警。它解决的不仅仅是“检测到人脸”的问题更是“如何从人脸中提取有效的疲劳指标”以及“如何设计一个稳定可靠的预警逻辑”这一系列工程问题。无论你是计算机视觉的初学者想通过一个完整的项目理解从数据到模型的 pipeline还是相关领域的开发者需要一个快速验证想法的原型工具亦或是高校学生正在寻找一个既有理论深度又有实践价值的毕业设计课题这个项目都能提供一个扎实的起点。2. 项目核心思路与技术选型解析2.1 为什么选择YOLOv5在众多目标检测模型中为这个疲劳驾驶项目选择YOLOv5是基于多方面的权衡。首先速度与精度的平衡是核心考量。疲劳检测需要实时或准实时处理视频流延迟过高就失去了预警意义。YOLO系列一贯以“快”著称而YOLOv5在继承这一优点的同时通过引入新的网络结构如CSPNet、SPP和更高效的训练策略在精度上也有不错的表现。对于检测眼睛、嘴巴这类尺寸相对固定、特征明显的目标YOLOv5的精度完全够用。其次极致的易用性是YOLOv5的杀手锏。PyTorch框架的友好性自不必说YOLOv5项目本身提供了极其清晰的代码结构、详尽的文档和丰富的预训练模型。从数据准备使用特定格式的标注文件、模型训练一行命令或一个脚本、到模型导出支持ONNX、TorchScript等多种格式整个流程都被高度封装和自动化。这对于教学和快速原型开发来说极大地降低了门槛学生或开发者可以将精力更多地集中在业务逻辑疲劳判定算法上而不是纠结于模型本身的调试。最后活跃的社区生态提供了强大后盾。任何在部署、训练中遇到的问题几乎都能在GitHub Issues或相关论坛中找到讨论和解决方案。这种“站在巨人肩膀上”的感觉能让项目推进得更顺利。当然我们也要认识到YOLOv5并非没有缺点例如对小目标、密集目标的检测在某些场景下可能不如一些两阶段检测器但对于车内相对单一环境下的面部关键点检测这个缺点并不突出。2.2 疲劳驾驶检测的逻辑链条设计一个完整的疲劳驾驶检测系统远不止“运行一个目标检测模型”那么简单。它是一条环环相扣的逻辑链。我们的项目设计遵循了“检测 - 追踪 - 分析 - 决策”的流程。第一步是面部与关键点检测。这是整个系统的基石。我们使用YOLOv5模型其输出不仅仅是“人脸”这个框更关键的是要能同时输出“左眼”、“右眼”、“嘴巴”等关键区域的坐标。这就要求我们的训练数据必须包含这些细粒度的标注。在模型设计上我们可能会采用一个多类别的检测头同时输出人脸、左眼、右眼、嘴巴的边界框和置信度。第二步是跨帧目标追踪。由于视频是连续的帧序列单纯对每一帧进行独立检测会导致目标ID跳变无法持续计算某个驾驶员的疲劳指标。因此需要引入简单的追踪算法如基于IOU交并比的关联或者集成更轻量的追踪器如DeepSORT的简化版以确保同一驾驶员的眼睛和嘴巴在连续帧中被正确关联。第三步是疲劳特征提取与分析。这是算法的“大脑”。对于追踪到的眼睛区域我们计算其纵横比Eye Aspect Ratio, EAR这是一个对眼睛开合程度不敏感的度量。通过连续帧的EAR值我们可以判断眼睛是否闭合以及闭合的持续时间。对于嘴巴区域类似地计算其纵横比Mouth Aspect Ratio, MAR或高宽比来检测打哈欠动作。此外头部姿态估计如通过面部关键点计算头部偏转角度也可以作为注意力分散的辅助判断依据。第四步是疲劳状态决策与预警。这是逻辑的终点。我们不会因为一帧的眨眼就判定为疲劳。通常采用基于时间的状态机或滑动窗口统计。例如设定一个时间窗口如2秒统计窗口内眼睛闭合帧数占总帧数的比例PERCLOS一种常用的疲劳度量标准当该比例超过阈值如0.2且可能伴随打哈欠频率过高则触发“疲劳”状态并启动声光预警。注意阈值如EAR阈值、PERCLOS阈值的设定需要根据实际场景数据进行校准。不同人种、光照条件、摄像头角度都会影响这些数值。项目中提供的阈值是一个经验起始值在实际部署前必须用目标环境的数据进行验证和调整。3. 项目结构与核心模块详解3.1 源码目录结构剖析解压项目压缩包后你会看到一个清晰的结构这反映了模块化的设计思想。下面是一个典型的目录树及其功能说明fatigue_detection_yolov5/ ├── data/ │ ├── images/ # 存放训练、验证、测试用的图片 │ ├── labels/ # 存放对应图片的YOLO格式标注文件 (.txt) │ └── dataset.yaml # 数据集配置文件定义路径、类别名等 ├── models/ │ ├── yolov5s.yaml # YOLOv5s网络结构定义文件 │ └── yolov5s_fatigue.pt # 训练好的针对疲劳检测的模型权重示例 ├── utils/ │ ├── datasets.py # 数据加载与预处理工具 │ ├── general.py # 通用函数画框、计算IOU等 │ ├── metrics.py # 评估指标计算 │ └── fatigue_utils.py # **核心**疲劳特征计算与状态判断函数 ├── detect_fatigue.py # **主程序**实时疲劳检测脚本 ├── train.py # 模型训练脚本 ├── requirements.txt # Python依赖包列表 └── README.md # 项目详细使用说明关键文件解读dataset.yaml这是数据集的“地图”。它定义了训练集、验证集图片的路径、类别数量以及类别名称列表。例如我们的类别可能是[‘face’ ‘left_eye’ ‘right_eye’ ‘mouth’]。正确配置这个文件是训练的第一步。fatigue_utils.py这是项目的“智慧核心”。它不包含YOLO的检测代码而是专注于处理YOLO检测后的结果。其主要函数可能包括calculate_ear(eye_landmarks)根据眼睛的6个关键点坐标计算EAR值。calculate_mar(mouth_landmarks)根据嘴巴的坐标计算MAR值。is_eye_closed(ear, threshold)判断当前帧眼睛是否闭合。fatigue_state_machine(ear_history, mar_history, time_window)基于历史数据实现疲劳判定的状态机。detect_fatigue.py这是应用的“总控制器”。它集成了YOLO检测、追踪、调用fatigue_utils进行分析、以及绘制结果和发出预警的整个流水线。通常你可以通过命令行参数指定模型路径、摄像头ID、置信度阈值等。3.2 模型训练与数据准备要点如果你不想使用项目提供的预训练模型或者想用自己的数据优化模型那么训练是必经之路。YOLOv5的训练流程已经非常标准化。数据准备你需要收集大量包含驾驶员面部最好是不同光照、角度、表情的图片。然后使用标注工具如LabelImg、CVAT、Roboflow进行标注。关键点在于你需要标注出四个类别整个人脸框、左眼框、右眼眶、嘴巴框。标注完成后工具会生成YOLO格式的.txt文件每行格式为class_id x_center y_center width height坐标是归一化后的值0-1之间。配置文件调整修改models/yolov5s.yaml中的nc类别数为4。在data/dataset.yaml中正确指向你的images和labels文件夹路径并更新names列表。启动训练训练命令通常很简单例如python train.py --img 640 --batch 16 --epochs 100 --data ./data/dataset.yaml --cfg ./models/yolov5s.yaml --weights yolov5s.pt --name fatigue_detection--img 640输入图像尺寸。YOLOv5会自适应缩放但固定一个尺寸有利于批量处理。--batch 16批大小。根据你的GPU内存调整越大训练越快但需要更多显存。--epochs 100训练轮数。通常需要观察损失曲线不再明显下降为止。--weights yolov5s.pt从官方的YOLOv5s预训练权重开始训练这是非常重要的技巧能极大加快收敛速度并提升最终性能这称为迁移学习。--name fatigue_detection本次训练运行的名称用于创建保存结果的目录。实操心得在训练自己的数据集时最常见的坑是标注错误。务必仔细检查标注文件确保边界框紧贴目标且类别ID正确。可以使用YOLOv5自带的utils.plots模块中的函数将标注框画回图片上进行检查。另一个关键是学习率如果从头训练不加载预训练权重学习率要设得很小如1e-3如果使用预训练权重可以用稍大的学习率如1e-2并在后期衰减。4. 核心算法疲劳特征提取与状态判定4.1 眼睛纵横比与嘴巴纵横比计算疲劳检测的可靠性很大程度上取决于特征提取的鲁棒性。我们主要依赖两个几何特征眼睛纵横比和嘴巴纵横比。眼睛纵横比EAR的计算基于眼睛的6个关键点在2D图像上这通常由人脸关键点检测器提供但在我们这个项目中我们直接用YOLO检测出的眼睛框来近似。更精确的做法是在检测到眼睛框后再用一个小型的关键点网络或传统图像处理来定位眼皮点。经典的EAR公式是EAR (||p2-p6|| ||p3-p5||) / (2 * ||p1-p4||)其中p1...p6是眼睛轮廓上的六个点从左眼角开始顺时针。这个比值在眼睛睁开时相对稳定闭合时会迅速趋近于0。在我们的项目中如果只有边界框我们可以用一个简化版本EAR height / width。即眼睛区域框的高度除以宽度。当眼睛睁开时框是扁长的宽度远大于高度EAR值小当眼睛闭合时框更接近正方形或竖长条高度相对增加EAR值会变大。这里需要注意这个简化方法对头部姿态变化比较敏感但在正对摄像头的情况下效果尚可。嘴巴纵横比MAR的计算类似用于检测打哈欠。可以用嘴巴外轮廓的关键点计算简化版同样可以用检测框的高度/宽度。打哈欠时嘴巴张大高度显著增加MAR值会变大。在fatigue_utils.py中相应的函数可能如下所示def calculate_simple_ear(eye_box): 根据眼睛检测框计算简化的EAR值。 eye_box: [x1, y1, x2, y2] 像素坐标 width eye_box[2] - eye_box[0] height eye_box[3] - eye_box[1] if width 0: # 避免除零错误 return 0 ear height / width return ear def is_eye_closed_simple(ear, threshold0.25): 根据简化的EAR值判断眼睛是否闭合。 threshold: 经验阈值需要根据实际数据调整。 return ear threshold4.2 基于时序分析的疲劳状态机单帧的判断毫无意义疲劳是一个持续的状态。因此我们需要一个基于时间窗口的状态机。一个简单而有效的设计如下数据缓冲为每个追踪到的驾驶员维护两个固定长度的队列或列表分别存储最近N帧例如对应2秒假设30fps则N60的EAR值和MAR值。特征统计PERCLOS计算在EAR队列中统计EAR值低于“闭合阈值”的帧数除以总帧数N得到眼睛闭合时间比例。打哈欠频率在MAR队列中统计MAR值超过“哈欠阈值”的帧数可以计算单位时间内的打哈欠次数。多级预警决策正常状态PERCLOS低于阈值P1如0.1且打哈欠频率低。预警状态PERCLOS超过阈值P1但低于P2如0.2或打哈欠频率开始升高。系统可以发出轻度提示如屏幕闪烁。疲劳状态PERCLOS超过阈值P2或短时间内打哈欠次数超过阈值。系统触发强预警如持续蜂鸣声、语音提示。这个状态机可以在fatigue_utils.py中用一个类来实现class FatigueDetector: def __init__(self, ear_thresh0.25, perclos_thresh0.2, time_window60): self.ear_thresh ear_thresh self.perclos_thresh perclos_thresh self.time_window time_window self.ear_history [] # 保存历史EAR值 self.fatigue_counter 0 def update(self, current_ear): self.ear_history.append(current_ear) if len(self.ear_history) self.time_window: self.ear_history.pop(0) # 保持队列长度固定 # 计算当前窗口内的PERCLOS closed_frames sum([1 for ear in self.ear_history if ear self.ear_thresh]) perclos closed_frames / len(self.ear_history) # 状态判断 if perclos self.perclos_thresh: self.fatigue_counter 1 if self.fatigue_counter 5: # 连续多帧判定为疲劳避免抖动 return FATIGUE, perclos else: self.fatigue_counter max(0, self.fatigue_counter - 1) return NORMAL, perclos注意事项所有阈值ear_threshperclos_threshtime_window都不是金科玉律。它们需要在实际部署环境中进行校准。最好的方法是录制一段目标环境下的驾驶员视频包含清醒和疲劳状态人工标注出疲劳时间段然后用程序跑一遍调整阈值使得程序的判断与人工标注尽可能吻合。这个过程可能有点枯燥但至关重要。5. 项目部署与实时检测流程5.1 环境配置与依赖安装要让项目跑起来第一步是搭建Python环境。强烈建议使用Anaconda创建独立的虚拟环境避免包版本冲突。# 1. 创建并激活虚拟环境以conda为例 conda create -n fatigue_yolo python3.8 conda activate fatigue_yolo # 2. 安装PyTorch请根据你的CUDA版本到PyTorch官网选择对应命令 # 例如对于CUDA 11.3 pip install torch1.12.1cu113 torchvision0.13.1cu113 torchaudio0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113 # 3. 安装项目依赖 cd path/to/fatigue_detection_yolov5 pip install -r requirements.txt # requirements.txt 通常包含opencv-python, pandas, seaborn, tqdm, matplotlib, pyyaml等关键依赖说明PyTorchYOLOv5的运行基础。务必选择与你的GPU如果有及CUDA版本匹配的安装命令。如果没有GPU则安装CPU版本。OpenCV用于图像/视频的读取、显示、预处理和结果绘制。其他pandas,seaborn等主要用于训练过程中的数据分析与可视化实时检测脚本可能不需要全部。5.2 实时检测脚本运行与参数调优环境准备好后运行实时检测脚本通常很简单python detect_fatigue.py --source 0 --weights ./models/yolov5s_fatigue.pt --conf-thres 0.5--source 0指定视频源。0代表系统默认摄像头。你也可以传入视频文件路径如--source ./test.mp4或图片路径。--weights指定训练好的模型权重文件路径。--conf-thres 0.5置信度阈值。只有检测框的置信度高于此值才会被保留。调高它可以减少误检但可能漏检调低则相反。运行后会弹出一个窗口显示摄像头画面并在检测到的人脸、眼睛、嘴巴上画框同时在画面顶部或侧边显示当前的EAR、MAR值和疲劳状态如“NORMAL” “WARNING” “FATIGUE”。性能调优实战帧率FPS提升如果感觉卡顿首先尝试降低推理分辨率。在detect_fatigue.py中找到加载模型后对图像进行预处理的地方通常有一个img_size参数。将其从640降低到416或320可以显著提升速度但可能会轻微降低小目标的检测精度。减少抖动检测框和状态判断可能会帧间抖动。可以在fatigue_utils.py的状态机中引入“迟滞”机制如上文代码中的fatigue_counter只有连续多帧满足条件才切换状态。对于检测框可以使用简单的移动平均滤波来平滑坐标。多线程处理对于高性能应用可以考虑将图像采集、模型推理、后处理与UI显示放在不同的线程中通过队列进行通信避免因显示或I/O操作阻塞推理。6. 常见问题排查与实战技巧6.1 模型训练与评估中的典型问题问题现象可能原因排查方法与解决方案训练损失loss不下降1. 学习率设置过高或过低。2. 数据标注存在大量错误。3. 模型结构或配置文件有误。1. 尝试使用默认学习率或使用学习率预热warmup和余弦退火cosine annealing策略。2. 使用utils.plots中的plot_labels函数可视化检查标注框是否合理。3. 检查dataset.yaml中的类别数和models/*.yaml中的nc是否一致。验证集精度mAP很低但训练集损失正常模型过拟合。1. 增加数据增强YOLOv5默认已包含较强的增强。2. 如果数据集很小尝试使用更小的模型如yolov5n。3. 加入正则化如权重衰减weight decay。4. 检查训练集和验证集的数据分布是否差异过大。模型检测不到目标漏检1. 置信度阈值conf-thres设得过高。2. 训练数据中目标尺寸差异大模型未学好。3. 推理图像尺寸与训练尺寸不匹配。1. 逐步调低conf-thres如从0.5调到0.25。2. 检查数据集中目标框的尺寸分布确保训练时使用了多尺度训练YOLOv5默认开启。3. 确保推理时输入的图像被缩放到与训练相同的尺寸如640。检测框位置不准1. 标注框不精确。2. 数据增强过于激进导致目标变形严重。1. 重新检查并修正标注数据。2. 适当减少数据增强的强度特别是旋转和剪切变换。6.2 实时检测中的工程挑战与应对光照变化这是车载环境最大的挑战。强烈逆光、隧道明暗交替、夜晚光线不足都会导致检测失败。应对在图像预处理阶段加入自适应直方图均衡化或对比度受限的自适应直方图均衡化来增强图像。考虑在模型训练数据中尽可能包含各种光照条件的图片。遮挡问题驾驶员可能戴眼镜、墨镜或者用手托腮遮挡部分面部。应对训练数据中必须包含足够多的遮挡样本。对于墨镜导致的完全遮挡需要引入其他辅助判断如头部姿态是否低垂或车辆方向盘操作信号如车道偏离。侧脸与姿态驾驶员经常转头看后视镜或侧窗。应对训练数据需要包含多角度的面部图片。在算法层面当检测到侧脸时可以只依赖能看到的单只眼睛进行判断或暂时降低疲劳判断的权重主要依赖头部姿态角如俯仰角过大进行预警。误报与漏报的权衡过于敏感的系统会频繁误报干扰驾驶员过于迟钝的系统则起不到预警作用。应对这是一个产品层面的决策。需要通过大量实车路测数据来调整疲劳判定算法的阈值和逻辑。可以考虑引入二级预警机制一级为轻度提醒如仪表盘图标闪烁二级为强烈警告持续声音。6.3 项目扩展与进阶方向如果你已经成功运行了基础项目并希望将其深化或用于更实际的场景这里有几个进阶方向模型轻量化与嵌入式部署将PyTorch模型转换为ONNX格式然后利用TensorRT或OpenVINO等工具在Jetson Nano、RK3568等边缘计算设备上加速推理实现真正的车载嵌入式部署。多模态信息融合单一的视觉信息在极端情况下可能不可靠。可以尝试融合其他传感器数据例如方向盘操作信号通过CAN总线获取方向盘转角波动频率和幅度。车辆状态信号车道偏离预警系统的输出。生理信号如果可获取心率、皮肤电反应等。设计一个基于多传感器数据的融合决策模型如卡尔曼滤波、简单的加权投票或深度学习融合网络能显著提升系统的鲁棒性。更精细的关键点检测用YOLO框出眼睛和嘴巴区域后可以在这些区域内部署一个轻量级的面部关键点检测模型如MobileNet回归头获取更精确的眼角、嘴角坐标从而计算更稳定的EAR和MAR值减少对边界框的依赖。加入注意力机制在YOLOv5的主干网络或检测头中引入注意力模块如SE CBAM让模型更关注面部关键区域提升在复杂背景下的检测精度。这个基于YOLOv5的疲劳驾驶检测项目就像一把钥匙为你打开了计算机视觉应用开发的大门。从数据准备、模型训练、到算法集成和问题调试它涵盖了一个AI项目从0到1的主要环节。在实际动手的过程中你遇到的每一个报错、每一次调参、对每一个阈值的纠结都是比理论更宝贵的经验。我个人的体会是把项目跑通只是第一步真正理解每一行代码背后的意图并能根据实际遇到的新问题去调整和优化它甚至推翻重来某些部分才是学习和成长的关键。最后一个小建议在开始动手前先花点时间通读一遍README.md和主要的源代码在脑子里画出整个程序的数据流图这会让你在后续的调试中事半功倍。本文还有配套的精品资源点击获取