news 2026/9/13 22:40:41

安全帽检测数据集处理全流程:从RAR解压到YOLO训练验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
安全帽检测数据集处理全流程:从RAR解压到YOLO训练验证

简介:安全帽目标检测数据集压缩包面向计算机视觉初学者与工程开发者,聚焦工矿、建筑等高危作业场景下的人员与安全帽识别,可用于训练和评估目标检测模型。压缩包内共19688个文件,包含7571张jpg图像、6058个txt标注与6057个xml标注,及2个缓存文件,整体约803.3MB,可按需划分为训练集与验证集,便于直接用于YOLO、SSD、Faster R-CNN等主流算法。已有1636人学习下载,资源提供了丰富的标注数据,覆盖person和hat两个类别,可支撑从数据准备、模型训练到参数调优的完整流程;txt格式适合快速读取边界框与类别,xml则补充尺寸、角度等详细信息,两者结合便于适配不同框架的数据加载,也方便在验证集上调整参数和检查过拟合。借助这些数据还可进行模型轻量化与边缘部署测试,是智能安全监控系统开发的实用基础数据。

1. 安全帽目标检测数据集 hat-dataset.rar:从压缩包到可训练集的第一步

安全帽检测是智慧工地里落地最频繁的视觉任务。摄像头拍完画面,模型要回答的不是“有没有人”,而是“这个人头上有没有安全帽”——看起来只差一个类别,实际要处理的是遮挡、远距离小目标、逆光、俯视角度这些非常具体的干扰。而这一切的前提,是一份格式统一、类别清晰、标注没毛病的训练数据。hat-dataset.rar 就是这么一类数据包:解压后通常是 images 加 labels 的目录结构,标注打在 txt 或 xml 里。问题在于,实际拿到的压缩包很少干净到可以直接开训,标注格式混用、类别 id 对不上、图片尺寸和标注坐标不同步,这些才是常态。

我拿到这个标题后的第一反应是:真正顺手的数据集处理流程,应该覆盖从解压到能跑通训练的全过程,而不是只停留在“把 rar 解开”。这篇文章就按这个链路来写,从解压命令、目录分析、格式转换,到质量清洗、训练验证,每一步都给出能直接复制的命令和脚本。适合正在训练自己的安全帽检测模型、或者刚下载完类似数据包不知道怎么入手的工程师。读完后你会得到一套可复用的数据集处理思路,而不只是“解开一个压缩包”。

2. 解压 hat-dataset.rar 与目录结构分析:从压缩包到训练集的第一步

2.1 Linux 与 Windows 下的解压命令和参数

rar 格式和 zip 不同,不能用 unzip 直接解,需要 unrar 或 7-Zip。Linux 服务器上常见的安装方式是:

# Debian / Ubuntu sudo apt install unrar # CentOS / RHEL,需要先启用 EPEL sudo yum install epel-release && sudo yum install unrar

安装后进入压缩包所在目录执行解压,三个参数最常用:

unrar x hat-dataset.rar

x表示保留完整路径解压,e则表示把所有文件解到当前目录、不带目录结构。对数据集来说,目录结构本身就是信息,建议用x。如果包内带了密码(有些标注版本会加),在命令后追加-p密码即可。

Windows 环境下用 7-Zip 更顺手,右键菜单里选“解压到 hat-dataset/”就能保持内部目录。需要注意,如果压缩包是分卷(.part1.rar、.part2.rar),必须把所有分卷放在同一目录后再解压第一个文件。

2.2 目录树分析:找出图片、标注与类别清单三件套

解压后第一件事不是急着看图片,而是摸清目录结构。用 tree 命令最快:

tree -L 2 hat-dataset/

常见的安全帽检测数据集目录大致长这样:

hat-dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt └── README.md

也有直接把所有图片和标注平铺在一个目录下的版本,文件命名通常类似img_0001.jpg加同名img_0001.txtimg_0001.xml。看到平铺结构不用慌,后面第 5 章会给划分脚本。

classes.txt 是类别清单,决定标注文件里第一列数字的含义。安全帽数据集的类别体系常见有两种:两类的(0 表示戴了安全帽,1 表示没戴),三类的(0 戴帽,1 没戴帽,2 头)。先确认这一个文件,后面的转换和清洗才不会返工。

标注文件后缀也能透露出格式:.txt大概率是 YOLO 格式(每行class_id center_x center_y width height,坐标是归一化的),.xml大概率是 VOC 格式(Pascal VOC,坐标是绝对像素值)。这两种格式的转换是必做的,因为不同训练框架默认读的格式不一样。

2.3 统计图片尺寸与标注信息:用脚本快速了解数据长什么样

在动手转换之前,先跑一个快速统计脚本,确认图片尺寸是否统一、标注坐标是否在合理范围内。下面这段 Python 只用标准库就能完成:

import os from collections import Counter from PIL import Image image_dir = "hat-dataset/images" label_dir = "hat-dataset/labels" size_counter = Counter() class_counter = Counter() total_boxes = 0 for image_name in os.listdir(image_dir): if not image_name.endswith((".jpg", ".png", ".jpeg")): continue with Image.open(os.path.join(image_dir, image_name)) as img: w, h = img.size size_counter[(w, h)] += 1 base = os.path.splitext(image_name)[0] label_path = os.path.join(label_dir, base + ".txt") if os.path.exists(label_path): with open(label_path) as f: for line in f: parts = line.strip().split() if len(parts) >= 5: class_id = parts[0] class_counter[class_id] += 1 total_boxes += 1 print("图片尺寸分布:", size_counter.most_common()) print("类别分布:", class_counter) print("总标注框数:", total_boxes)

这段脚本做了三件事:统计图片尺寸分布,统计每个类别的标注框数量,统计总的框数。图片尺寸如果不统一,后面训练时虽然 YOLO 会自动做 letterbox 缩放,但尺寸差异过大会影响小目标的表现;类别分布如果严重偏斜,比如“没戴帽”只有几十个框,模型很容易把这一类学成噪声。

统计命令和脚本的输出要对着看,如果发现图片数量和标签数量对不上,先找缺失列表,后面第 4 章专门处理。

3. 标注格式统一:从 VOC 到 YOLO txt 的坐标换算脚本

3.1 为什么数据集的标注格式必须统一

目标检测的数据集标注格式看着五花八门,本质上描述的都是同一件事:一个框。区别只在于坐标系和形状。VOC 用左上角和右下角两个像素点描述框,YOLO 用中心点坐标加宽高描述框,且横纵坐标都除以图片宽高做了归一化。COCO 则用左上角坐标加框宽高,单位是像素。

hat-dataset.rar 里如果同时出现 .xml 和 .txt,说明这是有人从多个来源拼起来的数据包,或者标注工具导出时选了两种格式。训练时不能混着喂给模型。YOLO 系列训练流程走的是 txt,Ultralytics YOLO 的yolo train命令只认 YOLO 格式的标注;而用 Detectron2、MMDetection 这类框架的朋友通常需要 COCO JSON。所以我一般建议:先统一成 YOLO txt,再按需从这里转成 COCO。

3.2 VOC XML 转 YOLO txt 的脚本与公式拆解

import os import xml.etree.ElementTree as ET def convert_voc_to_yolo(xml_path, txt_path, class_map): tree = ET.parse(xml_path) root = tree.getroot() size = root.find("size") img_w = int(size.find("width").text) img_h = int(size.find("height").text) with open(txt_path, "w") as out: for obj in root.iter("object"): name = obj.find("name").text if name not in class_map: continue box = obj.find("bndbox") xmin = float(box.find("xmin").text) ymin = float(box.find("ymin").text) xmax = float(box.find("xmax").text) ymax = float(box.find("ymax").text) # 关键:VOC 的坐标是绝对像素,要归一化且转成中心点+宽高 x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h class_id = class_map[name] out.write(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n") class_map = {"hat": 0, "no_hat": 1, "head": 2} xml_dir = "hat-dataset/annotations" txt_dir = "hat-dataset/labels" os.makedirs(txt_dir, exist_ok=True) for xml_name in os.listdir(xml_dir): if not xml_name.endswith(".xml"): continue base = os.path.splitext(xml_name)[0] convert_voc_to_yolo( os.path.join(xml_dir, xml_name), os.path.join(txt_dir, base + ".txt"), class_map, )

类名转 class id 的映射表是这段代码的核心。class_map 引号里的词组,比如no_hat还是without_hat,要以 classes.txt 里实际写的为准。我见过不少情况是同一份数据里同一个含义的类名有多个写法,转换前先去个重。

归一化坐标公式中有个容易踩的坑:异常数据里 xmax 可能小于 xmin,或者坐标超过图片尺寸,直接除宽高会得到大于 1 的值。这类脏数据后面第 4 章会专门处理,但转换脚本里最好现在就加一层判断,输出超过[0, 1]范围的框到警告日志。

3.3 反向转换的原因:可视化检查标注框

有时候需要从 YOLO txt 转回像素坐标画框,用来检查标注和图片对不对得上。以下脚本读一张图和一个 txt,画完框保存为可视化结果:

import os from PIL import Image, ImageDraw def draw_yolo_boxes(image_path, label_path, output_path): with Image.open(image_path) as img: draw = ImageDraw.Draw(img) w, h = img.size with open(label_path) as f: for line in f: parts = line.strip().split() if len(parts) < 5: continue _, x_center, y_center, box_w, box_h = map(float, parts[:5]) # 反归一化回像素坐标 x_center_px = x_center * w y_center_px = y_center * h box_w_px = box_w * w box_h_px = box_h * h xmin = x_center_px - box_w_px / 2 ymin = y_center_px - box_h_px / 2 xmax = x_center_px + box_w_px / 2 ymax = y_center_px + box_h_px / 2 draw.rectangle([xmin, ymin, xmax, ymax], outline="red", width=3) img.save(output_path) draw_yolo_boxes( "hat-dataset/images/train/img_0001.jpg", "hat-dataset/labels/train/img_0001.txt", "vis/img_0001.jpg", )

画框用的是反归一化公式:中心点乘宽高得到像素中心,框宽乘宽得到像素宽,再减半得左上角。建议跑可视化时,从每个子目录挑 20 张左右抽查,人的眼睛判断“框有没有贴住头”比任何指标都直接。尤其是安全帽这种小目标,框如果偏大把肩部也包进去了,模型学到的特征就不纯粹。

4. 数据质量清洗:训练前必须处理的噪声、空标注与异常框

4.1 数据集质量检查清单:先看这五项再动手

压缩包里解出来的数据,质量大概率参差不齐。常见问题有五类,按会造成的后果排优先级:

问题类型表现对训练的影响
损坏图片打开报错、解码失败训练中断或该图被跳过
空标注文件txt 或 xml 里没有目标框负样本过多,误检率上升
越界坐标框超出图片边界导致 loss 异常或警告刷屏
类别 id 不合法超过 classes.txt 里的类别数训练直接报错
无对应标注有图没标注或有标注没图数据对不上,白白浪费算力

这些问题的排查不复杂,但需要写脚本遍历,不能靠肉眼。下面这段审计脚本可以在解压后马上跑一遍。

4.2 用审计脚本揪出损坏图片、越界框与孤立文件

import os from PIL import Image image_dir = "hat-dataset/images" label_dir = "hat-dataset/labels" num_classes = 3 broken_images = [] empty_labels = [] bad_boxes = [] orphan_images = [] orphan_labels = [] for image_name in os.listdir(image_dir): if not image_name.endswith((".jpg", ".png", ".jpeg")): continue image_path = os.path.join(image_dir, image_name) base = os.path.splitext(image_name)[0] label_path = os.path.join(label_dir, base + ".txt") # 检查图片是否损坏 try: with Image.open(image_path) as img: img.verify() width, height = img.size except Exception: broken_images.append(image_name) continue # 检查标注文件是否存在且非空 if not os.path.exists(label_path): orphan_images.append(image_name) continue if os.path.getsize(label_path) == 0: empty_labels.append(image_name) continue # 检查每个框的坐标和类别id with open(label_path) as f: for line in f: parts = line.strip().split() if len(parts) < 5: continue class_id = int(parts[0]) x_center = float(parts[1]) y_center = float(parts[2]) box_w = float(parts[3]) box_h = float(parts[4]) if class_id >= num_classes: bad_boxes.append((image_name, "class_id 越界")) if x_center < 0 or x_center > 1 or y_center < 0 or y_center > 1: bad_boxes.append((image_name, "中心点越界")) if box_w <= 0 or box_h <= 0 or box_w > 1 or box_h > 1: bad_boxes.append((image_name, "框宽高异常")) # 检查是否有孤立标注文件(有label无image) if not os.path.exists(image_path): orphan_labels.append(label_path) print("损坏图片:", broken_images) print("空标注:", empty_labels) print("异常框:", bad_boxes) print("孤立图片:", orphan_images) print("孤立标注:", orphan_labels)

这个脚本的判定逻辑是:图片读不出来直接记入损坏列表;标注文件存在但字节数为 0 属于空标注;每个框检查类别 id 在不在合法范围内、中心点是否归一化到 [0,1]、框宽高是否为正值。孤立图片是“有图无标注”,孤立标注是“有标注无图”,两类都导致样本对不齐。

跑完脚本如果发现大量空标注,不要急着删文件。在某些数据集的设定里,空标注图片代表“画面里出现了人但没有安全帽”,这类负样本对降低误检是有价值的。如果整个数据集都是正样本(每张图至少一个框),模型会对“没有目标”的场景反应异常,部署时容易在无人区域乱框。

4.3 类别不均衡与清洗策略:删还是补偿

安全帽检测数据集的类别不均衡很典型:戴帽的工人占多数,没戴帽的是少数。如果第 2.3 节的统计结果显示两类比例超过 10:1,直接开训的话,模型会把所有靠近头部的区域都判断成“戴帽”。

常见处理有三条路:一是收集更多没戴帽的样本补充数据;二是用数据增强时对少数类别做过采样复制;三是稍微调低多数类别的 loss 权重。对数据集本身来说,能做的清洗是把重复图片去掉:用文件的 MD5 值去重是最简单可靠的方案。

# 找出重复文件并输出到 dup.txt find hat-dataset/images -type f -exec md5sum {} + | sort | awk '{ if ($1 == prev_hash) print $2; prev_hash = $1; }' > dup.txt

这段命令的思路是:先给每个图片算 MD5,排序后相同哈希值的文件会相邻出现,再用 awk 把重复项挑出来。执行后手动看一眼 dup.txt 再删,比直接跑 rm 安全得多。数据量不大的话,我更习惯把重复文件挪到 backup 目录而不是直接删除,防止误删后需要回滚。

5. 数据集划分与训练前验证:最短路径跑通一个安全帽检测模型

5.1 按 train/val/test 重建目录结构

数据集清洗完成、标注格式统一之后,下一步是按训练框架要求的目录结构重新组织文件。YOLO 系列模型的目录约定是所有图片放在 images 下按 train/val/test 分子目录,同名标注放在 labels 下同样结构。很多数据包解压后是平铺的,所以划分脚本基本是必写项。

import os import random import shutil random.seed(42) src_images = "hat-dataset/images" src_labels = "hat-dataset/labels" dst_root = "hat-dataset-split" splits = {"train": 0.8, "val": 0.1, "test": 0.1} all_images = [f for f in os.listdir(src_images) if f.endswith((".jpg", ".png"))] random.shuffle(all_images) n = len(all_images) train_end = int(n * splits["train"]) val_end = int(n * (splits["train"] + splits["val"])) split_map = {} for i, img_name in enumerate(all_images): if i < train_end: split = "train" elif i < val_end: split = "val" else: split = "test" split_map[img_name] = split for img_name, split in split_map.items(): base = os.path.splitext(img_name)[0] src_img = os.path.join(src_images, img_name) src_lab = os.path.join(src_labels, base + ".txt") dst_img_dir = os.path.join(dst_root, "images", split) dst_lab_dir = os.path.join(dst_root, "labels", split) os.makedirs(dst_img_dir, exist_ok=True) os.makedirs(dst_lab_dir, exist_ok=True) shutil.copy2(src_img, os.path.join(dst_img_dir, img_name)) if os.path.exists(src_lab): shutil.copy2(src_lab, os.path.join(dst_lab_dir, base + ".txt")) print(f"total={n}, train={train_end}, val={val_end - train_end}, test={n - val_end}")

随机种子random.seed(42)这行很关键。同一次划分跑两次结果必须一致,否则你验证了三次模型,每次用的都是不同数据分布,对比结果没有可信度。划分比例按需求调,样本多就 8:1:1,样本少就把 test 并入 val,只划 train/val 两个目录。

5.2 用 YOLO 训练流程跑一个 30 epoch 的冒烟测试

数据划分完毕,用 YOLO 目标检测框架做一次小规模训练验证数据集可用性。先创建 data.yaml:

path: /绝对路径/hat-dataset-split train: images/train val: images/val test: images/test nc: 3 names: ["hat", "no_hat", "head"]

注意 names 的排列顺序必须和第 3 章的 class_map 完全一致。比如 class_map 里{"hat": 0, "no_hat": 1},names 就必须先写 hat 再写 no_hat。顺序错位是训练时最常见的低级错误,模型不会报错,但精度曲线从头到尾都是乱的。

接着跑训练:

yolo train data=data.yaml model=yolov8n.pt epochs=30 imgsz=640 batch=16

有人会问为什么不直接训 300 epoch。数据集检查才刚做完,这一步的目的是验证标注格式、类别 id、目录结构有没有问题。30 epoch 的曲线足够看出数据有没有“学得动”,完整训练留给检查通过之后。观察三个地方:class_loss 是不是在稳定下降、mAP50 有没有逐步爬升、target 图里框的中心点分布是否覆盖了图片各处。如果 mAP50 在 10 个 epoch 后就超过 0.7,说明数据质量不错可以放大模型继续训。

5.3 验证标注与训练结果的两个技巧

第一个技巧是训练前用yolo detect predict或者刚才第 3.3 节的可视化脚本,从 train 目录里随机抽 30 张图,把标注框画出来看一遍,重点检查有没有漏标的安全帽。漏标产生的危害比误标更隐蔽:模型把漏标区域当成背景,反向传播时会朝着“这里不该有目标”的方向优化。

第二个技巧是训练完成后跑预测,把预测置信度阈值调到 0.25,然后专门看 val 目录的图片。注意观察那些“人没戴帽但模型给出 hat 高置信度”的样本,这类误检的根源通常不是模型能力,而是数据里大量负样本(背景里出现的帽子、反射倒影)没有被充分标注。做一轮针对性补充,比盲目调模型参数有效得多。

第二个技巧延伸到部署环节还有个实用做法:把模型的预测框画回原图,按置信度排序取后 20 张看最低置信度的正确检测。这能直观告诉你模型在什么尺度、什么遮挡比例下开始漏检,对判断数据集要不要补小目标样本非常有用。与其等上线后被现场反馈打得措手不及,不如提前用这类可视化方法把数据集的短板全部暴露出来。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 22:33:46

Easy-Vibe 安全思维指南:从攻防原理到上线前的安全检查清单

Easy-Vibe 安全思维指南&#xff1a;从攻防原理到上线前的安全检查清单 【免费下载链接】easy-vibe &#x1f4bb; vibe coding 101&#xff5c;The first course for AI-native product builders. 项目地址: https://gitcode.com/GitHub_Trending/ea/easy-vibe 导读 本…

作者头像 李华
网站建设 2026/9/13 22:30:54

802.3协议解读 02:116章节 200 Gb/s 和 400 Gb/s 网络介绍 II

116.2 200 Gigabit 和 400 Gigabit 以太网子层总结116.2.1 协调子层&#xff08;RS&#xff09;和媒体无关接口&#xff08;GMII&#xff09;&#xff08;1&#xff09; RS&#xff08;Reconciliation Sublayer&#xff0c;协调子层&#xff09;&#xff08;2&#xff09; GMII…

作者头像 李华
网站建设 2026/9/13 22:29:04

高铁上的移动办公室:手机热点上架的连环验证

高铁上的移动办公室&#xff1a;手机热点上架的连环验证 一个高铁上还想上架的卖家自述&#xff1a; 「从北京回杭州的高铁上&#xff0c;我掏出笔记本想把手头三十个品传了。手机开热点&#xff0c;连上&#xff0c;登录&#xff0c;一切正常——好景不长&#xff0c;第三个品…

作者头像 李华
网站建设 2026/9/13 22:25:38

智能家居与物联网实战:每天同一时间开灯为什么越用越别扭?让日落和时钟各管一件事

智能家居与物联网实战:每天同一时间开灯为什么越用越别扭?让日落和时钟各管一件事 [!NOTE] 固定时间容易理解,但季节变化会让开灯时刻逐渐不合适;只用日落又可能遇到阴天和室内遮挡。本课分清墙上时钟、太阳位置与现场照度,用模拟计划和安全提示展示时间自动化的选择方法。…

作者头像 李华