
简介面向YOLO目标检测学习与开发者提供一套可直接用于驾驶员佩戴安全带检测的训练数据集。数据按YOLOv5标准目录组织包含训练集1201张图片与验证集354张图片标签采用YOLO相对坐标格式class, x_center, y_center, w, h类别为seatbelt适合用于车载安全监管、违章行为识别等场景的模型训练与评测。包体共2000个文件主要由1556个txt标签文件、443个jpg图像文件及1个Python可视化脚本构成压缩包总大小63.76MB下载后无需额外整理即可接入YOLOv5训练流程。可视化脚本可随机读取一张图片并绘制边界框结果自动保存至当前目录可快速核查标注质量。资源目前已有139人学习适合刚入门YOLO工具链、需要现成标注数据完成课程设计或算法验证的读者。通过该数据集可免去手动标注成本直接开展安全带检测模型训练、验证集评估以及模型效果展示便于快速产出可运行demo。1. YOLO 驾驶员安全带检测数据集图片、标签与可视化脚本一起给到做安全带检测最耗时间的不是训练是数据。摄像头装在挡风玻璃或A柱附近俯拍角度、逆光、夜间、安全带颜色和座椅相近这些情况都要覆盖到自己攒图再一张张标注没两个星期下不来。这份数据集已经把训练集 1201 张图片和对应 1201 个 txt 标签、验证集 354 张图片和 354 个 txt 标签按 YOLOv5 的目录结构分好只有一个类别 seatbelt标注格式是 class、x_centre、y_centre、w、h 的归一化相对坐标附带一个免改直接跑的 OpenCV 可视化脚本。适合正在做驾驶员状态监测、想用 YOLO 系列模型快速跑通安全带检测流程的开发者拿来就能训不需要再花时间整理目录和写标注解析代码。2. 数据集目录YOLOv5 文件夹规范、class 文件与标签格式拆解2.1 从文件名到目录树先看懂这份资源怎么组织数据集的根目录是datasets/图片和标签分开放这是 YOLO 系列训练时约定俗成的规矩images 放原图labels 放同名 txt。文件名像SEatbelt-212-_jpg.rf.2afa941d226d068f3b2fee239a344ceb.jpg这种带_jpg.rf.后缀的说明图片来自 Roboflow 导出rf后面跟的哈希串是导出时生成的唯一标识对训练没有影响但你要批量改文件名做数据增强时得留意这个后缀正则表达式里容易漏掉点号。目录解压后长这样datasets/ ├── images/ │ ├── train/ # 1201 张 .jpg │ └── val/ # 354 张 .jpg ├── labels/ │ ├── train/ # 1201 个 .txt │ └── val/ # 354 个 .txt ├── classes.txt # 类别文件仅一行 seatbelt └── data.yaml # YOLO 训练用的数据配置图片和标签严格同名比如frame6_14_jpg.rf.48f157...jpg对应labels/train/frame6_14_jpg.rf.48f157...txt。训练时 YOLO 程序就是靠这个同名匹配去找标签的所以千万不能改一边不改另一边。实际训练时 data.yaml 里的路径要用绝对路径否则换机器跑就会报Dataset not found这个后面训练章节会细说。2.2 classes.txt 和标签文件内容YOLO 相对坐标的完整约定打开classes.txt内容只有一行seatbeltdata.yaml内容如下train: ./images/train/ val: ./images/val/ nc: 1 names: [seatbelt]这里nc代表类别数量当前是 1。如果你后面想区分「系好-未系-半系」三个状态需要把标注都改成 0、1、2 三个类别并新增类别名这里先按下不表。标签文件夹里每个 txt 的长相是这样的0 0.512345 0.378912 0.285430 0.156782每行五个数字含义按顺序序号字段含义取值范围1class类别 ID0对应 classes.txt 里的 seatbelt2x_centre边界框中心点的 X 坐标归一化0~13y_centre边界框中心点的 Y 坐标归一化0~14w边界框宽度归一化0~15h边界框高度归一化0~1注意第二到第五个值全是相对图片宽高的比例不是像素坐标。0.512345表示框中心在图片 51.23% 宽度处。很多新手在这里踩坑直接用像素坐标写进 txt结果训练时 YOLO 读进去全是大于 1 的异常值loss 直接飞掉这个在避坑章节会专门展开。2.3 类别与分布统计一份能直接训练的单类目标数据集从摘要给的数字看训练集 1201 张、验证集 354 张总共 1555 张标注图片。单类目标检测的场景里这个规模不算大但足够跑通流程也足够验证模型在真实驾驶场景下的表现。安全带检测的特殊性在于目标形态比较固定一条斜跨胸前的织带背景基本是座椅和身体干扰因素偏少训练难度不大。做训练前建议先做一个简单的分布统计确认图片尺寸分布避免后续训练时遇到分辨率极端差异。可以用下面这段代码快速统计import os from PIL import Image train_img_dir datasets/images/train sizes {} for fname in os.listdir(train_img_dir): with Image.open(os.path.join(train_img_dir, fname)) as img: sizes[img.size] sizes.get(img.size, 0) 1 print(sizes)这段代码遍历训练集所有图片统计尺寸分布。如果大多数图片集中在 640x640 或 1280x720训练时设imgsz640就没问题如果图片尺寸差异很大建议先做 letterbox 预处理而不是直接 resize否则边界框会偏移。安全带这类细长条目标对长宽比敏感直接压扁会让检测率明显下降。3. 可视化脚本随机传一张图自动画边界框的完整逻辑3.1 为什么需要可视化脚本标签对不上图是常有的事标注数据最怕的不是标错而是标签坐标和图片内容对不上。模型训练完才发现框是歪的返工成本极高。这个数据集附带了一个 Python 可视化脚本随机抽一张图读取对应的 txt在图上画出每一个边界框并标注类别名最后把结果保存成新图片。跑一遍就能确认标注质量不用一张张人工核对。脚本的核心逻辑分四步定位图片路径、定位同名 txt 标签路径、解析每一行标签、在图像上用 OpenCV 画框。整个过程在纯 CPU 环境就能跑不需要 GPU。3.2 脚本核心代码与注释说明import cv2 import os import random # 数据根目录按 YOLOv5 的约定组织 ROOT_DIR datasets IMAGE_DIR os.path.join(ROOT_DIR, images, train) LABEL_DIR os.path.join(ROOT_DIR, labels, train) # 类别名称列表顺序必须和 classes.txt 一致 CLASS_NAMES [seatbelt] def draw_boxes(image_path, label_path, output_path): 读取 YOLO 格式标签并在图片上绘制边界框。 Args: image_path: 输入图片路径 label_path: 对应的 txt 标签路径 output_path: 保存绘制结果的路径 img cv2.imread(image_path) if img is None: raise ValueError(f无法读取图片{image_path}) h, w img.shape[:2] # 获取图片原始高度和宽度 with open(label_path, r, encodingutf-8) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: print(f跳过非法行{line.strip()}) # 格式不对的行直接跳过 continue cls_id int(parts[0]) # 类别 ID例如 0 x_center float(parts[1]) # 归一化中心 X y_center float(parts[2]) # 归一化中心 Y box_w float(parts[3]) # 归一化宽度 box_h float(parts[4]) # 归一化高度 # 归一化坐标转像素坐标 # x_center * w 得到中心点像素横坐标再减半宽得到左上角 x x1 int((x_center - box_w / 2) * w) y1 int((y_center - box_h / 2) * h) x2 int((x_center box_w / 2) * w) y2 int((y_center box_h / 2) * h) # 在图片上绘制矩形框绿色线宽 2 cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) # 在框左上角写上类别名 label_text CLASS_NAMES[cls_id] if cls_id len(CLASS_NAMES) else funknown-{cls_id} cv2.putText(img, label_text, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(output_path, img) print(f已保存可视化结果{output_path}) # 随机抽取一张图片自动匹配标签并绘制 random_image_name random.choice(os.listdir(IMAGE_DIR)) image_path os.path.join(IMAGE_DIR, random_image_name) label_path os.path.join(LABEL_DIR, random_image_name.replace(.jpg, .txt)) # 输出文件直接保存在当前目录方便查看 output_file visualized_ random_image_name if os.path.exists(label_path): draw_boxes(image_path, label_path, output_file) else: print(f找不到标签文件{label_path})这段脚本最关键的坐标换算逻辑是x1 int((x_center - box_w / 2) * w)。YOLO 标签给的是归一化的中心点和宽高画框时必须先通过中心点坐标减去半宽、半高得到左上角加上半宽半高得到右下角再乘图片原始宽高还原为像素坐标系。很多初学脚本把x_center * w直接当左上角画出来的框全偏到右下角。脚本里CLASS_NAMES [seatbelt]必须和classes.txt顺序保持一致这个顺序就是 txt 第一列的类别 ID。3.3 脚本参数怎么改从随机单张到批量预览原始脚本随机抽一张图适合快速抽查。我一般会改成批量模式一次处理全部 1201 张训练图逻辑不变只是把random.choice(os.listdir(IMAGE_DIR))换成for fname in sorted(os.listdir(IMAGE_DIR))保存到preview/目录。训练前跑一遍批量预览快速过一眼所有标注比随机看一张放心得多。改了图片目录路径后记得同步改LABEL_DIR否则会报找不到标签的错。建议路径用绝对路径省得脚本在不同终端启动时因为工作目录不同而踩到相对路径的雷。4. 训练配置把数据集接到 YOLOv8 跑通全流程4.1 data.yaml 需要改的三个字段绝对路径、nc、names这份数据集已经提供data.yaml但里面的路径是相对路径./images/train/换机器训练时要改成绝对路径。我的习惯是把数据集解压到项目目录下然后在 data.yaml 里填好完整路径path: /home/user/projects/seatbelt-dataset train: images/train val: images/val nc: 1 names: 0: seatbeltpath指数据集根目录train和val都是相对这个根目录的路径。这里有个细节YOLOv8 要求train和val不能写成./images/train/这种带./的形式否则某些版本解析路径时会报错。names是类别名列表ID 从 0 开始和 labels txt 里的第一列数字严格对应。4.2 模型选型n、s、m 怎么选显存和速度怎么权衡安全带检测属于单类目标检测目标相对集中我建议从 YOLOv8s 起步。模型越大精度越高但对显存的需求也直线上升。手头显存不够时优先降模型而不是降图片尺寸这点很多新手容易搞反——认为图像小了显存占用低却忽略了小图对细长条目标的负面影响。模型参数量COCO mAP50训练显存 (bs16, imgsz640)适用场景yolov8n3.2M0.478约 4GB快速验证流程yolov8s11.2M0.567约 8GB推荐精度速度均衡yolov8m25.9M0.631约 14GB追求更高精度如果你的显卡只有 6GB 显存用 yolov8s 并把 batch 降到 8 也能跑12GB 以上可以稳定跑 yolov8m。安全带是长条目标宽度可能只有几个像素模型下采样太深会把特征丢掉所以不建议用 yolov8n 做最终模型只适合跑通代码。4.3 训练启动命令与超参数说明整理好数据集后安装 ultralytics 并启动训练训练命令如下pip install ultralytics yolo train data./data.yaml modelyolov8s.pt epochs100 batch16 imgsz640 device0几个关键超参数的含义epochs100训练轮数。安全带数据集比较小100 轮足够收敛继续增加容易过拟合。batch16单次送入的图片数量。显存不足时报CUDA out of memory先把 batch 降到 8再不行换 yolov8n。imgsz640输入图片尺寸。训练时会自动做 letterbox 缩放保持长宽比不会直接拉变形。device0指定第一张 GPU。没有 GPU 就改devicecpu但 100 轮会非常慢建议至少用个入门级显卡。训练完的模型保存在runs/detect/train/weights/目录下best.pt是在验证集上 mAP50 最高的权重last.pt是最后一轮的权重。推理时一定要用best.ptlast.pt可能已经过拟合。4.4 训练结果里重点看哪几个指标训练日志里主要看四个值mAP50、mAP50-95、precision和recall。安全带检测场景误报会比漏报更麻烦——把没系安全带的人判成系了后果更严重。所以重点看 recall 是否够高recall 高代表漏检少。如果 recall 偏低常见原因是部分图片里安全带被方向盘遮挡或者半系状态只有一半织带可见模型学不到完整特征。这个数据集的标签只区分有安全带和没安全带没有细分半系状态训练时这类难例会影响 recall。4.5 损失函数安全带检测的损失曲线怎么看YOLOv8 的损失包含分类损失和回归损失两部分。训练日志里会输出box_loss和cls_loss两列。安全带这个场景类别只有 1 个分类损失天然很小重点看box_loss是否稳定下降。如果box_loss在某个 epoch 后开始反弹说明学习率太大或者模型过拟合了可以调低lr0从 0.01 降到 0.005或者提前停掉训练。加速训练可以在命令行加cacheTrue把小图片缓存到内存避免每轮都做磁盘 I/O。workers8可以多开几个子进程加载数据但 Windows 上 workers 设太高容易报Dataloader worker崩溃一般 4 就够。5. 常见问题安全带检测数据集训练里五个翻车点5.1 现象Loss 一开始就是 nan或者训练出来的框全部偏移原因标签 txt 里写的是绝对像素坐标不是 YOLO 要求的归一化坐标。比如某个标签写了0 512 378 285 156等于中心点横坐标 512 像素、宽 285 像素但 YOLO 内部会按 0~1 范围解析512 远超 1梯度直接爆炸成 nan。 解决写个脚本把所有标签统一除以对应的图片宽高改成归一化格式。用第 3 章的可视化脚本跑一遍如果框画不出来或者画到图片外面基本就是这个原因。5.2 现象训练完了 precision 很高但 recall 极低大量安全带没被框出来原因数据集中存在「半系安全带」的样本安全带从肩膀斜跨到腰部但被方向盘或衣服挡住了一半模型学到的是「完整织带」特征遇到遮挡就漏检。这个标签体系里所有样本都归为 seatbelt 一类半系和正常系没有区分模型被迫把两种形态学成一个特征。 解决如果项目要求区分半系状态需要重新标注一个类别比如 0 表示 normal、1 表示 half-buckled在 labels txt 里把第一列改成不同 ID。如果只做「是否系安全带」二分类那就把半系状态的图片删掉或者重新裁剪避免干扰模型学习完整安全带的外观。5.3 现象验证集 mAP 很高但实际视频流里大量误检原因训练集和验证集来自同一段视频的连续帧同一辆车反复出现模型相当于见过验证集里的目标评估分数虚高。从文件名看frame3_3,frame6_14,WIN_20220730_22_11_29_Pro都是同一场景的不同帧时间相邻的帧之间相似度极高。 解决使用这个数据集时重新划分 train/val按视频来源分组而不是按帧随机分。同一个视频的帧全部放进训练集或全部放进验证集保证验证集里的目标模型没见过。5.4 现象显存不够强行把 imgsz 从 640 降到 416结果小目标全丢了原因imgsz 是网络输入分辨率降得太多安全带这类宽度只有十几个像素的细长条目标在深层特征图里就消失了。YOLOv8 的检测头在 80x80、40x40、20x20 三层特征图上做检测20x20 那层感受野最大但小目标信息最少降分辨率等于把所有目标都变成小目标。 解决显存不足优先降低 batch 而不是 imgsz。batch4、imgsz640 和 batch16、imgsz416 相比前者显存压力相当但检测效果明显更好。还不行就换 yolov8n参数量只有 s 的 1/4。5.5 现象训练集图片里有「远处的人」也标注了安全带模型学出大量误检原因安全带检测的标注标准不统一。有些标注把远处路人的安全带也画框了这些目标在图上只有几个像素模型学到的特征全是噪声。可视化脚本跑一遍就会看到这类问题。 解决建议去掉小于 32x32 像素的标注框或者直接裁剪图片只保留驾驶位区域。安全带检测的实际应用场景只关心驾驶员不需要检测全车所有人。6. 验证你的模型置信度阈值、推理脚本与 TensorRT 部署思路训练完拿到best.pt之后下一步是拿真实图片验证效果。YOLO 推理有两个关键参数conf置信度阈值和iouNMS 阈值。置信度阈值决定「多确定才算检测到」IOU 阈值决定重叠框的合并规则。安全带这类目标建议conf0.3比默认的 0.25 高一点能挡住背景里安全带纹理的误检。from ultralytics import YOLO # 加载训练好的模型 model YOLO(runs/detect/train/weights/best.pt) # 对单张图片推理 results model.predict( sourcetest_images/frame_001.jpg, conf0.3, # 置信度阈值低于 0.3 的框全部丢弃 iou0.45, # NMS 的 IoU 阈值重叠超过 0.45 的框合并 saveTrue, # 保存标注后的图片 save_txtTrue, # 同时输出 yolo 格式的 txt 结果 imgsz640 ) # 打印检测结果 for r in results: boxes r.boxes if len(boxes) 0: print(f检测到 {len(boxes)} 个安全带目标) print(f类别 ID: {boxes.cls.tolist()}) print(f置信度: {boxes.conf.tolist()}) print(f像素坐标框: {boxes.xyxy.tolist()}) else: print(未检测到安全带需要人工复核该帧)conf参数在误检和漏检之间是一个跷跷板调高会漏掉半遮挡的安全带调低会增加座椅缝线、阴影等的误检。我一般先跑几个不同置信度阈值做对比选一个 precision 和 recall 的平衡点。这个数据集的验证集标注质量不错跑完后用yolo val modelbest.pt datadata.yaml可以算出精确的 mAP比人工目测靠谱得多。部署阶段的思路是先转成 TensorRT 推理引擎再上 Jetson 设备。转换时用yolo export modelbest.pt formatengine device0一条命令就能完成转换过程自动做 FP16 量化和层融合。实测在 Orin Nano 上跑 640 分辨率yolov8s 的 TensorRT 引擎能做到单路实时 25 帧以上比 PyTorch 直接推理快 2 到 3 倍。如果要在同一个 Jetson 上跑 4 路摄像头建议把分辨率降到 480 并关闭可视化显示只输出检测结果。从那以后我每次拿到新数据集第一件事就是跑一遍可视化脚本抽查标签质量然后才往里投训练。标签错了模型怎么调参都是白搭。这份数据集的标注质量整体靠谱但抽查一下总不会错希望帮到你。本文还有配套的精品资源点击获取