简介:这是一套面向嵌入式AI初学者与高校实践者的驾驶员危险驾驶行为检测预警系统,基于YOLOv5深度学习模型开发,专为树莓派等边缘设备轻量化部署优化,适用于毕业设计、课程设计、学科竞赛及工程实训等场景。资源包共105个文件,涵盖39个核心Python源码(含模型训练、推理、告警逻辑)、18个配置类YAML文件(定义类别、超参与硬件适配参数)、3个MP3语音提示音频、2个关键人脸特征点检测.dat模型文件,以及Dockerfile、ONNX导出模型、UI界面与图标资源等,完整支撑从训练到端侧部署全流程,压缩包大小为174.34MB。已有153人学习下载,项目经实测可在树莓派4B上稳定运行,支持打哈欠、闭眼、分心、抽烟等多类危险行为实时识别与声光预警。用户获取后可直接烧录运行,无需二次调试;配套README详述环境搭建、引脚连接与功能验证步骤,并提供面包板快速复现方案,降低硬件门槛,助力嵌入式AI项目落地实践。
1. 项目缘起:从实验室到路边的真实需求
去年夏天,我参与了一个智能交通相关的校企合作项目,其中一个核心任务就是解决驾驶员疲劳驾驶、分心驾驶等危险行为的实时监测问题。最初,我们尝试了基于传统计算机视觉的方案,比如通过计算眼睛闭合时间(PERCLOS)来判断疲劳,或者用HOG+SVM检测驾驶员是否在打电话。但在实际路测中,这些方法在复杂光照、驾驶员姿态多变的情况下,鲁棒性很差,误报率居高不下。项目一度陷入僵局,直到我们转向了基于深度学习的方案,特别是YOLOv5,才真正打开了局面。
这个“基于深度学习+YOLOv5的驾驶员危险驾驶行为检测预警系统”,听起来像是一个典型的毕设或课设题目,但它背后指向的是一个非常实际且具有社会价值的应用场景。将这样一个系统部署到树莓派这样的边缘计算设备上,意味着它可以从昂贵的服务器或工控机中解放出来,真正走进每一辆普通的营运车辆、教练车甚至私家车,实现低成本、低功耗的实时预警。这不仅仅是完成一个作业,更是将前沿技术落地到真实世界的一次有价值的尝试。如果你正在为类似的项目寻找思路,或者对如何把AI模型塞进一个小小的树莓派感到好奇,那么我接下来分享的这套从算法选型、模型优化到边缘部署的完整流程,或许能给你带来一些直接的启发。
2. 核心任务拆解:我们要检测什么以及为什么是YOLOv5
在动手写一行代码之前,我们必须明确系统的检测目标。驾驶员危险驾驶行为是一个宽泛的概念,我们需要将其具体化为几个可被视觉算法识别的关键类别。基于行业共识和实际道路安全需求,我通常将其聚焦为以下几类:
- 使用手机:驾驶员手持手机并置于视线范围内,无论是打电话还是刷屏幕,都是典型的分心行为。
- 抽烟:手持香烟或做出吸烟动作。
- 未系安全带:驾驶员肩部安全带带扣未处于扣合状态。
- 双手脱离方向盘:在非自动驾驶状态下,驾驶员双手均未与方向盘接触。
- 疲劳驾驶:通过检测“闭眼”和“打哈欠”两种状态来间接判断。单纯的闭眼可能是眨眼,但结合打哈欠和长时间的闭眼,就能有效提示疲劳。
为什么选择YOLOv5来完成这个多目标检测任务?在项目初期,我们对比过Faster R-CNN、SSD和YOLO系列。Faster R-CNN精度高但速度慢,在树莓派上根本无法实时运行。SSD速度尚可,但在小目标检测(如手中的香烟)上精度损失明显。YOLOv5则是一个绝佳的平衡点:
- 速度与精度的卓越平衡:YOLOv5的四种模型(s, m, l, x)提供了从快到精的灵活选择。对于树莓派4B/5这样的设备,YOLOv5s模型经过优化后,完全有可能达到接近实时的检测速度(例如5-10 FPS),这对于预警系统来说是可接受的。
- 易于训练和部署:PyTorch框架生态友好,YOLOv5提供了极其完善的训练脚本、数据增强管道和模型导出工具(如导出为ONNX或TorchScript),大大降低了从零开始研发的难度。
- 社区活跃,资源丰富:遇到任何问题,从数据标注格式到模型剪枝技巧,几乎都能在社区找到讨论和解决方案,这对于项目开发至关重要。
因此,我们的技术路线非常清晰:使用YOLOv5s(或针对树莓派进一步优化的nano版本)作为基础检测模型,在一个数据集中同时学习并检测上述5类(手机、香烟、未系安全带、双手脱离、闭眼、打哈欠)行为目标。
3. 数据集的构建、标注与增强实战
模型性能的上限很大程度上由数据集决定。对于这个特定场景,公开可用的、质量高的驾驶员行为数据集非常稀少。因此,自建数据集是绕不开的一步。
3.1 数据收集与爬取策略
我们的数据主要有三个来源:
- 公开数据集整合:例如
Distracted Driver Detection、State Farm Distracted Driver Detection等,但这些数据集类别往往与我们的需求不完全匹配,主要用作补充。 - 模拟拍摄:在确保安全的前提下(如在停车场静止车辆内),邀请不同性别、体型、穿着的人员,模拟各种危险驾驶行为进行多角度、不同光照条件下的拍摄。这是获取高质量、针对性数据的主要方式。
- 网络视频抽帧:从一些行车记录仪分享视频或电影电视剧中(需注意版权),抽取包含相关行为的帧。这种方法效率高,但背景复杂,需要仔细清洗。
最终,我们积累了大约8000张有效图像,并按照8:1:1的比例划分为训练集、验证集和测试集。
3.2 标注规范与工具选择
我们使用LabelImg进行标注,格式选择YOLO所需的TXT格式。每个TXT文件对应一张图片,每行内容为:<class_id> <x_center> <y_center> <width> <height>,坐标是归一化后的值。
注意:标注的准确性至关重要。例如,“使用手机”这个类别,必须确保手机主体在驾驶员手部附近且朝向面部;“双手脱离方向盘”需要同时标注两只手不在方向盘上的位置,或者直接标注“空手”区域。模糊不清的行为宁可舍弃,也不要引入噪声。
3.3 数据增强的针对性技巧
YOLOv5内置了强大的数据增强(Mosaic, MixUp等),但我们还可以根据场景进行定制,以提升模型鲁棒性:
- 光照变化:随机调整亮度、对比度、饱和度,模拟清晨、黄昏、夜间行车以及进出隧道的光照突变。
- 模拟运动模糊:对部分图像施加方向性模糊,模拟车辆颠簸或摄像头抖动。
- 遮挡模拟:随机添加一些矩形遮挡块,模拟被方向盘、遮阳板或车内饰物部分遮挡的情况。
- 背景替换:将裁剪出的驾驶员区域粘贴到不同的车辆内饰背景中,增加背景多样性。
这些增强操作可以通过Albumentations库方便地集成到YOLOv5的训练管道中。
4. 模型训练、优化与压缩:为边缘部署做准备
有了高质量的数据集,就可以开始训练模型了。但这不仅仅是跑通train.py那么简单。
4.1 训练环境搭建与超参数调优
我们在一台配备RTX 3080的服务器上进行训练。首先从YOLOv5官方GitHub仓库克隆代码。关键的超参数设置在data/custom.yaml(定义数据集路径和类别)和models/yolov5s.yaml(定义模型结构)中。
训练命令的核心是:
python train.py --img 640 --batch 16 --epochs 100 --data data/driver_behavior.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt --name driver_detection--img 640:输入图像尺寸。更小的尺寸(如320)速度更快但精度可能下降,需要权衡。--batch 16:批大小,根据GPU显存调整。--epochs 100:迭代轮数,通常需要观察验证集损失曲线提前停止。
4.2 针对树莓派的模型优化策略
直接在服务器上训练好的yolov5s.pt模型有十几MB,在树莓派上直接推理速度仍不理想。必须进行优化:
- 模型剪枝:使用诸如
torch-pruning这样的工具,移除网络中冗余的通道或层。例如,我们可以对卷积层的通道数进行稀疏化训练,然后剪掉贡献度低的通道。这能在基本保持精度的情况下显著减少模型大小和计算量。 - 知识蒸馏:用一个更大的教师模型(如YOLOv5m)来指导我们的小模型(YOLOv5s)训练,让小模型学习教师模型的输出分布和中间特征,从而提升小模型的能力。
- 量化:这是为边缘设备提速的关键一步。我们将PyTorch模型转换为TorchScript,然后进行动态量化或静态量化(推荐后者,精度损失更可控)。量化将模型权重和激活从FP32转换为INT8,能大幅减少内存占用和加速计算,尤其适合树莓派这类具有整数计算优势的ARM处理器。
# 示例:静态量化后导出 import torch model = torch.jit.load('yolov5s.torchscript.pt') model.eval() model_fp32 = model model_int8 = torch.ao.quantization.quantize_dynamic( model_fp32, # 原始模型 {torch.nn.Linear, torch.nn.Conv2d}, # 要量化的模块类型 dtype=torch.qint8 ) torch.jit.save(model_int8, 'yolov5s_quantized_int8.pt')
经过“剪枝+量化”组合拳后,我们的模型大小可以从14MB压缩到3-4MB,推理速度提升2-3倍,而mAP(平均精度)仅下降1-2个百分点,这在边缘场景是完全可接受的 trade-off。
5. 树莓派端环境部署与推理加速
这是将算法从“实验室玩具”变为“车上设备”的关键一跃。树莓派4B或5的性能虽然远超前辈,但直接运行PyTorch完整版和原生YOLOv5推理脚本仍然吃力。
5.1 系统选择与基础环境配置
我强烈推荐使用64位的 Raspberry Pi OS Lite(无桌面环境),以最大化节省系统资源。通过raspi-config工具超频CPU/GPU、增加交换空间(swap)也是常规操作。
基础环境安装步骤:
# 1. 更新系统 sudo apt update && sudo apt upgrade -y # 2. 安装Python3及pip sudo apt install python3-pip python3-venv -y # 3. 创建虚拟环境(避免污染系统) python3 -m venv yolov5_env source yolov5_env/bin/activate # 4. 安装PyTorch的ARM64版本 # 访问PyTorch官网获取最新的适用于aarch64的whl文件链接 pip3 install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 5. 安装其他依赖,如OpenCV, NumPy等 pip3 install opencv-python-headless numpy tqdm pandas注意:务必安装
opencv-python-headless,它不包含GUI相关的库,体积更小,更适合无桌面环境的树莓派。
5.2 推理引擎的选择与优化
在树莓派上直接使用PyTorch运行模型效率并非最优。我们有更好的选择:
ONNX Runtime:将YOLOv5模型导出为ONNX格式,然后使用ONNX Runtime进行推理。ONNX Runtime针对不同硬件有高度优化的执行提供者(Execution Providers),在ARM CPU上表现优异。
# 在训练服务器上导出ONNX模型 python export.py --weights best.pt --include onnx --img 640 --simplify将导出的
.onnx文件拷贝到树莓派,使用ONNX Runtime加载和推理,通常能获得比原生PyTorch更快的速度。TensorRT(如果使用带有NVIDIA Jetson的树莓派HAT):这是一个更高级的选项。TensorRT是NVIDIA的深度学习推理优化器,能实现极致的性能。但需要额外的硬件。
LibTorch(C++接口):对于追求极致性能的开发者,可以使用PyTorch的C++前端LibTorch,避免Python解释器的开销。但这需要C++编程能力。
在我们的项目中,ONNX Runtime因其易用性和良好的性能提升成为了首选。实测在树莓派4B上,使用ONNX Runtime推理量化后的INT8模型,处理一张640x640的图像,耗时可以从约500ms降低到200ms左右,达到了5 FPS的实时性门槛。
5.3 摄像头驱动与图像采集
树莓派连接USB摄像头或官方CSI摄像头都很方便。使用picamera2库(针对CSI摄像头)或cv2.VideoCapture(针对USB摄像头)进行视频流读取。
一个常见的坑是帧率与分辨率的平衡。高分辨率(如1080p)会给推理带来巨大压力。我们的策略是:用高分辨率采集(用于显示或录像),但将缩放后的低分辨率图像(如640x640)送入模型推理。
import cv2 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while True: ret, frame = cap.read() if not ret: break # 高分辨率frame用于显示 display_frame = frame.copy() # 低分辨率img用于推理 img = cv2.resize(frame, (640, 640)) # ... 进行推理 ... # 将推理结果(边界框)映射回高分辨率坐标系并绘制在display_frame上 cv2.imshow('Detection', display_frame)6. 系统集成与预警逻辑设计
检测出行为只是第一步,如何根据检测结果做出合理、及时的预警,是系统是否好用的关键。
6.1 行为状态机与误报过滤
直接对每一帧的检测结果进行报警会导致警报泛滥。我们需要引入一个基于时间窗的状态机来平滑判断。
例如,对于“疲劳驾驶(闭眼)”的检测:
- 单帧检测到“闭眼”可能只是眨眼。
- 我们设定一个时间窗口(如2秒)和一个阈值(如在此窗口内,有80%的帧都检测到闭眼)。
- 只有当连续多帧的检测结果满足阈值条件时,才触发“疲劳驾驶”状态,并启动预警。
- 一旦预警触发,系统可以进入一个“冷却期”(如10秒),在此期间即使再次检测到闭眼,也不重复报警,避免打扰驾驶员。
这种机制能有效过滤瞬时误检,让系统更智能。
6.2 多模态预警输出
预警方式需要根据车辆环境设计:
- 声音预警:通过树莓派的音频接口或外接扬声器,播放清晰的提示音或语音(如“请勿使用手机”、“请集中注意力”)。可以使用
pygame或pyaudio库实现。 - 视觉预警:在连接到树莓派的小屏幕(如3.5寸LCD)上,用醒目的颜色(如红色)闪烁警示图标或文字。
- 数据上报:通过树莓派的GPIO引脚连接一个蜂鸣器进行硬件报警,或者通过4G/5G模块将报警事件(时间、行为类型、图片快照)上传到云端管理平台,用于车队管理。
6.3 系统资源管理与看门狗
树莓派长期运行需要稳定性保障。我们需要编写一个简单的看门狗脚本,监控主检测进程是否存活,如果崩溃则自动重启。同时,要注意控制内存和CPU占用,避免因内存泄漏导致系统卡死。可以使用psutil库来监控系统资源。
7. 实测中的挑战与调优经验
把系统装上车进行路测,才是真正的试金石。我们遇到了几个预料之外但又在情理之中的问题:
7.1 光照变化的极端挑战
黄昏时分,阳光从侧面射入驾驶室,在驾驶员脸上形成强烈的明暗对比,模型对“闭眼”的检测完全失效。解决方案是:
- 数据增强加强:在训练数据中增加更多极端光照条件的模拟样本。
- 预处理中加入直方图均衡化(CLAHE):在图像送入模型前,先进行自适应直方图均衡化,提升图像对比度,特别是在暗部区域,这能显著改善模型在低光照下的表现。
import cv2 clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) l, a, b = cv2.split(lab) l_clahe = clahe.apply(l) lab_clahe = cv2.merge((l_clahe, a, b)) img_enhanced = cv2.cvtColor(lab_clahe, cv2.COLOR_LAB2BGR)
7.2 摄像头抖动与图像模糊
车辆行驶中的震动会导致图像模糊,影响小目标(如香烟)的检测。除了在数据增强中加入运动模糊,我们还在推理管线中加入了简单的图像清晰度评估。如果检测到当前帧过于模糊,则暂时跳过该帧的推理,或者降低该帧检测结果的置信度权重,等待下一帧清晰的图像。
7.3 模型热启动与延迟
树莓派冷启动后第一次运行模型推理会特别慢(可能长达数秒),这是因为模型需要加载和初始化。为了解决“上车启动即用”的需求,我们设计了一个后台预热线程。在系统启动后,主程序加载前,先在一个后台线程中用一张空白图片跑一遍完整的推理流程,让模型和运行时环境完成“热身”,这样当真正的视频流进来时,延迟就会大大降低。
7.4 功耗与散热
持续满负荷运行的树莓派发热严重,长期在高温下工作可能引发降频甚至死机。我们加装了散热风扇和金属散热片,并将树莓派放置在中控台通风较好的位置。同时,在软件层面,我们不是每帧都进行检测,而是采用了跳帧检测的策略(例如每3帧处理1帧),在保证行为连续性能被捕捉的前提下,有效降低了平均CPU占用率和温度。
经过这些实战调优,我们的系统最终能够在树莓派4B上,以5-8 FPS的速度稳定运行,对常见危险驾驶行为的检测准确率(mAP@0.5)达到85%以上,误报率控制在可接受范围内,基本满足了项目原型的预期目标。这个过程让我深刻体会到,边缘AI部署不仅仅是“跑通一个模型”,更是一个在有限资源下,对算法、工程和硬件进行全方位权衡和优化的系统工程。
本文还有配套的精品资源,点击获取