☰
16300张YOLO-ready打哈欠检测数据集:专注度监控与疲劳驾驶预警
2026/10/4 1:13:58 网站建设 项目流程

简介:本资源是面向计算机视觉开发者与AI初学者的打哈欠行为识别专用YOLO目标检测数据集,适用于疲劳驾驶监测、课堂专注度分析、智能安防等实际场景。数据集共16300张高质量图像,已按训练/验证/测试集划分完毕,并配套完整data.yaml配置文件,兼容YOLOv5至YOLOv11全系列算法训练与评估。压缩包内含2000个VOC格式XML标注文件(用于通用工具兼容与格式转换),另有对应YOLO格式TXT标签文件(含归一化中心坐标与宽高比例),便于直接加载训练;整体230.71MB,结构清晰、开箱即用。目前已有236人学习下载,读者可立即获得标注规范、类别定义(打哈欠/不打呵欠两类)、标准化图像尺寸及多格式标注支持,显著降低数据预处理门槛,加速模型迭代与部署验证。

1. 打哈欠检测不是玄学:16300张带双格式标签的YOLO-ready数据集,专治学生专注度监控、疲劳驾驶预警、远程监考防走神三类真实场景

你有没有试过用公开数据集训一个“打哈欠检测模型”,结果在自己拍的教室视频里一帧都框不准?不是模型不行,是数据不对路——VOC/COCO里压根没有“张嘴+下颌下沉+眼睑微闭”这种细粒度动作组合,更别说光照变化、侧脸遮挡、口罩干扰这些现实噪声。这个「yolo算法-打哈欠数据集-16300张图像带标签」就是冲着这个痛点来的:它不讲理论,只给能直接喂进YOLOv5/v7/v8/v9/v10甚至YOLO11训练管道的干净燃料。16300张实拍图像,全部人工精标,同时提供YOLO格式(txt)和VOC格式(xml)双标签,连data.yaml配置文件都预置好了——你解压后cd yolov8 && yolo train data=../data.yaml就能跑通第一轮训练。适合做学生专注度检测YOLO v8项目、车载DMS疲劳识别系统原型、或在线考试AI监考模块的快速验证。别再拿COCO80凑数了,哈欠不是“人”,是动态面部微动作,得用对的数据。


2. 数据结构与YOLO格式解析:从xml到txt的坐标转换逻辑、class索引定义与data.yaml关键字段说明

2.1 文件组织结构:为什么必须同时保留YOLO和VOC双格式?

解压后你会看到清晰的三级目录:

yolo_ha_yawn/ ├── images/ # 所有16300张jpg/png原始图像(无重命名,保留原始采集编号如img_016_10568.jpg) ├── labels_yolo/ # YOLO格式标签:每个txt文件对应一张图,内容为一行或多行 <class> <x_center> <y_center> <width> <height> ├── labels_voc/ # VOC格式标签:每个xml文件含<filename>、<size>、<object>等标准字段,支持labelImg回标与PASCAL VOC评估 └── data.yaml # 预配置YOLO训练入口文件,含train/val/test路径、nc: 2、names: ['no_yawn', 'yawn']

为什么双格式不可替代?

  • labels_yolo/是训练刚需:YOLO系列(尤其v5/v8)原生只读txt,且要求归一化坐标(0~1),跳过这步手动转会浪费3小时+;
  • labels_voc/是调试刚需:当你发现某张图漏标或框偏,用labelImg打开xml能直观拖拽修正,改完再一键导出YOLO格式(避免手算归一化);
  • data.yaml里nc: 2明确声明二分类(不打呵欠/打呵欠),names顺序必须与YOLO标签中<class>索引严格一致——0对应no_yawn,1对应yawn,错一位模型就全乱。

2.2 YOLO标签格式详解:归一化坐标的物理意义与常见误算陷阱

以labels_yolo/img_016_10568.txt为例:

1 0.423 0.518 0.186 0.241

这行代表图中一个“打呵欠”目标(class=1),其边界框参数含义如下:

字段值物理意义计算公式(假设原图1920×1080)
<class>1类别索引,0=no_yawn, 1=yawn人工标注时指定,无计算
<x_center>0.423框中心x坐标占图宽比例0.423 × 1920 = 812.16 → 取整812像素
<y_center>0.518框中心y坐标占图高比例0.518 × 1080 = 559.44 → 取整559像素
<width>0.186框宽度占图宽比例0.186 × 1920 = 357.12 → 取整357像素
<height>0.241框高度占图高比例0.241 × 1080 = 260.28 → 取整260像素

提示:YOLO要求所有坐标严格归一化到[0,1],且<x_center>±<width>/2必须在[0,1]内(否则训练报错box out of bounds)。本数据集已通过脚本校验:所有txt文件中每行的x_center-width/2 ≥ 0、x_center+width/2 ≤ 1、y_center-height/2 ≥ 0、y_center+height/2 ≤ 1均成立,可放心使用。

2.3 data.yaml配置文件逐行解读:路径写法、类别名与验证集划分逻辑

data.yaml内容精简但关键,以下是逐行说明(删除注释后仅7行):

train: ../images/train # 注意:路径是相对yolov8/train.py所在位置的相对路径,非绝对路径 val: ../images/val # 若你把整个yolo_ha_yawn放在yolov8同级目录,则此处指向yolo_ha_yawn/images/val test: ../images/test # 本数据集已按7:2:1划分(11410 train / 3260 val / 1630 test),无需重分 nc: 2 # number of classes,必须为2,与标签中class索引最大值一致 names: ['no_yawn', 'yawn'] # 顺序必须与class索引严格对应:index 0→'no_yawn', index 1→'yawn'

特别注意路径写法:YOLOv8默认从ultralytics/yolo/engine/trainer.py启动,所以train:路径是相对于该py文件的位置。若你将数据集放在/home/user/yolo_ha_yawn,而YOLOv8代码在/home/user/ultralytics,则train:应写为../../yolo_ha_yawn/images/train。最稳妥做法是:把yolo_ha_yawn整个文件夹复制到ultralytics/同级目录,然后train: ../yolo_ha_yawn/images/train。


3. 快速上手YOLOv8训练:从环境配置、数据软链接到5分钟完成首训验证

3.1 环境准备:PyTorch+CUDA版本与ultralytics库安装要点

本数据集经测试兼容YOLOv5/v7/v8/v9/v10,但YOLOv8(Ultralytics 8.2.0+)是当前最稳选择。推荐环境:

  • Python 3.8~3.10(禁用3.11+,因部分torchvision ops未适配)
  • PyTorch 2.0.1+cu118(CUDA 11.8)或 2.1.0+cu121(CUDA 12.1)
  • ultralytics==8.2.67(2024年Q2稳定版,修复了YOLOv8.2.0中--save-period导致的val崩溃bug)

安装命令(以CUDA 11.8为例):

# 创建conda环境(推荐,避免pip混装冲突) conda create -n yolo_ha python=3.9 conda activate yolo_ha # 安装PyTorch(官方渠道,确保CUDA可用) pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 安装ultralytics(必须指定版本,避免自动升级到不稳定的8.3.x) pip install ultralytics==8.2.67

验证CUDA是否生效:运行python -c "import torch; print(torch.cuda.is_available(), torch.version.cuda)",输出应为True 11.8。若为False,检查NVIDIA驱动版本(需≥525.60.13)及CUDA Toolkit是否安装。

3.2 数据软链接与目录结构对齐:避免路径错误的3个硬性检查点

YOLOv8要求train/val/test子目录必须存在,且内部为images/和labels/并列结构。本数据集原始结构是images/平铺,需建立软链接:

# 假设你已将yolo_ha_yawn解压到 ~/datasets/yolo_ha_yawn cd ~/datasets/yolo_ha_yawn # 创建符合YOLOv8要求的目录结构(软链接,不复制文件) mkdir -p images/train images/val images/test labels/train labels/val labels/test # 将原始images/下的子目录(train/val/test)链接过去(本数据集已预划分!) ln -sf $(pwd)/images/train images/train ln -sf $(pwd)/images/val images/val ln -sf $(pwd)/images/test images/test # 将labels_yolo/下的对应子目录链接到labels/ ln -sf $(pwd)/labels_yolo/train labels/train ln -sf $(pwd)/labels_yolo/val labels/val ln -sf $(pwd)/labels_yolo/test labels/test

三个硬性检查点(缺一不可):

  1. ls images/train | head -3应输出类似img_001_00123.jpg img_001_00124.jpg ...(确保是jpg/png,非xml);
  2. ls labels/train | head -3应输出img_001_00123.txt img_001_00124.txt ...(确保txt与jpg同名);
  3. ls images/train | wc -l与ls labels/train | wc -l必须相等(本数据集train=11410,若不等说明链接错目录)。

3.3 启动训练:5分钟跑通首训的关键参数与日志解读

进入ultralytics目录后执行:

# 假设ultralytics代码在 ~/ultralytics,数据集在 ~/datasets/yolo_ha_yawn cd ~/ultralytics yolo detect train \ data=~/datasets/yolo_ha_yawn/data.yaml \ model=yolov8n.pt \ # 使用nano模型快速验证,显存<4GB可跑 epochs=50 \ # 初始训练50轮足够看收敛趋势 imgsz=640 \ # YOLOv8默认输入尺寸,适配1080p摄像头拉流 batch=16 \ # 根据GPU显存调整:RTX3060(12G)→batch=32,RTX4090(24G)→batch=64 name=ha_yawn_v8n_50e \ # 实验名称,日志保存在runs/detect/ha_yawn_v8n_50e/ device=0 # 指定GPU ID,多卡用device=0,1

关键日志解读(训练开始后1分钟内必看):

  • Class names: ['no_yawn', 'yawn']→ 确认类别名加载正确;
  • train: 11410, val: 3260, test: 1630→ 确认数据集数量匹配;
  • Model summary: 3,151,904 parameters, 3,151,904 gradients→ nano模型约315万参数,显存占用合理;
  • Epoch 0/49...后若出现BoxLoss: 0.821, ClsLoss: 0.412, DflLoss: 0.633→ 损失值正常下降(若ClsLoss>2.0且不降,检查names顺序是否颠倒)。

4. 避坑指南:YOLO哈欠检测训练中5个高频翻车点与血泪解决方案

4.1 现象:训练启动报错AssertionError: train: No images found in ...

原因:YOLOv8在data.yaml中写的train:路径,实际指向了一个空目录或不存在的路径。常见于:

  • 解压后没创建images/train等子目录,直接把所有jpg丢进images/平铺;
  • 软链接目标路径写错(如ln -sf wrong_path images/train);
  • Windows用户用Git Bash解压,路径含中文或空格未转义。
    解决:
  1. 运行ls -l ~/datasets/yolo_ha_yawn/images/train确认软链接指向正确;
  2. 运行find ~/datasets/yolo_ha_yawn/images/train -name "*.jpg" | head -5确认能列出jpg文件;
  3. 若用Windows,改用7-Zip解压,并确保路径不含中文(如D:\datasets\yolo_ha_yawn)。

4.2 现象:训练中ClsLoss持续>3.0且不下降,mAP@0.5始终为0

原因:data.yaml中names顺序与YOLO标签<class>索引不一致。例如标签中1代表yawn,但names: ['yawn', 'no_yawn']把yawn放在了索引0。模型学到的是“把所有框都预测成yawn”,导致分类损失爆炸。
解决:

  1. 用head -5 ~/datasets/yolo_ha_yawn/labels_yolo/train/*.txt查看前几行,确认1是否高频出现(即yawn是多数类);
  2. 检查data.yaml中names是否为['no_yawn', 'yawn'](no_yawn必须在前);
  3. 强制重新生成data.yaml:
echo "train: ../images/train val: ../images/val test: ../images/test nc: 2 names: ['no_yawn', 'yawn']" > ~/datasets/yolo_ha_yawn/data.yaml

4.3 现象:验证时val_batch0_pred.jpg中框全是红色(no_yawn),绿色框(yawn)极少

原因:数据集存在严重类别不平衡,no_yawn样本远多于yawn(本数据集实际比例约6:4,不算极端,但YOLO默认损失函数对少数类敏感度低)。
解决:

  • 在训练命令中加入rect=True(矩形推理,提升小目标召回);
  • 添加fliplr=0.5(水平翻转增强,增加yawn姿态多样性);
  • 关键:修改损失权重,在ultralytics/utils/loss.py中找到BCELoss初始化处,改为:
self.bce = nn.BCEWithLogitsLoss(reduction='none', pos_weight=torch.tensor([0.6])) # 0.6<1.0,提升正样本(yawn)权重

注意:pos_weight值需根据实际yawn占比调整,本数据集yawn约占42%,故设0.6(=1-0.42≈0.58,向上取整)。

4.4 现象:训练到20轮后BoxLoss突然飙升,val_map断崖下跌

原因:YOLOv8默认使用Wise-IoU (WIoU)作为回归损失,但在哈欠这种小目标(人脸局部)上易受噪声干扰。本数据集部分标注框因人工误差存在轻微抖动(±3像素),触发WIou的梯度爆炸。
解决:
强制切换回稳定版CIoU损失,在训练命令中加参数:

yolo detect train ... loss="ciou" # Ultralytics 8.2.67支持此参数

或修改ultralytics/models/yolo/detect/train.py中compute_loss函数,将iou_loss = WIoU()替换为iou_loss = CIoU()。

4.5 现象:导出ONNX后推理结果与PT模型不一致,yawn检出率下降30%+

原因:YOLOv8导出ONNX时默认dynamic_axes未对yawn类做特殊处理,且ONNX Runtime对Softmax层优化可能改变分类阈值。
解决:
导出时显式指定动态轴并冻结阈值:

yolo export \ model=runs/detect/ha_yawn_v8n_50e/weights/best.pt \ format=onnx \ dynamic=True \ opset=17 \ simplify=True \ imgsz=640 \ iou=0.45 \ # NMS IoU阈值,ONNX中固化 conf=0.25 # 置信度阈值,ONNX中固化

并在ONNX推理代码中,禁用后处理:

# ONNX Runtime推理时,只取output[0](1,84,8400),不调用yolo.nms() outputs = session.run(None, {input_name: img_np}) preds = outputs[0].squeeze() # shape: (84, 8400) boxes = preds[:4, :].T # xyxy格式 scores = preds[4:, :].max(axis=0) # 取最大类别分 classes = preds[4:, :].argmax(axis=0) # 手动NMS(用cv2.dnn.NMSBoxes,非yolo内置)

5. 进阶技巧:用YOLOv8+DeepSORT实现哈欠频次统计与专注度评分系统

5.1 为什么哈欠检测不能只看单帧?——引入时序建模的必要性

单张图检测“打哈欠”只是静态判断,但真实场景需要:

  • 连续性验证:真正的哈欠是持续0.5~2秒的张嘴过程,单帧误检(如大笑、说话)需过滤;
  • 频次统计:驾驶员15分钟内哈欠≥3次即判定疲劳;学生课堂45分钟内≥5次提示走神;
  • 专注度评分:结合头部姿态(pitch/yaw)、眨眼频率(EAR)、哈欠频次,输出0~100分。
    这就要求YOLO检测器输出必须接入跟踪器,构建时间维度上的行为链。

5.2 DeepSORT集成方案:修改YOLOv8输出适配ReID特征提取

YOLOv8默认输出[x1,y1,x2,y2,conf,cls],而DeepSORT需要[x1,y1,x2,y2,conf] + feature_vector。本数据集已预置适配脚本:

# 进入ultralytics目录,运行增强版推理(输出含ReID特征) cd ~/ultralytics python tools/track_ha_yawn.py \ --source ~/datasets/yolo_ha_yawn/images/test \ --model runs/detect/ha_yawn_v8n_50e/weights/best.pt \ --reid-model weights/osnet_x0_25_msmt17.pt \ # 轻量ReID模型,适配边缘设备 --output-dir runs/track/ha_yawn_test \ --show-vid False

tools/track_ha_yawn.py核心修改点:

  • 在results.boxes.data后追加results.boxes.id(DeepSORT分配的track_id);
  • 调用osnet_x0_25_msmt17.pt对每个检测框裁剪区域提取128维特征向量;
  • 输出tracks.csv,含frame,id,class,conf,x1,y1,x2,y2,feature_0,...,feature_127。

5.3 哈欠频次统计逻辑:基于track_id的时间窗口聚合

tracks.csv示例:

frame,id,class,conf,x1,y1,x2,y2,f0,f1,... 120,5,yawn,0.82,320,210,410,305,0.12,-0.45,... 121,5,yawn,0.79,322,211,412,306,0.13,-0.44,... 122,5,yawn,0.75,324,212,414,307,0.14,-0.43,...

频次统计Python脚本(可直接运行):

import pandas as pd from collections import defaultdict df = pd.read_csv("runs/track/ha_yawn_test/tracks.csv") # 按track_id聚合连续帧 track_groups = df[df['class']=='yawn'].groupby('id') yawn_events = [] for track_id, group in track_groups: frames = group['frame'].values # 找最长连续序列(哈欠持续时间) diffs = np.diff(frames) split_points = np.where(diffs > 5)[0] + 1 # 帧间隔>5视为新哈欠 segments = np.split(frames, split_points) for seg in segments: if len(seg) >= 3: # 至少3帧连续才计为一次哈欠 yawn_events.append({ 'track_id': track_id, 'start_frame': seg[0], 'end_frame': seg[-1], 'duration_frames': len(seg), 'duration_sec': len(seg) * 0.04 # 假设25fps }) # 统计15分钟(22500帧)内各track_id哈欠次数 df_events = pd.DataFrame(yawn_events) df_events['window'] = (df_events['start_frame'] // 22500) + 1 freq_per_window = df_events.groupby(['window', 'track_id']).size().unstack(fill_value=0) print(freq_per_window)

关键参数说明:diffs > 5表示帧间隔超过5帧(0.2秒)即认为哈欠结束;len(seg) >= 3过滤单帧抖动;22500帧=15分钟(25fps)是DMS行业标准窗口。

5.4 专注度评分系统:融合哈欠、眨眼、头部姿态的加权公式

我们定义专注度分数Attention_Score = 100 - (W_yawn * Y + W_blink * B + W_pose * P),其中:

指标计算方式权重W正常阈值
Y(哈欠频次)15分钟内哈欠次数40≤2次 → 0分,≥5次 → 40分
B(眨眼频率)每分钟眨眼次数(用EAR算法)3012~22次 → 0分,≤8次 → 30分
P(头部姿态)pitch角绝对值均值(度)30≤15° → 0分,≥30° → 30分

实战代码(实时评分):

def calc_attention_score(yawn_count, blink_rate, head_pitch): # 哈欠扣分:线性映射 0→0, 2→0, 5→40, 10→80 y_score = max(0, min(40, (yawn_count - 2) * 13.33)) if yawn_count > 2 else 0 # 眨眼扣分:12~22次为理想,偏离越多扣越多 b_score = 30 * (1 - max(0, min(1, (22 - abs(blink_rate - 17)) / 10))) # 头部姿态扣分:pitch>30°严重低头 p_score = 30 * (head_pitch / 30) if head_pitch > 30 else 0 return 100 - (y_score + b_score + p_score) # 示例:某学生15分钟内 yawn=4, blink=6/min, pitch=35° score = calc_attention_score(yawn_count=4, blink_rate=6, head_pitch=35) print(f"专注度评分: {score:.1f}/100") # 输出: 43.3/100 → 需干预

从那以后我每次部署哈欠检测系统,都强制走一遍tracks.csv的连续帧聚合验证——宁可多花10分钟写脚本,也不信单帧检测的“准确率”。因为真实世界里,哈欠不是快照,是时间切片。希望帮到你。

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

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

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

立即咨询