简介本资源是一个面向深度学习初学者的疲劳驾驶监测图像数据集适用于人工智能、计算机视觉方向的入门级项目实践特别适合以闭眼、打哈欠等典型疲劳姿态为识别目标的二分类或关键点检测任务。压缩包共含2000个文件主体为2915张JPG格式人脸图像与2914份对应XML标注文件涵盖多角度、多光照条件下的疲劳状态样本总容量256.28MB配套提供了数据清洗脚本可自动剔除图片与标注不匹配的异常样本显著降低新手预处理门槛。已有4733人学习下载资源结构规范标注格式兼容主流目标检测框架如YOLO、Faster R-CNN并附有典型XML文件预览便于快速验证数据读取逻辑与标注解析流程。1. 疲劳驾驶监测数据集不是“拿来即用”的图像包而是需要先做数据对齐的训练起点你下载的疲劳驾驶监测数据集.zip表面看是 10 个 XML 文件如1429.xml、894.xml但实际它只提供了标注文件骨架缺失配套的 JPEG 图像文件——这正是新手直接解压后跑不通训练脚本的根本原因。该数据集本质是一个「半结构化标注集」XML 描述了每张图中人眼闭合、嘴巴张开等关键疲劳特征的位置与状态但原始图像未随包分发需自行采集或从其他合规渠道补充。它适合用作深度学习入门项目核心价值在于标注规范清晰Pascal VOC 格式、疲劳定义明确闭眼 张嘴双阈值且样本量适中约 100–200 张有效图经清洗后可得。如果你正尝试复现驾驶员状态识别模型、调试 YOLOv5 或 Faster R-CNN 的小规模训练流程这个数据集就是极佳的“最小可行验证集”——前提是先解决图片与 XML 的严格一一对应问题。跳过数据对齐直接训练模型会因标签错位而输出完全不可信的 loss 曲线这是 90% 初学者卡在第一步的真实陷阱。2. 数据对齐用 Python 扫描并剔除无图 XML 或无标 JPG建立严格的一一映射关系2.1 为什么必须做数据对齐从 XML 结构反推图像缺失逻辑Pascal VOC 格式的 XML 文件如1429.xml在filename标签内硬编码了对应图像的文件名例如filename1429.jpg/filename size width640/width height480/height /size object nameclosed_eye/name bndbox xmin120/xmin ymin85/ymin xmax180/xmax ymax115/ymax /bndbox /object注意filename值是1429.jpg而非1429.xml。这意味着 XML 文件本身不包含图像仅声明“我描述的是名为1429.jpg的图”。若你的JPEGImages/目录下没有1429.jpg该 XML 就是悬空标注强行参与训练会导致 DataLoader 加载时抛出FileNotFoundError或更隐蔽地因cv2.imread()返回None导致 bbox 坐标计算崩溃。原始数据集提供的 10 个 XML 文件恰恰是这种悬空标注的典型样本——它们是完整标注集的子集快照而非独立可用包。2.2 执行双向校验先删无图 XML再删无标 JPG原始摘要中给出的代码仅单向清理删除 JPEGImages 中无对应 XML 的图片这在真实场景中是危险的。正确做法是执行双向强制对齐确保每个 XML 有同名 JPG每个 JPG 有同名 XML。以下是生产级校验脚本含日志与备份import os import shutil from pathlib import Path # 配置路径按实际解压结构调整 JPEG_DIR Path(Dataset/dataset/JPEGImages) ANNOTATION_DIR Path(Dataset/dataset/Annotations) BACKUP_DIR Path(Dataset/dataset/backup_mismatched) # 创建备份目录 BACKUP_DIR.mkdir(exist_okTrue) # 获取所有 JPG 文件名不含扩展名 jpg_names {f.stem for f in JPEG_DIR.glob(*.jpg) if f.is_file()} # 获取所有 XML 文件名不含扩展名 xml_names {f.stem for f in ANNOTATION_DIR.glob(*.xml) if f.is_file()} # 计算差集 jpg_only jpg_names - xml_names # 有图无标 xml_only xml_names - jpg_names # 有标无图 print(f发现 {len(jpg_only)} 张无标注图片: {sorted(jpg_only)[:5]}...) print(f发现 {len(xml_only)} 个无图片标注: {sorted(xml_only)[:5]}...) # 备份并删除无标注 JPG for stem in jpg_only: jpg_path JPEG_DIR / f{stem}.jpg backup_path BACKUP_DIR / f{stem}.jpg shutil.move(jpg_path, backup_path) print(f 已备份无标图: {jpg_path.name} → {backup_path.name}) # 备份并删除无图片 XML for stem in xml_only: xml_path ANNOTATION_DIR / f{stem}.xml backup_path BACKUP_DIR / f{stem}.xml shutil.move(xml_path, backup_path) print(f 已备份无图标: {xml_path.name} → {backup_path.name}) # 输出最终有效样本数 valid_count len(jpg_names xml_names) print(f\n✅ 对齐完成剩余 {valid_count} 组有效 (JPG XML) 对)提示此脚本使用shutil.move()而非os.remove()强制保留所有被剔除文件至backup_mismatched/目录。这是工程实践底线——任何数据清洗操作都必须可逆。若后续发现误删可直接从备份目录恢复。2.3 验证对齐结果生成清单文件并人工抽检对齐后需生成trainval.txtVOC 标准划分文件并抽检。运行以下命令生成清单# 在终端中执行Linux/macOS或 PowerShellWindows cd Dataset/dataset ls JPEGImages/*.jpg | xargs -I {} basename {} .jpg ImageSets/Main/trainval.txt然后手动打开trainval.txt随机选取前 3 行如1429,894,1062检查JPEGImages/1429.jpg是否存在且能正常打开用file JPEGImages/1429.jpg查看 MIME 类型Annotations/1429.xml是否存在且filename值为1429.jpg用浏览器打开1429.jpg肉眼确认是否包含闭眼或张嘴动作疲劳核心特征。若任一检查失败说明对齐不彻底需重新运行脚本并检查路径拼写常见错误JPEGImages写成JpegImages或大小写不一致。3. 模型训练基于 YOLOv5s 的轻量级疲劳检测实现与关键参数调优3.1 为什么选 YOLOv5s 而非 ResNet 或 Faster R-CNN疲劳驾驶检测是典型的单阶段目标检测任务需同时定位眼部闭合状态和口腔张开状态两个关键区域并判断其空间关系。YOLOv5s 在以下维度优于其他架构推理速度在 Jetson Nano 等嵌入式设备上可达 25 FPS满足车载实时性要求小目标敏感度s版本的 Neck 层PANet对 40×40 像素级的眼部 bbox 有更强响应标注容错性相比 Faster R-CNN 的两阶段流程YOLO 对 bbox 标注轻微偏移±5px鲁棒性更高适配手工标注数据集。ResNet 仅适合分类任务如“疲劳/清醒”二分类无法输出位置信息Faster R-CNN 虽精度高但训练耗时长同等配置下比 YOLOv5s 慢 3.2 倍且对小样本收敛困难——本数据集经对齐后仅约 150 张图YOLOv5s 是唯一能在 2 小时内完成端到端训练的合理选择。3.2 构建 VOC-to-YOLO 格式转换器将 XML 转为.txt标签YOLO 要求标签为class_id center_x center_y width height归一化坐标。编写转换脚本xml_to_yolo.pyimport xml.etree.ElementTree as ET from pathlib import Path def convert_voc_to_yolo(xml_path, img_width, img_height, class_map): tree ET.parse(xml_path) root tree.getroot() yolo_lines [] for obj in root.findall(object): cls_name obj.find(name).text.strip() if cls_name not in class_map: continue # 跳过非目标类别如 face bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) # 归一化center_x, center_y, w, h x_center (xmin xmax) / 2.0 / img_width y_center (ymin ymax) / 2.0 / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height yolo_line f{class_map[cls_name]} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f} yolo_lines.append(yolo_line) return yolo_lines # 配置 CLASS_MAP {closed_eye: 0, open_mouth: 1} # 疲劳双特征0闭眼, 1张嘴 VOC_ANN_DIR Path(Dataset/dataset/Annotations) YOLO_LABEL_DIR Path(Dataset/yolo/labels) YOLO_LABEL_DIR.mkdir(exist_okTrue) # 遍历所有 XML假设图像尺寸统一为 640x480 for xml_path in VOC_ANN_DIR.glob(*.xml): stem xml_path.stem yolo_path YOLO_LABEL_DIR / f{stem}.txt # 从 XML 中读取 size更健壮 tree ET.parse(xml_path) size tree.find(size) w int(size.find(width).text) h int(size.find(height).text) yolo_lines convert_voc_to_yolo(xml_path, w, h, CLASS_MAP) yolo_path.write_text(\n.join(yolo_lines)) print(f已生成: {yolo_path.name} ({len(yolo_lines)} 个目标))注意CLASS_MAP显式定义了两类疲劳特征。实际训练中模型会学习closed_eye和open_mouth的联合出现模式——单类检测准确率可能达 92%但双类共现才判定为疲劳这是业务逻辑层的关键设计。3.3 YOLOv5s 训练命令详解与超参调优表在yolov5仓库根目录下执行训练假设已克隆官方 repopython train.py \ --img 416 \ # 输入尺寸416x416平衡速度与小目标检测 --batch 8 \ # batch_size8显存占用约 3.2GBGTX 1080 可行 --epochs 100 \ # 小数据集需足够 epoch避免欠拟合 --data dataset.yaml \ # 数据配置文件见下文 --weights yolov5s.pt \ # 使用 COCO 预训练权重迁移学习关键 --name fatigue_yolov5s \ # 实验名称输出至 runs/train/fatigue_yolov5s/ --exist-ok # 允许覆盖同名实验目录dataset.yaml内容必须严格匹配你的目录结构train: ../Dataset/yolo/images/train # 训练图路径需提前复制对齐后的 JPG val: ../Dataset/yolo/images/val # 验证图路径 nc: 2 # 类别数 names: [closed_eye, open_mouth] # 类别名顺序与 CLASS_MAP 一致参数推荐值调优逻辑--img416小于 640 可提升小目标 recall大于 416 显存溢出风险陡增--batch8batch16在 1080Ti 上 OOMbatch4收敛慢 40%--epochs100学习率衰减策略cosine需足够轮次50 epoch 时 mAP0.5 通常仅 0.32--weightsyolov5s.pt必须启用迁移学习随机初始化在 150 图上无法收敛训练完成后runs/train/fatigue_yolov5s/weights/best.pt即为最优模型。用val.py验证python val.py --weights runs/train/fatigue_yolov5s/weights/best.pt --data dataset.yaml --task test重点关注metrics/mAP_0.5IoU0.5 时的平均精度新手项目达到0.72即为合格。4. 疲劳判定逻辑落地从模型输出到驾驶状态决策的端到端链路4.1 解析模型输出提取闭眼与张嘴的置信度及空间关系YOLOv5 输出为(x, y, w, h, conf, cls)六元组。关键不是单独看conf而是构建双特征联合判定规则import cv2 import torch from models.experimental import attempt_load from utils.general import non_max_suppression model attempt_load(runs/train/fatigue_yolov5s/weights/best.pt, map_locationcpu) model.eval() def detect_fatigue(frame): # 预处理BGR→RGB→归一化→添加 batch 维度 img cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img torch.from_numpy(img).float().div(255.0).permute(2,0,1).unsqueeze(0) # 推理 pred model(img)[0] pred non_max_suppression(pred, conf_thres0.4, iou_thres0.4)[0] # NMS 后处理 # 分离两类检测框 eyes pred[pred[:, -1] 0] # cls_id0: closed_eye mouths pred[pred[:, -1] 1] # cls_id1: open_mouth # 计算联合置信度几何平均 if len(eyes) 0 and len(mouths) 0: eye_conf eyes[:, 4].max().item() mouth_conf mouths[:, 4].max().item() joint_conf (eye_conf * mouth_conf) ** 0.5 return joint_conf 0.65 # 双特征置信度乘积开方 0.65 判定疲劳 return False # 使用示例 cap cv2.VideoCapture(0) while cap.isOpened(): ret, frame cap.read() if detect_fatigue(frame): cv2.putText(frame, FATIGUE DETECTED!, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2) cv2.imshow(Fatigue Monitor, frame) if cv2.waitKey(1) ord(q): break cap.release()提示joint_conf使用几何平均而非算术平均是因为闭眼和张嘴是必要非充分条件——任一特征缺失如只闭眼不张嘴不能判定疲劳几何平均天然惩罚单边高置信。4.2 抗干扰优化时间窗口平滑与瞳孔面积动态阈值真实车载场景中单帧误检率高强光反射导致假闭眼、说话导致假张嘴。引入时间维度过滤# 维护最近 5 帧的 joint_conf 序列 conf_history [] def robust_fatigue_decision(current_conf): conf_history.append(current_conf) if len(conf_history) 5: conf_history.pop(0) # 连续 3 帧 0.65 才触发报警 return sum(c 0.65 for c in conf_history) 3 # 瞳孔面积动态阈值防强光误判 def get_pupil_area(frame, eye_bbox): x1, y1, x2, y2 [int(v) for v in eye_bbox[:4]] eye_roi frame[y1:y2, x1:x2] gray cv2.cvtColor(eye_roi, cv2.COLOR_BGR2GRAY) _, thresh cv2.threshold(gray, 30, 255, cv2.THRESH_BINARY_INV) # 强光下阈值需下调 area cv2.countNonZero(thresh) return area / ((x2-x1) * (y2-y1)) # 归一化面积比 # 在 detect_fatigue 中调用 # if get_pupil_area(frame, eyes[0]) 0.12: # 瞳孔面积占比 12% 才认为真闭眼4.3 部署验证用 OpenCV-DNN 加载 ONNX 模型实现零依赖推理为脱离 PyTorch 环境部署导出 ONNX 并用 OpenCV 加载# 导出 ONNX在 yolov5 目录 python export.py --weights runs/train/fatigue_yolov5s/weights/best.pt --include onnxOpenCV 加载代码无需安装 PyTorchimport cv2 import numpy as np net cv2.dnn.readNetFromONNX(yolov5s_fatigue.onnx) net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU) def cv2_dnn_inference(frame): blob cv2.dnn.blobFromImage(frame, 1/255.0, (416,416), swapRBTrue, cropFalse) net.setInput(blob) outputs net.forward(net.getUnconnectedOutLayersNames()) # 解析 outputsYOLOv5 ONNX 输出为 [1, 25200, 6] detections outputs[0].squeeze() # shape: (25200, 6) boxes, confs, classes [], [], [] for det in detections: conf det[4] if conf 0.4: x, y, w, h det[:4] cls int(det[5]) boxes.append([int(x-w/2), int(y-h/2), int(w), int(h)]) confs.append(float(conf)) classes.append(cls) # NMS indices cv2.dnn.NMSBoxes(boxes, confs, 0.4, 0.4) return [(boxes[i], confs[i], classes[i]) for i in indices.flatten()]至此你已构建出一条从原始数据清洗、模型训练、多特征融合判定到轻量部署的完整技术链路。下一步可接入 CAN 总线触发车辆警报或叠加头部姿态估计增强鲁棒性——但那已是另一个项目的边界了。本文还有配套的精品资源点击获取