简介本资源是面向智能座舱与疲劳驾驶监测领域的YOLO目标检测专用数据集适用于计算机视觉初学者、车载AI算法工程师及高校相关课题研究者用于训练和验证驾驶人眼部开闭状态与口腔张合动作的多类别目标检测模型。压缩包共含2000个XML格式标注文件严格遵循PASCAL VOC规范每个文件对应一张原始图像的边界框坐标、类别标签如open_eye、close_eye、open_mouth、close_mouth及关键点辅助信息便于直接转换为YOLOv5/v8所需格式整体包体大小为256.91MB结构简洁无冗余文件。目前已有69人学习下载适合快速构建驾驶员状态识别基线模型。读者可直接加载该数据集开展标注格式转换、数据增强实验、mAP对比测试及轻量化部署验证配套XML结构统一、样本覆盖光照变化与姿态多样性显著降低数据预处理门槛。 开车犯困这件事做过实车测试的人都知道有多难搞。早期我用过基于方向盘的偏离检测也试过仅靠心率带做疲劳推断但这些方案都有一个共同问题它们测的是“间接信号”而不是直接看驾驶员的面部状态。真正可靠的方案绕不开对“眼睛是否睁开、嘴巴是否张合”的实时判断。这也是YOLO类目标检测模型在这个场景下最吃香的原因——直接把睁眼、闭眼、张嘴、闭嘴这些状态当作目标框出来交给分类器或时序模型去做疲劳判定。我最近在整理一套专门用来训练这类模型的资源驾驶人睁闭眼张合嘴检测数据集图片配xml格式标签。这篇文章就围绕这个数据集展开从数据规格、标注细节、模型训练适配到实际部署中的坑一条线讲清楚。1. 驾驶人状态检测任务的场景与难点1.1 为什么单靠传感器方案不够市面上很多疲劳驾驶预警系统走的都是“间接推断”路线。比如监测方向盘转角是否长时间不动、车道偏离次数是否陡增、跟车距离是否异常拉近。这些方法有用但问题也很明显它们必须等“异常行为已经发生”才能报警属于事后检测。而真正的疲劳往往伴随面部特征的渐进变化——眼睛闭合时间变长、眨眼频率降低、打哈欠次数增多。这些信号在行为异常之前就已经出现能争取到的提前量通常是几秒到几十秒别小看这点时间高速上几十秒就是几百米甚至上千米的刹车距离。所以现在的行业主流方案都转向了直接监测驾驶员面部状态。摄像头装在A柱、方向盘或仪表盘附近对准人脸用目标检测模型实时输出眼睛和嘴巴的ROI感兴趣区域再结合状态分类器判断当前是睁眼还是闭眼、张嘴还是闭嘴。这个方案看起来简单但真正落地时对数据集的要求极高。1.2 脸部状态检测对数据集的特殊要求和通用目标检测不同驾驶人状态检测的数据集有几个特殊性筛选时一定要留心。第一是视角的集中性。摄像头安装位置固定人脸角度变化范围有限所以数据集里的图片主体应该尽量是正脸或近正脸而不是像COCO那样的任意场景。第二是光照多样性。车内光照条件跨度极大白天强光、逆光、夜间仪表盘微光、隧道内忽明忽暗样本里这些情况都得覆盖。第三是遮挡情况。戴眼镜、墨镜、口罩、刘海遮眼、手部遮挡这些情况会导致检测框本身不完整需要在模型设计时提前考虑。第四是状态分布均衡性。闭眼和打哈欠这类状态在自然驾驶中占比极低如果数据集里睁眼和闭嘴样本占九成以上训练出来的模型对少数类几乎不敏感。好的数据集应该有意均衡两个类别的样本量。这套驾驶人睁闭眼张合嘴检测数据集就是围绕以上几个要求整理的。图片内容聚焦于人脸局部区域标签覆盖眼睛和嘴巴的开关状态格式上用VOC标准的xml标注可以直接配合YOLO系模型使用也方便转成其他格式。2. 数据集内容规格与目录结构详解2.1 图片内容与标注类别这个数据集的核心检测对象是两类器官、四种状态眼睛的睁开与闭合嘴部的张开与闭合。具体的标注类别通常以open_eye、closed_eye、open_mouth、closed_mouth这四类来命名也有数据集会把眼睛统一为eye嘴统一为mouth通过标签属性区分开关状态。拿到手之后第一步就是确认类别名称因为YOLO训练时类别ID直接依赖标签顺序搞错了就得改一堆配置文件。从图片内容看数据采集通常包含多名不同性别、年龄、是否佩戴眼镜的受试者背景以车内环境为主部分图片会有光照变化。图片以单张jpg格式存储分辨率需要能让眼睛区域至少占到几十个像素以上否则检测框会小到难以训练。拿到数据后我建议先做一步筛查把分辨率过低、目标过小、严重模糊的图片剔除掉这类脏数据对模型精度的拖累比想象中大。2.2 VOC xml标签结构xml格式的标注遵循Pascal VOC的标准结构。每张图片对应一个同名xml文件内部核心信息包含图片路径、尺寸、通道数以及每个目标的类别名称和边界框坐标。坐标以四个整数记录xmin、ymin、xmax、ymax表示边界框左上角和右下角的位置。这里有一个非常容易踩的坑VOC坐标是绝对像素坐标而YOLO训练需要的是归一化到0到1之间的中心点坐标和宽高。转换公式是固定的但很多人会在宽高计算上出错。YOLO格式里中心点x需要除以图片宽度中心点y需要除以图片高度框宽和框高也分别要除以图片宽高。换句话说是四个值全都除以各自的对应维度而不是统一除以一个大数。2.3 验证集与训练集的划分思路数据集打包后通常没有直接划分train和val目录而是所有图片和xml放在一起需要自己拆。拆分的比例建议按8比2来如果图片总量不大可以采用K折交叉验证来评估模型稳定性。划分时要注意一个点不要让同一个人不同状态下的图片出现在训练集和验证集里。比如同一个受试者的闭眼图在训练集、睁眼图在验证集这会导致验证结果虚高因为模型学到了人的特征而不是状态的特征。如果数据是按受试者组织的按人划分而不是按图片划分才是正确做法。3. 标注质量与使用前的关键检查3.1 坐标越界与空框问题拿到标注数据我强烈建议先跑一段脚本做全量检查而不是直接进训练。常见问题有三个坐标越界、空框、类别不均衡。坐标越界是指xmax或ymax超过了图片宽高这种框在转换YOLO格式后会出现大于1的归一化值训练时直接报错或产生nan损失。还有一些标注框是空框即宽或高为0这类样本应该在预处理阶段直接剔除。检查和修复逻辑可以这样写遍历所有xml读取每个object的边界框坐标判断是否在图片边界内宽高是否大于0类别名称是否在预定义类别列表里。一旦发现问题可以选择剔除该标注或整张图片。如果是坐标轻微越界例如越界几个像素可以用钳位操作把坐标值裁剪回图片范围内。3.2 类别名称统一与漏标检查另一个高频问题是从不同来源收集的数据标签命名风格不统一。有的叫closed_eye有的叫eye_close有的叫eye_closed。如果不做统一训练时就等于把同一类目标拆成了多个类别导致检测混乱。统一类别名称的逻辑很简单在预处理脚本里维护一个映射表把所有可能的命名变体映射到标准名称然后批量改写xml文件。改写后还要检查是否有漏标的情况——比如一张图里明显有睁眼和闭眼两个目标但xml里只标了其中一个。这类问题比较难自动化处理最笨也最可靠的办法是随机抽样几百张图片可视化标注框人工肉眼过一遍。3.3 数据增强的边界训练时数据增强能显著提升模型的泛化能力尤其是光照变化和遮挡场景。但在做增强时要注意一个边界——对闭眼和睁眼这种细微差别的目标翻转和旋转幅度过大会改变语义。比如左右翻转是安全的因为左右眼互换不影响“睁或闭”的语义。但大角度旋转就可能出问题旋转90度后眼睛的形态特征变得不典型模型学到的特征会偏离真实场景。对于眼睛和嘴巴检测我建议的增强策略以亮度调整、对比度调整、小范围平移缩放、左右翻转为主尽量避免大角度旋转和极端透视变换。另外还有一个常用技巧Mosaic增强在YOLOv4之后基本都是标配但用在眼睛和嘴巴这种小目标上有时会适得其反。Mosaic把四张图拼在一起目标会更小小目标检测本来就难拼图后更难。如果发现小目标检测效果差可以尝试关闭Mosaic或降低其使用概率。4. 用YOLO训练驾驶人状态检测模型从xml到推理的完整流程4.1 环境准备与目录搭建在开始训练之前先把环境搭好。推荐使用YOLOv8或YOLOv5两者对自定义数据集的支持都比较完善资料也多。以YOLOv8为例项目目录下需要建立这样的结构dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamlimages目录放图片labels目录放转换好的YOLO格式txt文件每个txt文件名与对应图片名相同。data.yml内容如下train: dataset/images/train val: dataset/images/val names: 0: open_eye 1: closed_eye 2: open_mouth 3: closed_mouth这个文件指定了训练和验证图片的路径以及类别名称与ID的对应关系。类别顺序必须和标签转换脚本保持一致否则模型学到的类别含义会错位。4.2 xml转YOLO txt的脚本实现目录准备好之后写一段脚本把VOC xml转成YOLO格式。核心逻辑是读取xml中的size信息图片宽高和每个object的边界框坐标计算归一化中心点坐标和宽高写入txt文件。import os import xml.etree.ElementTree as ET def convert_voc_to_yolo(xml_file, out_dir, classes): tree ET.parse(xml_file) root tree.getroot() img_width int(root.find(size/width).text) img_height int(root.find(size/height).text) out_lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 钳位到图片边界内 xmin max(0, min(xmin, img_width - 1)) xmax max(0, min(xmax, img_width - 1)) ymin max(0, min(ymin, img_height - 1)) ymax max(0, min(ymax, img_height - 1)) if xmax xmin or ymax ymin: continue dw 1.0 / img_width dh 1.0 / img_height center_x (xmin xmax) / 2.0 * dw center_y (ymin ymax) / 2.0 * dh box_w (xmax - xmin) * dw box_h (ymax - ymin) * dh out_lines.append(f{cls_id} {center_x:.6f} {center_y:.6f} {box_w:.6f} {box_h:.6f}) if out_lines: out_name os.path.splitext(os.path.basename(xml_file))[0] .txt with open(os.path.join(out_dir, out_name), w) as f: f.write(\n.join(out_lines)) classes [open_eye, closed_eye, open_mouth, closed_mouth] # 遍历所有xml文件循环处理即可这段脚本里有三个细节值得注意。一是钳位操作防止边界越界但如果你发现坐标系里xmax等于图片宽度这样看似“越界”的值其实是合法的像素索引说明你对坐标的理解还不够透彻。二是类别过滤如果xml里有模型不需要的类别直接跳过。三是输出格式每行五个值类别ID加四个归一化坐标YOLO系列模型统一用这个格式。4.3 训练参数设置与调参经验训练时首先是模型规模的选择。对于眼睛和嘴巴这类小目标检测我建议从yolov8n或yolov8s起步不要一上来就上yolov8x。原因有二一是驾驶员状态检测通常在车载嵌入式设备上运行算力有限大模型即使精度高也部署不了二是眼睛和嘴巴目标数量少、类别简单大模型不仅浪费算力还容易过拟合。图像分辨率方面YOLOv8默认的640x640是够用的但前提是数据集中眼睛区域的像素尺寸不能太小。建议训练时将imgsz参数设为640如果数据集中人脸占比较大、眼睛区域像素清晰也可以试着调到960有时能提升小目标召回率但训练时间和显存消耗会明显增加。epochs建议从100起步配合早停机制patience设为20到30。由于数据集规模通常不算大几十个epoch之后模型可能就收敛了。优化器用默认的SGD或AdamW都可以YOLOv8默认的SGD在实际训练中表现稳定。关键的超参数是mosaic和mixup这两种增强的概率如果发现训练集损失下降很快但验证集损失震荡优先检查是不是增强强度过大。训练命令参考yolo detect train datadata.yaml modelyolov8n.pt epochs150 imgsz640 batch16 patience30 projectruns namedriver_status训练结束后在runs/driver_status/weights/目录下会生成best.pt和last.pt取best.pt做后续推理和导出。4.4 推理与状态判定逻辑模型训练好后推理流程是对视频帧做人脸检测或者直接对整帧做目标检测输出眼睛和嘴巴的检测框及类别。实际部署中通常是先做人脸检测在脸部区域内再做眼睛和嘴巴检测这样可以减少全图搜索的干扰提升检测速度。写一个简单而有效的状态判定逻辑对连续若干帧的检测结果做平滑处理。举例来说单帧检测出closed_eye置信度很高但下一帧又是open_eye直接按单帧判定会频繁抖动。常规做法是加一个状态计数器假设连续5帧中4帧以上判定为闭眼才认为驾驶员确实处于闭眼状态。打哈欠的判定类似连续检测到open_mouth超过2秒才算一次有效哈欠误报会低很多。5. 训练状态分类器的经验与踩坑记录5.1 目标检测与状态分类的分工严格来说YOLO目标检测模型输出的是“眼睛在图像的哪个位置”和“这个位置的类别是睁眼还是闭眼”。它把检测和分类合二为一所以部署起来非常方便。但实际项目中我见过不少人走入一个误区试图让YOLO直接输出“疲劳等级”或“是否疲劳”这种整体状态。疲劳是一个时序概念单帧图像无法定义。闭眼0.1秒还是闭眼2秒含义完全不同。正确的架构是YOLO做目标级检测把眼睛和嘴巴的状态输出出来然后再用一个状态机或时序模型例如LSTM、GRU甚至简单的滑动窗口统计对一段时间内的状态序列做综合判定。这种分工既简单又可靠不要把疲劳判定的压力全放在检测模型上。5.2 夜间与光照不足场景的处理夜间是驾驶员状态检测的重灾区。如果训练数据以白天为主模型在夜间红外摄像头的画面下表现会很差。解决思路有几个一是针对性补数据。在真实夜间环境下采集图片加入训练集。这是最直接也最有效的方法。二是预处理适配。如果部署端用的是红外摄像头训练时就要把图片做灰度化或红外风格化预处理让模型学到的特征与部署环境一致。很多人忽视这个导致白天精度很高、夜晚上车直接不能用。三是曝光和对比度增强。对暗光图片做CLAHE对比度受限自适应直方图均衡化增强能在不改变语义的前提下让特征更清晰。这部分可以在数据加载时做在线增强也可以在预处理阶段做离线增强后加入训练集。5.3 误检与漏检的排查思路训练完成后用一段实际驾驶视频测试结果如果出现严重误检或漏检按这个思路排查。漏检眼睛或嘴巴优先检查图片分辨率。如果摄像头距离驾驶员较远人脸区域小眼睛可能只占几个像素此时要么调整摄像头安装位置要么在检测链路中增加一个人脸放大步骤。误检则首先看背景干扰例如方向盘上的logo、手机屏幕、窗外的反光都可能被模型误认为眼睛或嘴巴。我自己的实践经验是在训练集中随机混入一些不含驾驶人状态的负样本图片比如空座椅、中控台、挡风玻璃外景告诉模型“这些地方没有目标”能显著降低误检率。YOLO系列支持这种负样本训练但需要对应空的txt标签文件。5.4 数据集的扩展与持续迭代模型部署之后的迭代比初始训练更关键。建议在实车测试中收集困难样本比如戴墨镜的眼睛、阳光直射下的强反光、打哈欠时嘴巴被手遮住一半定期补充到训练集里重新微调。数据集不是一次性的东西它是一个需要持续维护的资产。对现有数据集做增强扩展也是一种方式。比如用亮度扰动模拟不同时段的光线用模拟遮挡生成戴口罩或墨镜的负样本用mixup方法把不同状态的人脸做混合增强模型的鲁棒性。这个过程没有太多高深理论就是靠样本量和对真实场景的理解堆出来的。6. 部署实践中的几个关键选择6.1 模型导出与推理框架训练好的PyTorch权重不能直接上车需要导出成部署格式。以YOLOv8为例可以用一行命令导出为ONNX或TensorRT引擎yolo export modelbest.pt formatonnx opset12导出ONNX后可以用ONNX Runtime跑CPU推理也可以用TensorRT做GPU推理。实际部署时车载设备往往没有强劲GPU更常见的选择是瑞芯微、地平线或英伟达Jetson系列平台。不同平台支持的模型格式和算子库不一样ONNX是中间转换最稳妥的格式。导出后要跑一遍推理确认输出结果和PyTorch原版一致这一步叫做精度对齐验证是在嵌入式平台上经常会踩的坑。6.2 帧率与检测策略的平衡车载场景下检测帧率直接决定了系统的可用性。如果每秒只能检测5帧一个人眨眼的动作可能就错过了。为了保证帧率需要做一些取舍。实际部署中常见的策略是分级检测先用轻量级人脸检测模型定位人脸区域裁剪出人脸ROI只在ROI内部跑眼睛和嘴巴检测。这样可以大幅减少计算量因为整帧图像的大部分区域不需要做目标检测。我自己实测在Jetson Nano这类边缘设备上这种策略能把眼睛嘴巴检测的帧率从个位数提升到20帧以上。另一个思路是帧间复用如果上一帧检测到人脸位置下一帧大幅度移动的可能性不大可以在上一帧人脸位置附近扩大一定范围的区域做检测而不是全图搜索。这本质上是用时序连续性换算力效果非常明显。6.3 告警阈值与误报控制最后一步是告警策略。闭眼检测到一次并不代表一定要立刻报警需要结合持续时间来设定阈值。闭眼超过0.8秒或1秒才触发预警是行业内比较常见的设置。打哈欠的告警阈值可以设定为1分钟内检测到3次以上张嘴动作。这些阈值没有一个固定标准需要根据实车测试的效果不断调整。阈值设得太高系统反应迟钝起不到预警作用设得太低误报频繁驾驶员很快会对报警产生免疫。我建议在处理逻辑里把检测置信度、连续帧计数和持续时间三者结合起来做成可配置的参数方便在现场标定。在我实际做过的项目里单靠YOLO检测模型的输出直接接一个滑动窗口判断就能在误报可控的前提下达到较好的疲劳预警效果并不需要上复杂的时序网络。很多团队一上来就上LSTM加注意力反而把简单的任务复杂化了。如果你刚开始接触这个方向先用这套“检测加窗口统计”的组合跑通全流程再考虑优化其实是最务实的路线。本文还有配套的精品资源点击获取