ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

安全帽检测数据集处理全流程:从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.rarx表示保留完整路径解压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.txt或img_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 系列训练流程走的是 txtUltralytics 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_okTrue) 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], outlinered, width3) 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_okTrue) os.makedirs(dst_lab_dir, exist_okTrue) 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(ftotal{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.yamlpath: /绝对路径/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 datadata.yaml modelyolov8n.pt epochs30 imgsz640 batch16有人会问为什么不直接训 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 张看最低置信度的正确检测。这能直观告诉你模型在什么尺度、什么遮挡比例下开始漏检对判断数据集要不要补小目标样本非常有用。与其等上线后被现场反馈打得措手不及不如提前用这类可视化方法把数据集的短板全部暴露出来。本文还有配套的精品资源点击获取
返回列表