ARTICLE DETAIL

资讯详情

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

电力工地人头检测数据集:VOC/YOLO双格式与YOLOv8训练实战

电力工地人头检测数据集:VOC/YOLO双格式与YOLOv8训练实战 简介电力工地场景下的人头检测数据集面向电力行业与工地安全监测场景适合目标检测算法研究者、AI开发者和安防项目人员。数据集共包含7035张实景图片统一以head为标注类别累计26424个目标框并提供Pascal VOC与YOLO两种标注格式可直接用于模型训练、验证和格式切换。压缩包共2000个文件以xml标注文件与txt说明文件为主整体约226.32MB目录结构简洁便于按需加载。目前已有392人学习下载。数据由labelImg工具按矩形框规则标注样本覆盖电力作业、施工现场等典型场景标注准确规范同时附带VOC与YOLO双格式文件免去自行转换的环节适合作为电力工地人头检测、安全帽佩戴分析等任务的数据基础。1. 电力工地人头检测数据集为什么说它和通用人头不是一个物种在电力施工现场做安全监控最常见的需求不是安全帽检测而是先把人找出来。安全帽算法再强如果人头检测这一步把远处戴帽子的工人漏掉后面全白搭。这份电力工地场景的人头检测数据集共 7035 张图、单类别同时给出 VOC 和 YOLO 两种格式解压后可以直接开训不用先做格式转换。它的价值在场景纯度。电力工地的杆塔、脚手架、绝缘子串、高空平台和通用数据里的街道、办公室完全是两回事通用人头模型直接推理误检率偏高。这套数据适合做安全监控、安全帽检测的前置人头模块、电力巡检边缘设备的模型迭代。新手拿它练手老手拿它补场景盲区都合适。2. VOC 与 YOLO 双格式解析目录骨架、字段对应和使用边界2.1 解压后先看目录骨架两套格式怎么共存拿到 .7z 压缩包先别急着解压后直接开训。用 7-Zip 解压后第一步是确认目录结构因为 VOC 和 YOLO 是两套完全不同的组织方式目录层级不一样图片存放位置也不一样。常见做法是压缩包内分两个顶层目录一个走 VOC 规范一个走 YOLO 规范。VOC 侧一般是这套骨架VOCdevkit/ └── VOC2007/ ├── JPEGImages/ # 所有 jpg 原图 ├── Annotations/ # 每张图一个 xml └── ImageSets/ └── Main/ # train.txt / val.txt / test.txtYOLO 侧则扁平很多yolo_dataset/ ├── images/ # 所有 jpg 原图 ├── labels/ # 每张图一个 txt └── train.txt / val.txt # 图片路径列表两边共用同一批图片区别只在标注文件。所以拿到数据后先核对三件事图片数量和 xml、txt 数量是否一致文件名是否一一对应两个目录里的图片是不是同一份。数量对不上多半是解压中断或传输丢文件重新解压前不要开始训练。VOC 和 YOLO 在工程使用上的差别可以简单归纳成下表对比项VOC 格式YOLO 格式标注文件XML含目标类别和像素坐标TXT每行一个目标归一化坐标坐标含义左上角 xmin/ymin、右下角 xmax/ymax中心点 x、y 和宽、高均为 0~1 相对值类别表达标签字符串如 head类别 ID 数字需配合 classes 文件优点可读性好人工可查训练框架直接读取速度快常见问题部分平台导出的 size 不准确归一化小数位不足导致小目标框偏移这份数据集同时给了两种格式意味着训练用 YOLO 侧、人工检查用 VOC 侧两边可以互相印证。比如训练时怀疑某个框不对去 VOC 的 XML 里查原始像素坐标比盯着归一化数字直观得多。提示VOC 的 XML 文件名必须和图片名完全一致YOLO 的 txt 文件名也要和图片名一致这是两种格式共同的硬约束。2.2 VOC XML 和 YOLO TXT 的字段对应关系VOC 格式的核心是 XML 里的 bndbox 四个坐标表示人头的左上角和右下角。一份典型的标注长这样annotation folderJPEGImages/folder filenameworker_0142.jpg/filename size width1920/width height1080/height depth3/depth /size object namehead/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin342/xmin ymin201/ymin xmax411/xmax ymax265/ymax /bndbox /object /annotation这段 XML 表示在 1920×1080 的图上有一个类别为 head 的目标框左上角 x 是 342、y 是 201右下角 x 是 411、y 是 265。坐标单位是像素直接对应图片原尺寸。size 节点里的宽高是换算 YOLO 格式时的分母如果 size 和图片实际尺寸不一致后面所有归一化的框都会偏移。类别名这里写作 head实际压缩包里的类名可能是 head 也可能是 person_head以 xml 的 name 字段和 YOLO 侧的 classes.txt 为准。对应的 YOLO TXT 一行是五个空格分隔的数字0 0.19609375 0.21574074 0.0359375 0.02962963第一个数字是类别 ID单类别数据集里唯一类别是 0后面四个是归一化后的中心点 x、中心点 y、框宽、框高值域都在 0 到 1 之间。换算关系我在第 4 章展开这里先记住结论YOLO 存的是相对坐标离开图片宽高就失去意义VOC 存的是绝对像素坐标单独也能看懂框在哪。另外注意YOLO 侧通常还有一个 classes.txt里面按顺序列出类别名第一行就是 head。如果你的工程里还用了类别名或中文名训练前先打开这个文件确认 ID 对应关系。类别名错位是单类别数据集里最容易忽略的问题虽然只有一个类但也见过有人把 ID 从 1 开始写结果训练时所有标注全部被判成背景。2.3 单类别数据集的场景分布和使用边界7035 张图、1 个类别意味着没有类别不平衡问题但也意味着模型只能回答这是不是人头回答不了这是戴安全帽的还是没戴的。所以在使用上边界要清楚它适合做检测前置不适合直接当安全帽分类器。如果业务目标是安全帽识别常规路线是先用这种人头检测模型把人头框出来再在框内做安全帽的二级分类也就是 two-stage 流程这样比直接训练一个安全帽/非安全帽的检测器可靠得多。这类电力工地数据里常见的画面包括杆塔上的高空作业、地面设备区巡检、脚手架平台、施工通道等距离跨度很大近景人头可能有上百像素远景人头只有二三十像素。拿到数据后不要只看数量我一般会随机抽 100 张做可视化把标注框画在原图上重点看两类情况远景小目标占比高不高、有没有大量被安全帽遮挡的头部。这两种情况直接决定训练参数怎么调是走常规 640 输入还是上 1280 或切图。另外使用前确认压缩包里有没有现成的 train/val/test 划分文件。有就用现成的没有就自己按 8:1:1 划分7035 张大约对应 5628 训练、703 验证、704 测试。划分时注意别让某一个场景的图全部落进测试集否则验证结果会失真这一点的详细处理放在第 5 章 5.5 讲。3. 用 YOLOv8 训练自己的数据集数据配置、参数取舍与结果验证3.1 data.yaml 写法路径、类别与目录命名用 YOLOv8 训练自己的数据集第一步不是敲训练命令而是把数据集的路径和类别定义写进 data.yaml。处理数据集用于 YOLOv8 训练时要先保证 YOLO 环境配置没问题也就是确认 ultralytics 包能正常导入然后才是配置文件。YOLOv8 的训练入口完全依赖这个文件定位图片和标签文件写不对后面全是路径报错。一份典型的配置path: /home/user/head_dataset # 数据集根目录 train: images/train # 训练图片目录 val: images/val # 验证图片目录 test: images/test # 测试图片目录 nc: 1 # 类别数 names: 0: head # 唯一类别文件写好后YOLO 会自动从 images/train 目录推断对应的 labels 目录也就是把路径里的 images 换成 labels、jpg 换成 txt。所以图片目录和标签目录的命名最好保持默认的 images/labels 对不要自己改成 imgs/tags省得去翻源码找映射规则。如果数据集自带的目录名不规范我一般会先做一次目录重命名而不是去改数据配置绕路。注意path 建议写绝对路径或者写相对路径但要保证当前工作目录在数据集根目录下。很多新手翻车就翻在相对路径歧义上YOLO 找不到图片会直接报 FileNotFoundError而且报错信息里的路径是拼接后的排查起来要多花一轮功夫。3.2 训练参数取舍imgsz、batch、epochs 与损失函数YOLOv8 的命令行训练格式很固定我一般这么起yolo train datadata.yaml modelyolov8s.pt \ epochs200 imgsz640 batch16 \ workers8 device0拆开看几个关键参数。model 指定预训练模型yolov8s.pt 是 COCO 预训练权重第一次运行会自动下载。这就是常说的 YOLO 预训练模型下载问题网络环境一般的话建议先去 Ultralytics 的 Release 页手动把 yolov8n.pt、yolov8s.pt 下好放到工作目录避免训练中途下载超时中断。电力工地场景目标不算特别难n 和 s 都够用s 的精度余量更大一些。imgsz 是输入分辨率。电力工地远景人头小640 是基线做第 2 章的可视化时如果发现大量小于 32×32 像素的人头建议直接上 1280代价是显存和训练时间大约翻一倍。batch 受显存约束16 起步显存不够降到 8但低于 8 时 BatchNorm 统计会不稳。我习惯把 YOLO 的损失函数曲线一起看box_loss 震荡得厉害时优先保 batch 而不是保 imgsz。epochs 建议从 200 起步而不是 100。单类别人头检测收敛快但 100 轮往往还没到平台期看 val loss 曲线如果最后还在下降就继续加如果 200 轮后 val 指标不再动就说明收敛了。workers 是数据加载线程数Windows 上建议设 0 避免多进程报错Linux 服务器上设为 CPU 核数的一半左右比较稳。这里多说一句 YOLO 的损失函数YOLOv8 的 loss 由分类损失、回归损失和 DFL 损失三部分加权组成训练日志里分列显示。看曲线别只盯总 loss要分开看 box_loss 和 cls_loss。如果 cls_loss 降得很慢但 box_loss 正常往往是同类目标的表观差异太大比如远景模糊人头和近景清晰人头被强行当成同一个类这时先检查标注质量和小目标占比而不是加 epochs。3.3 结果验证混淆矩阵和 PR 曲线到底看什么训练结束Ultralytics 会在 runs/detect/train 下输出一堆图表最值得看的是混淆矩阵和 PR 曲线。单类别数据集只有两类混淆矩阵是 2×2第一行是真实 head第二行是背景 background。看它的目的是确认背景误检率head 行有一大块落到 background 列说明漏检严重background 行有大块落到 head 列说明误检多需要往训练集里加负样本。PR 曲线更直接。训练日志会打印 mAP50 和 mAP50-95单类别时可以直接看 PR 曲线右上角面积。mAP50 高但 mAP50-95 明显低说明框的位置不够准两个都低说明目标本身难检。电力工地场景常见的是前者因为人头框的标注边界本身就有模糊性安全帽边缘和头发边缘很难严格对齐这时候优先检查标注框是否普遍偏大或偏小而不是调模型。验证命令yolo val modelruns/detect/train/weights/best.pt \ datadata.yaml它会输出 mAP50、mAP50-95 和各类别细分指标。单类别场景下还能顺手看 val 目录里的预测图把框画到原图上人工扫一遍比任何指标都实在。我每次验证完会抽出十几张最难分辨的图确认是标注问题还是模型能力问题这个习惯比单纯看数字管用得多。4. VOC 与 YOLO 格式互转坐标换算、批量脚本与标注校验4.1 坐标换算公式归一化的本质虽然这份数据集已经是双格式但实际工程里经常会拿到只有 VOC 或只有 YOLO 的单格式数据或者自己补充标注时只导出了其中一种所以互转是躲不过的基本功。先记住一个原则YOLO 坐标是归一化的相对值转换时必须知道图片真实宽高。VOC 转 YOLO 的公式x_center (xmin xmax) / 2 / width y_center (ymin ymax) / 2 / height box_w (xmax - xmin) / width box_h (ymax - ymin) / height其中 width 和 height 来自 XML 的 size 节点也可以直接用 PIL 读图获取。反方向 YOLO 转 VOC 就是乘回去xmin (x_center - box_w / 2) * width xmax (x_center box_w / 2) * width ymin (y_center - box_h / 2) * height ymax (y_center box_h / 2) * height这个换算本身不复杂翻车点在于用错 width 和 height。XML 的 size 和图片实际尺寸不一致的情况很常见尤其是从标注平台导出时平台可能把 size 写成固定值。所以我的转换脚本一律用 PIL 重新读图片尺寸不信任 XML 里的 size 字段这是血泪经验换来的。4.2 批量转换脚本从 VOC 目录到 YOLO 标签集批量转换的脚本不难写核心是用 XML 解析库遍历 Annotations 目录对每张图生成对应的 txt。给一个可以直接改用的版本import os import xml.etree.ElementTree as ET from PIL import Image voc_ann_dir VOC2007/Annotations voc_img_dir VOC2007/JPEGImages yolo_label_dir yolo_dataset/labels os.makedirs(yolo_label_dir, exist_okTrue) class_name_to_id {head: 0} # 按压缩包内实际类名修改 for xml_name in os.listdir(voc_ann_dir): if not xml_name.endswith(.xml): continue xml_path os.path.join(voc_ann_dir, xml_name) img_name xml_name.replace(.xml, .jpg) img_path os.path.join(voc_img_dir, img_name) with Image.open(img_path) as img: img_w, img_h img.size tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_name_to_id: continue cls_id class_name_to_id[cls_name] bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h box_w (xmax - xmin) / img_w box_h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) txt_name xml_name.replace(.xml, .txt) with open(os.path.join(yolo_label_dir, txt_name), w) as f: f.write(\n.join(lines))逻辑说明程序遍历 Annotations 里所有 xml对每个 xml 用 PIL 读对应图片得到真实宽高然后解析所有 object 节点提取类别名和 bndbox 坐标按公式换算成归一化坐标每行一个目标最后写成与图片同名的 txt。注意 f-string 里保留了 6 位小数这是为了避免归一化值过长或过短带来的精度损失。参数说明里最值得注意的坑是小数位。人头目标框通常很小如果只保留 4 位小数归一化后的宽度可能从 0.0359 变成 0.0357换算回像素误差接近 2 个像素直接影响小目标回归精度。所以不管脚本还是标注工具txt 里至少保留 6 位小数。4.3 标注校验脚本越界、漏标、错标一网打尽拿到双格式数据集训练前最好跑一遍校验脚本把标注质量问题的风险前置。常见问题集中在三类归一化坐标越界、图片与标签对不上、类别 ID 超出范围。一个实用的做法是把所有 txt 读一遍检查坐标是否在 0 到 1 区间同时检查标签文件列表和图片列表是否一一对应。import os def validate_yolo_labels(label_dir, img_dir): label_names [f for f in os.listdir(label_dir) if f.endswith(.txt)] img_names set(f for f in os.listdir(img_dir) if f.endswith(.jpg)) errors [] for label_name in label_names: img_name label_name.replace(.txt, .jpg) if img_name not in img_names: errors.append(f缺少图片: {img_name}) continue with open(os.path.join(label_dir, label_name)) as f: for line_no, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: errors.append(f{label_name} 第{line_no}行字段数不对) continue cls_id int(parts[0]) vals [float(v) for v in parts[1:]] if cls_id ! 0: errors.append(f{label_name} 类别ID越界: {cls_id}) if any(v 0 or v 1 for v in vals): errors.append(f{label_name} 第{line_no}行坐标越界) if vals[2] 0 or vals[3] 0: errors.append(f{label_name} 第{line_no}行宽高为0或负值) return errors errs validate_yolo_labels(labels, images) print(f发现 {len(errs)} 个问题) for e in errs[:20]: print(e)逻辑说明脚本做四件事——检查每个 txt 是否有对应 jpg、每行是否刚好 5 个字段、类别 ID 是否在合法范围、归一化坐标是否在 0 到 1 之间且宽高为正。跑完输出前 20 条错误能快速定位问题文件。参数说明字段数 5 是 YOLO 标签的硬性要求多一个少一个都说明导出有问题坐标越界常见原因是转换脚本用了 XML 的错误 size宽高为 0 一般是空标注或标注工具 bug。这个脚本我放在项目根目录每次拿到新数据集先跑一遍养成了习惯之后后面省下的排查时间远大于写脚本的时间。5. 常见问题与排查电力工地人头检测的五个翻车点5.1 远景小目标漏检严重现象训练完在测试视频里看近景工人头都能框出来十米以外或画面角落的小人头一个都检不到安全帽颜色和背景接近时更明显。原因电力工地画面普遍是大广角、远距离人头在整幅图里可能只有 20×20 像素默认 imgsz640 时模型下采样后这个目标只占几个特征点信息量不足。本质是数据集里小目标占比高但训练时没有针对小目标做处理。解决首选把 imgsz 提到 1280让目标在输入图上占到更多像素其次对大图做滑窗切图把 1920×1080 的原图切成 640 或 960 的子图训练和推理第 6 章会细讲。也可以改用带 P2 输出层的检测头或在模型中加入小目标注意力结构但对这份数据来说先提高输入分辨率性价比最高。5.2 训练发散loss 突然变成 NaN现象训练到某个 epoch日志里 box_loss 一下子变成 nan接着总 loss 也跟着 nan验证集 mAP 归零后续所有 epoch 全是 nan。原因典型是 YOLO 训练中 BN 崩溃直接原因一般是 batch 太小导致 BatchNorm 统计量不稳或初始学习率过大在低 batch 下梯度爆炸。我在 batch4 时遇到过人头框都很小回归分支的梯度对数值敏感最容易触发。解决batch 至少拉到 8 以上最好 16顺手把学习率从默认 1e-2 降到 1e-3或者直接开 cosine 学习率调度。已经 NaN 的情况下没法断点续跑只能删掉 runs 目录重新训。所以在大规模训练前我会先跑 10 个 epoch 做冒烟测试确认 loss 正常下降再放完整训练。5.3 验证 mAP 高现场视频误检却一堆现象测试集 mAP50 到了 0.95 以上看着很乐观拿到工地真实视频一跑绝缘子、工具包、钢管上的阴影都被框成人头。原因数据集和现场分布不一致。数据集里的负样本太少模型没见过足够多像人头但又不是人头的背景决策边界偏激进。单类别数据集更容易出现这个问题因为 background 是唯一的负类。解决从现场采集没有人的空场景视频抽帧作为负样本加入训练对应 txt 写成空文件让模型学到这些背景不该有输出。这就是 hard negative mining具体流程放第 6 章。通常几百张负样本就能把误检率明显压下来。5.4 安全帽遮挡下人头框偏大或框到帽子现象戴安全帽的工人模型框出来的人头明显比实际头大一圈有的把整个帽檐包进去同一人不同帧的框抖动明显。原因标注标准不统一。有人把头按头发区域标有人连帽子一起标模型拟合了两种标注的均值框自然居中偏大。这是数据质量层面的问题不是模型能力问题调参解决不了。解决拿到数据先做可视化抽查确认标注标准。如果目标是安全帽佩戴检测建议统一按含帽区域标注框住整个帽体如果不含帽子就把帽子区域排除。修改标注后用第 4 章的校验脚本再跑一遍确保没有越界。5.5 train/val 划分不当导致指标波动现象训练日志里 val mAP 波动巨大这轮 0.9 下轮 0.7或者 val 一直很高但换个项目场景就崩。原因划分时把图片随机打散没按场景分层。电力工地数据里不同项目的背景差异很大如果某个项目场景的图大量落在验证集指标虚高全落在测试集指标虚低。单类别数据集指标本来就容易波动划分不当会放大波动。解决按拍摄场景或项目来源分层划分保证 train 和 val 里都有各种距离、各种背景的样本。划分前给每张图打场景标签没有场景标签至少按文件夹分组同一组的图整体划分不要打散。这是我在复现数据集训练时最注意的一步。6. 进阶技巧小目标切图与难例挖掘把 mAP 再提一档6.1 滑窗切图治小目标漏检最直接的手段模型收敛后如果还觉得小目标漏检与其改结构不如先做推理侧切图。把原始大图按固定步长切成子图每个子图独立送检再把子图上的框映射回原图坐标最后做一次全局 NMS 合并。这样小目标在子图里的尺寸占比变大检测率提升明显。切图的核心参数是 patch 大小和重叠率我常用的是 960×960、40% overlap密集人群场景下比 640 更稳overlap 低于 20% 时目标容易正好卡在切缝上被切碎。同时注意推理时要把子图坐标还原成原图坐标子图在原图中的偏移量加上子图内的局部坐标就是原图坐标。这一步写错框会整体平移看起来像模型学歪了其实是坐标还原的问题。6.2 难例挖掘闭环用模型自己找出数据缺口模型训练到一定阶段继续堆 epochs 提升有限更有效的是难例挖掘。流程是用当前最优权重去预测一批没有标注的工地现场图把置信度在 0.3 到 0.7 之间的检测框列为候选难例人工筛选漏检和误检的典型样本补标注后并入数据集重新训练。每轮补充 200 到 500 张两三轮下来 mAP 的提升通常比调两周参数都明显。我在做电力工地人头检测时把切图和难例挖掘配合使用切图解决找不到的小目标漏检难例挖掘解决找错的背景误检两者互补。这份数据集的完整流程就是这样先校验、再分层、切图训练、难例回灌。下载解压后别急着开训先花半小时把第 4 章的校验脚本和第 2 章的可视化步骤走一遍比直接跑训练省事得多。从那以后我每次拿到新的工地人头数据集都会强制走一遍这个流程跑校验、抽 100 张可视化确认标注标准、按项目场景分层划分这套固定步骤帮我避开了所有翻过的车。希望帮到你。本文还有配套的精品资源点击获取
返回列表