☰
基于YOLOv5的疲劳驾驶检测:从源码跑通到毕业设计落地全指南
2026/9/26 13:26:56 网站建设 项目流程

简介:这是一套面向计算机相关专业学生与项目实战学习者的疲劳驾驶检测识别毕业设计资源,基于YOLOv5实现,可直接用于毕设、课程设计或期末大作业。项目经导师指导并获97分评审认可,代码经过严格调试,确保可运行。压缩包共93个文件,约136.48MB,以31个Python源码、24个YAML配置、14个编译文件为主,另含模型权重、数据集标注、说明文档、演示视频与依赖脚本,覆盖训练、推理、评估全流程。资源包含完整项目源码、预训练模型、使用说明及配套资料,目录中可见训练脚本、检测脚本、工具模块与模型配置,便于读者理解YOLOv5在疲劳驾驶场景下的数据组织、模型训练与推理部署思路,也能作为二次开发与算法对比的起点。目前已有974人学习下载,适合需要完整项目方案、排错参考与实战练习的读者。

1. 疲劳驾驶检测项目拆解:从 YOLOv5 源码到可复现的落地路径

高速上连续开三小时,眼皮开始打架,方向盘轻微跑偏的那零点几秒,往往就是事故的起点。疲劳驾驶检测要解决的就是这个场景:用摄像头实时判断驾驶员是否闭眼、打哈欠、低头,然后触发告警。这个标题里的「基于 YOLOv5」说明检测核心用的是目标检测模型,而不是传统的人脸关键点回归方案。YOLOv5 在这里负责框出眼睛、嘴巴、人脸等目标,再配合状态判定逻辑输出疲劳结论。整套资料包含源码、模型权重、数据集和使用说明,适合做毕业设计的学生,也适合想快速跑通一个端到端视觉项目的工程师。它最大的价值在于:不用从零标注数据、不用自己搭训练框架,拿到就能跑,跑通就能改。但「能跑」和「能用」之间隔着环境配置、数据格式、阈值调参三道坎,下面按落地顺序拆开讲。

2. 环境配置与 YOLOv5 源码跑通:conda 建环境到第一帧推理

2.1 为什么选 YOLOv5 而不是关键点方案

疲劳检测有两条主流路线。一条是面部关键点回归,比如用 Dlib 或 MediaPipe 定位眼睛轮廓,再算 EAR(眼睛纵横比)判断睁闭。另一条是目标检测,直接框出睁眼、闭眼、张嘴、打哈欠等类别。关键点方案轻量,但对头部姿态敏感,侧脸或戴眼镜时关键点容易漂。YOLOv5 走检测路线,把「闭眼」「打哈欠」当成独立类别来学,鲁棒性更好,而且训练和部署工具链成熟,社区资料多,出问题好查。

从工程角度看,选 YOLOv5 还有一个现实理由:这个项目的资料包里已经带了训练好的权重和标注好的数据集。如果换成关键点方案,你得自己写 EAR 阈值逻辑,还得处理不同人眼型差异,调参成本反而更高。YOLOv5 的检测结果是一个个带类别和置信度的框,后续逻辑只需要判断「闭眼框连续出现多少帧」就能出结论,代码结构清晰,也方便做可视化。

需要提醒的是,YOLOv5 官方仓库迭代过多个版本,不同版本对 PyTorch 和 CUDA 的要求不一样。这个项目标题没有写明具体版本号,所以下面给的是通用配置思路,实际以你拿到的源码里 requirements.txt 为准。

2.2 conda 环境搭建与依赖安装

第一步永远是隔离环境。我一般用 conda 建一个 Python 3.8 的环境,因为 YOLOv5 早期版本对 3.9 以上支持不够稳。

# 创建并激活环境,Python 版本按源码要求调整 conda create -n fatigue python=3.8 -y conda activate fatigue # 安装 PyTorch,CUDA 版本按自己显卡驱动选,这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 进入源码目录,安装项目依赖 cd yolov5-fatigue pip install -r requirements.txt

这段命令的逻辑是:先隔离环境避免和系统里其他项目冲突,再装 PyTorch 主框架,最后装 YOLOv5 自己的依赖。参数说明:python=3.8是版本约束,cu118对应 CUDA 11.8,如果你没有 NVIDIA 显卡,把 index-url 换成 CPU 版本即可。装完后用python -c "import torch; print(torch.cuda.is_available())"验证,返回 True 说明 GPU 可用。

常见翻车点:requirements.txt 里可能锁定了某个旧版 numpy 或 opencv,直接装会和 PyTorch 冲突。遇到报错先看是哪两个包版本打架,手动降级或升级其中一个,不要无脑pip install -U全升,那样更容易崩。

2.3 用自带权重跑通第一帧推理

环境好了,先别急着训练,用项目自带的模型权重跑一张图,确认推理链路通。

# 对单张图片做推理,--weights 指向自带权重文件 python detect.py --weights weights/best.pt --source data/samples/driver_01.jpg --conf 0.4 --device 0 # 对一段视频做推理,结果默认保存在 runs/detect/exp 下 python detect.py --weights weights/best.pt --source data/samples/driver_fatigue.mp4 --conf 0.4 --device 0

逻辑说明:detect.py是 YOLOv5 的推理入口,--weights指定模型文件,--source可以是图片、视频或摄像头编号,--conf是置信度阈值,--device 0表示用第一块 GPU。跑完后去runs/detect/exp看输出,如果框出了眼睛和嘴巴且类别正确,说明权重和代码匹配。

参数怎么调:--conf默认 0.25,疲劳检测场景建议提到 0.4 到 0.5,因为误检一个「闭眼」比漏检更烦人,会频繁误报。--iou控制重叠框合并,一般保持默认 0.45。如果显存不够,加--img-size 416降低输入分辨率,速度会快但小目标精度下降。

3. 数据集格式与训练自己的疲劳数据:从标注到 best.pt

3.1 疲劳检测数据集的类别设计与标注规范

这个项目自带的数据集大概率已经标好了,但你要用自己的数据时,类别设计是第一个决策点。常见做法是分四类:open_eye、closed_eye、open_mouth、yawn。也有人只分两类:normal 和 fatigue,把判断完全交给模型。两种都能用,区别在于可解释性。

四类方案的好处是中间结果可见,你能看到模型到底框到了什么,调阈值时有依据。两类方案标注工作量小,但模型学的是一个抽象概念,出问题时不好排查。我一般推荐四类,因为疲劳检测的误报代价高,可解释性比省事更重要。

标注用 LabelImg 或 Roboflow 都行,输出 YOLO 格式:每张图对应一个 txt,每行是类别id 中心x 中心y 宽 高,坐标都归一化到 0 到 1。注意归一化是除以图片宽高,不是除以最大边,这个坑新手常踩,标出来的框会整体偏移。

3.2 把标注数据转成 YOLOv5 训练格式

YOLOv5 要求特定的目录结构,常见做法是建一个 datasets 文件夹,里面分 images 和 labels,各自再分 train 和 val。

import os import random import shutil # 原始图片和标注文件目录 img_dir = "raw/images" label_dir = "raw/labels" # 输出目录 out_root = "datasets/fatigue" for split in ["train", "val"]: os.makedirs(f"{out_root}/images/{split}", exist_ok=True) os.makedirs(f"{out_root}/labels/{split}", exist_ok=True) # 收集所有图片名,按 8:2 划分 names = [f for f in os.listdir(img_dir) if f.endswith(".jpg")] random.shuffle(names) split_idx = int(len(names) * 0.8) train_names = names[:split_idx] val_names = names[split_idx:] def copy_files(file_list, split): for name in file_list: stem = os.path.splitext(name)[0] shutil.copy(f"{img_dir}/{name}", f"{out_root}/images/{split}/{name}") # 标注文件同名但后缀是 txt shutil.copy(f"{label_dir}/{stem}.txt", f"{out_root}/labels/{split}/{stem}.txt") copy_files(train_names, "train") copy_files(val_names, "val") print(f"train: {len(train_names)}, val: {len(val_names)}")

逻辑说明:先建好 YOLOv5 要求的目录树,再打乱数据按 8:2 切分,最后把图片和同名标注一起复制过去。参数说明:0.8是训练集比例,数据量少于 2000 张时可以调到 0.85 让模型多见点数据;random.shuffle前建议设随机种子,保证每次划分一致,方便复现。

划分完还要写一个 data.yaml,告诉 YOLOv5 数据在哪、有几类、类名是什么。

# datasets/fatigue/data.yaml path: ./datasets/fatigue train: images/train val: images/val nc: 4 names: ['open_eye', 'closed_eye', 'open_mouth', 'yawn']

nc是类别数,必须和 names 长度一致,否则训练启动就报错。path用相对路径时,训练命令要在项目根目录执行。

3.3 训练参数怎么设:yolov5s 起步的实操配置

训练命令本身不复杂,关键是参数选择。

# 从预训练权重开始训练,避免从零学 python train.py \ --data datasets/fatigue/data.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --img-size 640 \ --device 0 \ --project runs/train \ --name fatigue_v1

逻辑说明:--weights yolov5s.pt加载官方预训练权重做迁移学习,比随机初始化收敛快很多。--epochs 100是训练轮数,疲劳检测数据量通常不大,100 轮够用,但要看验证集 loss 是否还在降。--batch-size 16受显存限制,8G 显存跑 640 分辨率大概能到 16,不够就降到 8。--img-size 640是输入分辨率,眼睛是小目标,不建议低于 416。

参数怎么改:如果训练集少于 1000 张,把--epochs提到 150 到 200,同时加--freeze 10冻结前 10 层,防止过拟合。如果验证集 mAP 一直上不去,先检查标注有没有漏标或错标,数据问题比调参更常见。训练完 best.pt 在runs/train/fatigue_v1/weights/下,拿它替换推理命令里的权重路径即可。

4. 疲劳判定逻辑与实时推理:从检测框到告警信号

4.1 用帧计数做疲劳状态判定

YOLOv5 只负责框目标,疲劳结论要靠后处理逻辑。最常见的做法是滑动窗口计数:连续 N 帧检测到闭眼或打哈欠,就判定疲劳。

from collections import deque # 用双端队列保存最近 30 帧的检测状态 window = deque(maxlen=30) EYE_CLOSED_ID = 1 YAWN_ID = 3 FATIGUE_RATIO = 0.6 def update_fatigue(detections): # detections 是当前帧的类别 id 列表 has_closed = EYE_CLOSED_ID in detections has_yawn = YAWN_ID in detections window.append(1 if (has_closed or has_yawn) else 0) # 窗口内疲劳帧占比超过阈值就告警 ratio = sum(window) / len(window) return ratio > FATIGUE_RATIO

逻辑说明:deque(maxlen=30)固定窗口长度,新帧进来旧帧自动弹出。每帧只要出现闭眼或打哈欠就记 1,否则记 0。窗口内 1 的占比超过 0.6 就触发告警。参数说明:窗口 30 帧在 30fps 下约等于 1 秒,FATIGUE_RATIO调到 0.6 是经验值,调低更敏感但误报多,调高更迟钝但漏报多。实际项目里我会把这个阈值做成可配置项,方便不同场景调整。

这个逻辑的边界在于:它假设帧率稳定。如果视频卡顿导致帧率波动,窗口对应的时间就不准。稳妥做法是用时间戳而不是帧数来算窗口,但实现会复杂一些,毕业设计场景用帧计数足够。

4.2 实时摄像头推理与告警输出

把推理和判定串起来,接摄像头做实时检测。

# source 设为 0 表示调用默认摄像头 python detect.py --weights runs/train/fatigue_v1/weights/best.pt --source 0 --conf 0.45 --device 0 --view-img

--view-img会弹出实时窗口显示检测结果。如果要加声音告警,需要在 detect.py 的绘图逻辑后插入判定代码,检测到疲劳时调用播放音频的库。注意摄像头推理对帧率敏感,YOLOv5s 在普通显卡上 640 分辨率大概能到 30fps 以上,够用;如果掉到 15fps 以下,把--img-size降到 416 或换 yolov5n 轻量模型。

提示:实时推理时--conf不要设太低,0.3 以下会框出大量误检,后处理逻辑被噪声淹没,告警会疯狂触发。

5. 避坑与排查:疲劳检测项目最常见的 5 个翻车点

5.1 现象:训练 loss 正常但验证 mAP 一直是 0

原因通常是 data.yaml 里的路径写错,或者 labels 目录下没有对应的 txt 文件。YOLOv5 找不到标注时不会报错,而是当成背景图训练,loss 会降但模型学不到东西。

解决:训练前用脚本检查每张图是否有同名 txt,且 txt 里每行格式是 5 个值。路径统一用相对路径,训练命令在项目根目录执行。

5.2 现象:推理时框的位置整体偏移

原因是标注时归一化算错了。有人用坐标除以图片最大边而不是对应边,导致宽高比例失真。YOLO 格式要求 x 和 w 除以图片宽,y 和 h 除以图片高。

解决:写个校验脚本,把标注框还原到图上画出来,肉眼确认是否贴合目标。这个步骤花五分钟,能省几小时排查。

5.3 现象:闭眼和睁眼频繁混淆

原因是这两类视觉差异小,尤其在小分辨率下。640 输入时眼睛区域可能只有几十像素,模型分不清。

解决:把--img-size提到 800 或 1024,代价是显存和速度。另一个办法是在数据增强里加马赛克和随机缩放,让模型多见不同尺度的眼睛。如果还不行,考虑先用人脸检测裁出眼部区域,再对眼部区域做分类,这是两阶段方案,精度更高但工程更复杂。

5.4 现象:换个人测试就失效

原因是训练数据里驾驶员太少,模型过拟合到特定人脸。疲劳检测数据集常见问题是同一个人的多帧被分到训练和验证集,导致验证指标虚高。

解决:按人划分数据集,同一个人要么全在训练集,要么全在验证集。标注时记录驾驶员 id,划分时按 id 分组。这个坑在毕业设计里特别常见,答辩时被问到泛化能力就露馅。

5.5 现象:部署到树莓派等边缘设备跑不动

原因是 YOLOv5s 对边缘设备还是偏重,CPU 推理一帧要几百毫秒。

解决:导出 ONNX 或 NCNN 格式,用推理引擎加速。常见做法是python export.py --weights best.pt --include onnx,再用 onnxruntime 加载。树莓派 5 上跑 yolov5n 加 416 分辨率,优化后能到几帧每秒,做低频检测够用。如果要求实时,考虑换更轻量的模型或加加速棒。

6. 把疲劳检测做成可演示的毕业设计:三个提分技巧

第一个技巧是加可视化面板。光弹个检测框太单薄,用 OpenCV 在画面角落画一个状态条,实时显示疲劳占比和告警状态,再叠加帧率和推理耗时。答辩时老师看到的是一个完整系统,不是一段脚本。实现上就是在 detect.py 的绘图函数里多画几个矩形和文字,代码量不大但观感提升明显。

第二个技巧是留一份对比实验记录。同一个测试视频,分别用 yolov5n、yolov5s、yolov5m 跑一遍,记录 mAP、帧率、模型大小,做成表格放进论文。这能体现你做过选型思考,而不是随便拿个模型就跑。表格里重点标出精度和速度的权衡点,说明你为什么最终选某个模型。

模型mAP@0.5帧率(FPS)模型大小
yolov5n待测待测待测
yolov5s待测待测待测
yolov5m待测待测待测

表格里的数据必须自己跑出来填,不要抄网上的,因为你的数据集和硬件环境不同,数字没有可比性。跑三组实验大概多花两小时,但答辩时被问到「为什么不用更大的模型」你能直接答上来。

第三个技巧是准备一个失败案例集。故意找几段模型表现差的视频,比如夜间红外画面、戴墨镜、侧脸,分析失败原因并给出改进方向。这比只展示成功案例更有说服力,说明你清楚方案的边界在哪。我见过太多毕业设计只放一段完美演示,老师一问边界就答不上来。

最后一个习惯:把训练日志和推理日志都存好,用 tensorboard 看 loss 曲线和 mAP 曲线。答辩前回看这些曲线,能快速回忆起哪次调参有效、哪次是玄学。这个习惯在以后做任何模型项目都用得上,不只是疲劳检测。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询