简介:这份安全帽数据集面向从事工业安全监控、智慧工地与计算机视觉方向的开发者及算法学习者,用于训练和验证YOLO目标检测模型,解决施工现场、矿山等场景下工人是否规范佩戴安全帽的识别问题。压缩包共约2000个文件,以6057张jpg图像、6057个xml标注和6058个txt标注为主,另含少量cache缓存文件,整体约608.51MB;图像与双格式标注一一对应,标注涵盖person与hat两类,便于直接用于模型训练与格式转换。目前已有1399人学习下载,适合入门目标检测实战或需要现成数据做迁移训练的人群。借助该数据集,读者可完成从标注解析、YOLO格式转换到模型训练与验证的完整流程,并可通过随机翻转、裁剪、色彩变换等增强手段提升泛化能力,为搭建实时安全帽检测系统提供扎实的数据基础。
1. 拿到 person_hat.rar 之后:安全帽数据集到底能解决什么检测问题
工地上真正难的不是「有没有戴安全帽」,而是「画面里十几个人,谁戴了、谁没戴、谁戴的是反光背心配的黄色帽」。person_hat.rar这类安全帽数据集,核心价值就在于把「人」和「帽子」两个目标绑在一起标注,让模型学会在同一个画面里同时输出 person 和 hat 两类框。它解决的是工地、电厂、隧道口这类场景下的合规巡检问题:摄像头架好,模型跑起来,没戴帽子的框自动报警。
适合谁用?三类人最直接:一是做智慧工地视觉方案的算法工程师,需要快速验证 helmet 检测可行性;二是学生或转行者,想找一个有真实遮挡、有密集小目标的数据集练手;三是已经有一版模型但漏检严重,想换数据重训的团队。这个数据集不是玩具,它通常包含不同光照、不同角度、部分遮挡的样本,正好卡在「能跑通」和「能上线」之间。先别急着解压,下面把从 rar 到可训练格式的整条链路拆开讲。
2. 从 rar 到可训练格式:解压、目录结构与标注格式确认
2.1 解压前先看清 rar 里到底装了什么
很多人拿到person_hat.rar第一反应是双击解压,结果解出来一堆乱码文件名或者嵌套三层目录。血泪经验是:先看压缩包列表,再决定解压路径。Linux 下用unrar l或7z l,Windows 下用 7-Zip 的「查看」功能。重点确认三件事:图片格式是 jpg 还是 png、标注是 xml(VOC)还是 txt(YOLO)、有没有中文路径。
# 列出 rar 内容,不实际解压,先看结构 unrar l person_hat.rar # 如果系统没装 unrar,用 7z 替代 7z l person_hat.rar # 确认无误后解压到指定目录,避免中文路径 mkdir -p /data/helmet_raw unrar x person_hat.rar /data/helmet_raw/逻辑说明:l参数只列目录,不写磁盘,适合先侦察。x参数保留完整路径解压。参数上注意,如果压缩包有密码而你又不知道,不要去找所谓的「rar 密码移除」工具,直接联系数据提供方,这是最省时间的做法。解压后立刻用find统计文件数量,确认图片和标注是否一一对应。
# 统计图片和标注文件数量,判断是否配对 find /data/helmet_raw -name "*.jpg" | wc -l find /data/helmet_raw -name "*.xml" | wc -l # 查看目录层级,确认没有多余嵌套 tree -L 2 /data/helmet_raw如果图片数和 xml 数不一致,说明有脏数据,后面转换会报错。常见情况是多了__MACOSX目录或.DS_Store文件,直接删掉即可。
2.2 VOC 与 YOLO 两种标注格式的取舍
安全帽数据集常见两种标注:Pascal VOC 的 xml 和 YOLO 的 txt。xml 里存的是绝对坐标xmin,ymin,xmax,ymax,txt 里存的是归一化后的class_id cx cy w h。选哪个取决于你用的框架:YOLOv5/v8 系列直接吃 txt,Detectron2 和 MMDetection 更习惯 VOC 或 COCO。我一般会先把 xml 转成 YOLO txt,因为后续做数据增强和划分训练集更方便。
转换前必须确认类别名。安全帽数据集里常见类别是person、hat,有的还带helmet、head、no_hat。打开一个 xml 看<name>标签,把类别列表固定下来。下面是一个标准的 VOC 转 YOLO 脚本,直接可抄。
import xml.etree.ElementTree as ET import os from pathlib import Path # 类别映射,必须和 xml 里的 name 完全一致 CLASSES = ["person", "hat"] CLASS_MAP = {name: i for i, name in enumerate(CLASSES)} def convert_bbox(size, box): """VOC绝对坐标转YOLO归一化坐标""" dw = 1.0 / size[0] dh = 1.0 / size[1] x = (box[0] + box[1]) / 2.0 y = (box[2] + box[3]) / 2.0 w = box[1] - box[0] h = box[3] - box[2] return x * dw, y * dh, w * dw, h * dh def convert_xml(xml_path, out_dir): tree = ET.parse(xml_path) root = tree.getroot() size = root.find("size") w = int(size.find("width").text) h = int(size.find("height").text) lines = [] for obj in root.iter("object"): name = obj.find("name").text if name not in CLASS_MAP: continue # 跳过未定义类别,避免训练时报错 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) bb = convert_bbox((w, h), (xmin, xmax, ymin, ymax)) lines.append(f"{CLASS_MAP[name]} " + " ".join(f"{v:.6f}" for v in bb)) # 写同名txt stem = Path(xml_path).stem with open(os.path.join(out_dir, stem + ".txt"), "w") as f: f.write("\n".join(lines)) if __name__ == "__main__": xml_dir = "/data/helmet_raw/annotations" out_dir = "/data/helmet_labels" os.makedirs(out_dir, exist_ok=True) for f in os.listdir(xml_dir): if f.endswith(".xml"): convert_xml(os.path.join(xml_dir, f), out_dir)逻辑说明:convert_bbox把左上右下坐标转成中心点加宽高,再除以图像宽高做归一化。CLASS_MAP决定类别索引,顺序一旦定了就不能改,否则训练和推理对不上。参数上,xmin等要转 float,有些 xml 里写的是小数。如果某个 xml 没有size节点,说明标注不完整,直接跳过并记录文件名。
2.3 划分训练集与验证集时别踩随机种子的坑
转换完 txt 后,按 8:2 划分 train 和 val。很多人用random.shuffle不固定种子,导致每次跑结果都不一样,调参时根本分不清是模型变了还是数据变了。固定seed=42,并且把划分结果写成 txt 文件,后续训练直接读。
import random from pathlib import Path random.seed(42) # 固定种子,保证可复现 img_dir = Path("/data/helmet_raw/images") all_imgs = sorted([p.stem for p in img_dir.glob("*.jpg")]) random.shuffle(all_imgs) split = int(len(all_imgs) * 0.8) train, val = all_imgs[:split], all_imgs[split:] for name, items in [("train", train), ("val", val)]: with open(f"/data/helmet_{name}.txt", "w") as f: f.write("\n".join(items))参数说明:seed一旦固定,任何人跑出来的划分都一样。sorted保证初始顺序稳定,避免文件系统返回顺序不同导致结果漂移。划分完检查一下 train 和 val 里是否都有 hat 类别,如果 val 里一个 hat 都没有,评估指标会失真。
3. 用 YOLOv8 在本地跑通安全帽检测的最小闭环
3.1 环境安装与数据配置文件写法
YOLOv8 是目前安全帽检测最省事的起点,ultralytics包一条命令装完。注意 Python 版本别低于 3.8,torch 版本和 CUDA 对齐。如果你只有 CPU,也能跑,只是训练慢,建议先用yolov8n.pt小模型验证流程。
pip install ultralytics # 验证安装 yolo checks数据配置文件helmet.yaml必须写对路径和类别名。路径用绝对路径,别用相对路径,否则训练时找不到图。
# helmet.yaml path: /data/helmet_dataset train: images/train val: images/val names: 0: person 1: hat逻辑说明:path是数据集根目录,train和val是相对路径。names的索引必须和转换脚本里的CLASS_MAP完全一致。常见翻车点是 names 写成了helmet但标注里是hat,训练不报错但推理时类别名对不上。
3.2 启动训练与关键参数怎么设
最小训练命令如下,先跑 50 轮看 loss 是否下降。安全帽数据集通常几千张图,yolov8s比n精度高,比m省显存,是性价比最高的选择。
yolo detect train \ data=helmet.yaml \ model=yolov8s.pt \ epochs=50 \ imgsz=640 \ batch=16 \ lr0=0.01 \ seed=42 \ project=helmet_run \ name=exp1参数说明:imgsz=640是安全帽检测的常用输入尺寸,小目标多可以提到 1280,但显存翻倍。batch=16在 8G 显存上比较稳,爆显存就降到 8。lr0=0.01是初始学习率,YOLOv8 默认自适应,但安全帽数据类别少,适当降低能减少震荡。seed=42和划分时保持一致。训练过程中重点看mAP50和mAP50-95,如果 20 轮后 mAP50 还低于 0.3,大概率是标注格式或类别映射错了。
3.3 推理验证与漏检排查
训练完用best.pt跑一张工地图,看框是否合理。下面命令输出带框图片。
yolo detect predict \ model=helmet_run/exp1/weights/best.pt \ source=/data/test_site.jpg \ conf=0.25 \ save=Trueconf=0.25是置信度阈值,安全帽检测建议先设 0.25 看召回,再根据误报调整。如果人戴了帽子但只框出 person 没框出 hat,检查标注里 hat 框是否太小或是否被 person 框完全包含。YOLO 对嵌套框的处理依赖 NMS,iou阈值默认 0.7,可以试着调到 0.5 减少抑制。
4. 安全帽数据集训练避坑:5 个真实翻车记录
4.1 现象:训练 loss 正常下降但 mAP 始终为 0
原因:类别索引错位。转换脚本里CLASS_MAP是person:0, hat:1,但 yaml 里写成了0: hat, 1: person。模型学到的 hat 实际是 person,评估时对不上。
解决:打开一个生成的 txt,看第一个数字是 0 还是 1,和 yaml 逐行核对。最稳妥的办法是转换脚本和 yaml 用同一个类别列表生成,别手写。
4.2 现象:解压后图片能打开但训练报「corrupt image」
原因:rar 解压时部分文件损坏,或者图片是 CMYK 模式,OpenCV 读不了。工地数据经常从不同设备导出,格式不统一。
解决:用 PIL 批量检查并转 RGB。
from PIL import Image import os for f in os.listdir("/data/helmet_raw/images"): p = os.path.join("/data/helmet_raw/images", f) try: img = Image.open(p).convert("RGB") img.save(p) # 覆盖保存为RGB except Exception as e: print(f"坏图: {f}, {e}")4.3 现象:验证集 mAP 很高,但实际工地图漏检严重
原因:训练集和验证集来自同一批视频帧,画面高度相似,模型过拟合到特定背景。安全帽数据集如果按帧随机划分,相邻帧会同时进 train 和 val,造成数据泄漏。
解决:按视频或按时间段划分,同一段视频的帧只进 train 或只进 val。如果数据集没提供视频来源,至少按文件名前缀分组划分。
4.4 现象:小目标 hat 框大量漏检
原因:输入尺寸 640 下,远处工人的帽子只有十几个像素,特征图下采样后信息丢失。
解决:把imgsz提到 1280,或者在数据增强里开启mosaic和copy_paste。YOLOv8 默认开启 mosaic,但copy_paste需要手动加。另外可以增加 P2 小目标检测层,但这会改模型结构,新手先用大尺寸输入顶一顶。
4.5 现象:训练到一半显存爆了
原因:batch设太大,或者workers太多导致内存泄漏。Windows 下workers设 0 更稳。
解决:batch=8,workers=4,开启amp=True混合精度。如果还爆,用yolov8n先跑通流程。
5. 把 person_hat 数据集用出上限:类别平衡与难例挖掘的实操技巧
数据集跑通只是及格线,真正拉开差距的是对难例的处理。安全帽检测的难例集中在三类:逆光、密集人群、帽子颜色和背景接近。我一般会在第一轮训练后,用best.pt对训练集做一次推理,把漏检和误检的图单独挑出来,人工复查标注。这个过程叫难例挖掘,比盲目加数据有效得多。
具体做法:用yolo detect predict的save_txt=True输出预测框,然后写脚本对比预测 txt 和标注 txt,找出 IoU 低于 0.3 的图。这些图要么标注错了,要么确实是难例。标注错的直接修,难例的复制到hard_examples目录,在下一轮训练时通过data=helmet_hard.yaml提高采样权重。
import os from pathlib import Path def iou(box1, box2): # box格式: cx cy w h x1 = max(box1[0]-box1[2]/2, box2[0]-box2[2]/2) y1 = max(box1[1]-box1[3]/2, box2[1]-box2[3]/2) x2 = min(box1[0]+box1[2]/2, box2[0]+box2[2]/2) y2 = min(box1[1]+box1[3]/2, box2[1]+box2[3]/2) inter = max(0, x2-x1) * max(0, y2-y1) area1 = box1[2]*box1[3] area2 = box2[2]*box2[3] return inter / (area1 + area2 - inter + 1e-6) def find_hard(gt_dir, pred_dir, img_dir, out_dir, thresh=0.3): os.makedirs(out_dir, exist_ok=True) for txt in Path(gt_dir).glob("*.txt"): gt_boxes = [list(map(float, l.split()[1:])) for l in open(txt) if l.strip()] pred_path = Path(pred_dir) / txt.name if not pred_path.exists(): continue pred_boxes = [list(map(float, l.split()[1:])) for l in open(pred_path) if l.strip()] # 简化判断:只要有一个gt框和所有pred框IoU都低于阈值,就算难例 for gb in gt_boxes: if all(iou(gb, pb) < thresh for pb in pred_boxes): img = Path(img_dir) / (txt.stem + ".jpg") if img.exists(): import shutil shutil.copy(img, out_dir) break find_hard("/data/helmet_labels", "runs/detect/predict/labels", "/data/helmet_raw/images", "/data/hard_examples")逻辑说明:iou计算两个框的交并比,find_hard遍历每个标注框,如果它和所有预测框的 IoU 都低于 0.3,说明模型完全没学到这个目标,把对应图片复制到难例目录。参数thresh可以按需调整,0.3 比较宽松,0.5 更严格。这个脚本跑完,你会得到几十到几百张难例图,人工过一遍,修正标注后再加入训练集,通常能带来 3 到 5 个点的 mAP 提升。
另一个技巧是类别平衡。安全帽数据集里 person 框通常远多于 hat 框,因为一张图里可能有三个人但只有一顶帽子。这会导致模型偏向 person。可以在 yaml 里加fraction或者用copy_paste增强 hat 类别。我习惯在训练时监控每个类别的instances数量,如果 hat 实例数不到 person 的 1/3,就手动复制含 hat 的图并做轻微旋转、亮度变化,扩充到 1/2 左右。
最后说一个验证方法:别只看 mAP,把模型部署到实际摄像头流上跑一天,统计误报和漏报的时间分布。很多模型在测试集上漂亮,一到下午逆光时段就崩。我现在的习惯是,任何安全帽模型上线前,必须过一遍早中晚三个时段的实拍视频,漏检率超过 5% 就回炉。这个习惯帮我省掉了好几次现场翻车。希望帮到你。
本文还有配套的精品资源,点击获取