简介面向电力设备检测研究人员与工程师这份docx文档围绕变压器检测场景完整呈现VOCYOLO格式红外图像数据集的构成与使用说明可用于目标检测模型训练前的数据理解与评估准备。资源包内含1个docx文件大小约1006KB重点介绍了数据集的格式规范、标注规则及统计信息。已有101人浏览学习。文档指出数据集包含4271张红外图像及对应VOC格式xml和YOLO格式txt标注覆盖ACB空气断路器、CT电流互感器、Connection连接器、LA避雷器、LBS负荷开关、MCCB塑壳断路器、PT电压互感器、VCB真空断路器、body、core等14个类别并列出各类别标注框数其中Connection最多为3961个、core最少为699个总计11896个标注框均由labelImg工具绘制矩形框完成。这些具体统计数据可为电力场景目标检测的类别分布分析和算法选型提供直接参考同时文档也声明不对训练所得模型或权重文件的精度作任何保证使用者需自行评估数据适用性。1. 为什么电力设备红外检测绕不开这份 4271 张的 VOCYOLO 数据集在电力巡检场景里可见光图像对发热缺陷几乎无能为力红外图像才是判断设备过热、接触不良、负荷异常的第一手依据。但目标检测模型要落地缺的不是算法而是带精标的数据。这份电力场景电气设备红外图像变压器检测数据集一共 4271 张 jpg、4271 个 VOC 格式 xml、4271 个 YOLO 格式 txt14 个类别累计 11896 个框覆盖空气断路器、电流互感器、避雷器、真空断路器、柜身等变电站常见部件。严格来说它的“变压器检测”不仅包含变压器本体还延伸到与变压器同场景的高压开关柜、互感器、连接件等成套设备实际训练时能直接当一个多类别红外目标检测的底座数据来用。这份资源最大的价值在于双格式同时给齐VOC 适合跑 Faster R-CNN、SSD 这类需要 xml 的框架YOLO 格式直接喂 YOLOv5/v8 训练不用自己写转换脚本。适合谁做电力设备红外缺陷检测、变电站智能巡检、电气设备状态识别的算法工程师和研究生拿到手就能开始做数据分析和模型训练。下面几章我按实际拆包的顺序来写从目录结构、格式转换、标注质量分析到训练前的检查最后补一组扩增和验证的技巧。2. 先拆目录再谈训练VOC 和 YOLO 格式的对应关系与解析脚本2.1 数据集目录的真实结构下载解压之后典型目录长这样电力红外数据集/ ├── images/ │ ├── 000001.jpg │ ├── 000002.jpg │ └── ... ├── annotations_xml/ │ ├── 000001.xml │ ├── 000002.xml │ └── ... └── annotations_txt/ ├── 000001.txt ├── 000002.txt └── ...严格说不是标准 VOC 的 JPEGImagesAnnotations 双层结构而是自定义的三目录xml 和 txt 各占一个目录。这不影响使用但喂给框架前要么改目录名要么改数据加载路径。我一般不动原目录而是新建一个统一结构的镜像目录避免把原始标注搞乱。还要注意一个不多见的情况txt 里没有 segmentation 信息只有 class_id、cx、cy、w、h 五个字段每行一个目标。xml 则是标准 VOC 结构object 节点下包含 name 和 bndbox。2.2 先读懂一张 xml 再动手annotation folderimages/folder filename000042.jpg/filename size width640/width height512/height depth3/depth /size object nameCT/name bndbox xmin128/xmin ymin96/ymin xmax256/xmax ymax180/ymax /bndbox /object /annotationxml 标注的坐标是像素绝对坐标left-top 和 right-bottom 各一对。做模型训练前最好先确认 size 节点的宽高是否和真实图像一致偶尔会遇到标注时图像分辨率改过但 size 没同步的情况直接信任 xml 的坐标去做目标裁剪会错位。2.3 VOC 转 YOLO 的解析脚本既然数据集同时提供两种格式理论上不用自己转但训练不同框架时——比如跑 Detectron2 需要 COCO跑 YOLOv8 需要 YOLO——经常得交叉验证标注一致性。我用下面这个脚本做校验核心思路是从 xml 重新生成 txt再和原 txt 做数值对比import os import xml.etree.ElementTree as ET CLASSES [ACB,CT,Conection,Connection,LA,LBS,MCCB, MOF,PF,PT,VCB,body,connection,core] def xml_to_yolo(xml_path, txt_path): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASSES: continue # 跳过未知类别 cls_id CLASSES.index(name) xmin float(obj.find(bndbox/xmin).text) ymin float(obj.find(bndbox/ymin).text) xmax float(obj.find(bndbox/xmax).text) ymax float(obj.find(bndbox/ymax).text) # 防止边界越界 xmin max(0, min(xmin, img_w - 1)) xmax max(0, min(xmax, img_w - 1)) ymin max(0, min(ymin, img_h - 1)) ymax max(0, min(ymax, img_h - 1)) dw 1.0 / img_w dh 1.0 / img_h cx (xmin xmax) / 2.0 * dw cy (ymin ymax) / 2.0 * dh w (xmax - xmin) * dw h (ymax - ymin) * dh lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) # 用法对每张图执行 xml_to_yolo(annotations_xml/000042.xml, check_txt/000042.txt)这段脚本做了三个防御性处理类别不在列表里直接跳过、坐标越界时裁剪到图像边界、归一化保留六位小数。跑完检查转换输出的 txt 是否与原始 txt 一致如果大量不一致说明原 txt 生成时用的类别顺序和当前 CLASSES 列表不一致重新按此脚本生成一份 txt 再训练。2.4 训练框架里的文件组织YOLOv8 的 dataset.yaml 需要 images 和 labels 两个目录且 labels 下的 txt 要和 images 里的 jpg 同名。数据集本身满足这个要求但 images 目录和 annotations_txt 目录不在同一父目录下yaml 里要分别写绝对路径或做软链接。我一般这么组织mkdir -p yolo_dataset/images yolo_dataset/labels cp images/*.jpg yolo_dataset/images/ cp annotations_txt/*.txt yolo_dataset/labels/# dataset.yaml path: ./yolo_dataset train: images val: images nc: 14 names: [ACB,CT,Conection,Connection,LA,LBS,MCCB, MOF,PF,PT,VCB,body,connection,core]这里有个细节val 也指向同一批图先跑通流程正式训练时要单独划分验证集不能把训练集当验证集来评估。3. 14 个类别不能直接开训类别分布、大小写差异与标注质量预分析3.1 类别统计藏着哪些问题打开标注统计先看到的是一张不均衡表ACB 94 CT 790 Conection 471 Connection 3961 LA 267 LBS 548 MCCB 1600 MOF 273 PF 56 PT 661 VCB 144 body 380 connection 1952 core 699最大的 Connection 有 3961 框最小的 PF 只有 56 框差距超过 70 倍。按 14 类平均约 849 框来算MCCB 和 Connection 是主流类PF、ACB、VCB 属于极稀有类。最诡异的是Conection 和 Connection 同时存在connection小写 c又是另一个类。光看名称像拼写错误但数据里它们是分别标注的各自的框数和空间分布也有差异。这带来两个实际影响一是在模型评估时如果只保留语义正确的那一类会丢掉一部分标注导致 AP 计算虚高或虚低二是如果合并这些类mAP 数字会变好看但实际部署时模型可能混淆相近类。我的建议是先跑一版 14 类原样训练的模型作为 baseline再看混淆矩阵。如果 Conection 和 Connection 互相混淆严重再考虑合并为单一 Connection 类并重新训练。别在数据准备阶段就擅自改类别等实验结果出来再决定。3.2 图像与标注一致性校验脚本拿到的数据不能盲信尤其是从网上下载的数据集。我习惯先做一轮文件级校验检查三种文件是否一一对应以及 xml 里的 filename 是否与真实文件名一致import os, glob img_files sorted(glob.glob(images/*.jpg)) xml_files sorted(glob.glob(annotations_xml/*.xml)) txt_files sorted(glob.glob(annotations_txt/*.txt)) img_names {os.path.splitext(os.path.basename(f))[0] for f in img_files} xml_names {os.path.splitext(os.path.basename(f))[0] for f in xml_files} txt_names {os.path.splitext(os.path.basename(f))[0] for f in txt_files} print(仅图片:, len(img_names - xml_names - txt_names)) print(仅xml:, len(xml_names - img_names - txt_names)) print(仅txt:, len(txt_names - img_names - xml_names)) print(全对齐:, len(img_names xml_names txt_names))我拆过的不少数据集图片和标注对不齐是常态有的缺 xml有的缺 txt。这套检查 10 秒能跑完4271 张图如果全对得上说明打包时是脚本批量生成的出错概率低。如果对不上训练前必须补齐或剔除否则 sampler 会报错。3.3 空标注与异常框排查另一个容易翻车的地方是空标注图片——图片存在但 xml/txt 里没有任何 object。YOLO 训练时空标签 txt 是合法的表示背景图但 VOC 训练某些框架会报错反过来如果一张图里目标多到 20 个以上红外图像里多半是设备密集排列造成的重叠要检查是否有大量重叠框。import os from collections import Counter empty_files [] num_objs Counter() for xml_file in xml_files: tree ET.parse(xml_file) objs tree.findall(object) num_objs[len(objs)] 1 if len(objs) 0: empty_files.append(os.path.basename(xml_file)) print(空标注文件数:, len(empty_files)) print(每图目标数分布 Top10:, num_objs.most_common(10))如果空标注文件占比超过 1%训练时要么删掉这些图要么作为负样本单独处理。目标数特别多的图要可视化确认是不是标注把多个设备框在一起了——这在红外图像里很普遍设备发热区域连成片标注员画框时容易把一个区域里的多个目标拉通。3.4 类别与英文缩写查全表标注类别名称用的英文缩写完整含义如下类别名中文含义框数稀有度ACB空气断路器94稀有CT电流互感器790中等Conection连接器拼写原文471稀有Connection连接器3961丰富LA避雷器267稀有LBS负荷开关548中等MCCB塑壳断路器1600丰富MOF计量柜273稀有PF功率因数柜56极稀有PT电压互感器661中等VCB真空断路器144稀有body柜身380稀有connection连接点1952丰富core铁芯/核心699中等table 里标红的部分是真正会影响到训练结果的——在数据增强、损失函数加权时56 框的 PF 和 94 框的 ACB 很容易被模型忽略。4. 不均衡与小样本怎么训从损失函数加权到红外数据扩增策略4.1 模型选型和损失函数配置14 类、单类最少 56 框这个数据规模建议直接用 YOLOv8s不要一上来就跑 YOLOv8x——红外图像纹理本身就模糊大模型的收益有限训练时间却翻好几倍。类别不均衡上最省事的方法是给稀有类加 loss 权重# YOLOv8 自定义 loss 权重示例 cls_weight torch.tensor([ 5.0, # ACB 2.0, # CT 3.0, # Conection 0.8, # Connection 3.0, # LA 2.0, # LBS 1.0, # MCCB 3.0, # MOF 10.0, # PF 2.0, # PT 5.0, # VCB 3.0, # body 1.5, # connection 2.0, # core ])权重设置逻辑框数少于 200 的类给 3.0 以上少于 100 的类给 5.0 以上PF 只有 56 框直接给到 10.0。这个权重不是拍脑袋定的是按 log(总框数/类框数) 加一个底数算出来的。但要注意loss 权重拉太高会让模型过拟合到稀有类的少数样本上训练时监控稀有类的 recall如果过拟合明显就降一档。4.2 红外图像专用数据增强红外图像和可见光不一样亮度分布、设备轮廓特征都有特殊性。一般我不会直接用 YOLOv8 默认的 mosaicflip 一套组合拳而是手动改增强参数# ultralytics 配置中的增强段 augment: mosaic: 0.5 # 原默认 1.0红外图拼接后容易产生伪影降到 0.5 flipud: 0.0 # 红外设备有上下位置语义禁止上下翻转 fliplr: 0.5 # 左右翻转安全 hsv_h: 0.01 # 红外图是伪彩色色相扰动要非常小 hsv_s: 0.3 hsv_v: 0.2 scale: 0.5 # 缩放范围收紧避免设备太小 translation: 0.1 # 平移扰动hsv_h 设为 0.01 是血泪经验——我用默认的 0.015 训过一次红外数据集模型把发热区域的伪彩色变化当成了类别特征在测试集上 ACB 的 AP 从 0.82 掉到 0.73。红外热像图伪彩色的色调偏移一点点人眼看不出区别模型却会当成新的特征学进去。flipud 必须关掉变电站设备有上下安装位置语义上下翻转后避雷器和互感器的空间关系完全变了。4.3 小样本增强复制粘贴与 MixUpPF 只有 56 个框靠翻转和缩放扩不出来花。我会对稀有类做 copy-paste 增强把 PF 的目标从原图抠出来贴到没有 PF 的训练图上import cv2, numpy as np def copy_paste_augment(src_img, src_box, dst_img, dst_box_list): 将 src_box 目标贴到 dst_img 中避开已有目标区域。 x1, y1, x2, y2 src_box obj src_img[y1:y2, x1:x2].copy() oh, ow obj.shape[:2] for _ in range(20): # 尝试 20 次随机位置 dx np.random.randint(0, dst_img.shape[1] - ow) dy np.random.randint(0, dst_img.shape[0] - oh) new_box (dx, dy, dx ow, dy oh) # IoU 检查避免和大目标重叠 if all(iou(new_box, b) 0.3 for b in dst_box_list): dst_img[dy:dyoh, dx:dxow] obj return dst_img, new_box return dst_img, Nonecopy-paste 有两个关键点一是只对稀有类做MCCB 和 Connection 本身框多粘贴它们只会加剧类别不平衡二是 IoU 阈值设 0.3 而不是更小红外图像里设备区域像素灰度值接近IoU 太大贴上去后两个设备傻傻分不清楚。另一种更省事的方式是 MixUp把包含稀有类的图和另一张图按 alpha 比例混合标注框同时保留。红外图做 MixUp 效果不错的原因是背景灰度变化平缓混合后不会产生明显接缝。4.4 验证集划分必须覆盖稀有类这个坑我在别的数据集上踩过随机按 8:2 划分训练验证集时PF 类 56 个框全部落进了训练集验证集一个 PF 都没有。训练时 loss 里 PF 权重拉高但验证时 mAP 计算直接忽略这类最终报告里 AP 看起来不错实际部署遇到 PF 就抓瞎。正确做法是按类别分层的划分确保稀有类在验证集里至少出现一次from sklearn.model_selection import train_test_split # 先找所有包含 PF/ACB 的图片 rare_class_files [f for f in img_names if PF in read_xml_classes(f)] # 稀有类图片优先放入验证集 rare_train, rare_val train_test_split(rare_class_files, test_size0.3, random_state42) # 其余图片普通 8:2 划分 normal_files [f for f in img_names if f not in rare_class_files] normal_train, normal_val train_test_split(normal_files, test_size0.2, random_state42)稀有类验证集比例设到 30%不是 20%这是为了给 PF 和 ACB 留出足够的评估样本。代价是训练集里稀有类更少了所以稀有类的增强要在划分之后再决定怎么做——先划分再对训练集中的稀有类做 copy-paste避免增强样本泄漏到验证集。5. 训练前避坑指南目录、类序、归一化三处最容易翻车5.1 现象txt 坐标出现大于 1 的值YOLOv8 训练直接崩打开一个 txt 文件发现某一行写着2 0.832 0.456 1.245 0.378w 的值大于 1明显不是归一化后的正确坐标。原因数据集作者在生成 txt 时可能直接用了 xml 里的像素坐标除以某个固定值但不同的红外图像分辨率不一致固定除数导致部分坐标没有归一化到 [0,1] 区间。解决批量检查所有 txt 文件的范围超出 [0,1] 的坐标用第一节的 xml_to_yolo 脚本重新生成# 检查所有 txt 坐标是否在合法范围 bad_files [] for txt_file in txt_files: with open(txt_file) as f: for line in f: parts line.strip().split() if len(parts) ! 5: bad_files.append((txt_file, 字段数错误)) continue vals list(map(float, parts[1:])) if any(v 0 or v 1 for v in vals): bad_files.append((txt_file, 坐标越界)) break print(异常文件数:, len(bad_files))如果异常文件很多不要手工改直接全部重新生成。5.2 现象训练时 class 索引错位模型学到完全不对的映射YOLOv8 的 dataset.yaml 里 names 顺序必须和 txt 里 class_id 完全对应。txt 里第一行开头的 0 代表 ACB但 yaml 里 names 第一项若是其他类训练时梯度方向直接错乱模型学到的类别映射全部偏移。原因txt 生成的类别索引是以某组顺序排列的而这个组顺序未必和 yaml 里手写的 names 列表一致。尤其是 Conection、Connection、connection 这种拼写相近的类手动写 yaml 时极易排错。解决不要手写 names直接从一个集中配置导入先统计 txt 里出现过的 class_id 的最大值确认和 len(names) 一致max_cls 0 for txt_file in txt_files: with open(txt_file) as f: for line in f: cls_id int(line.strip().split()[0]) max_cls max(max_cls, cls_id) print(最大类别索引:, max_cls, 类别数:, len(CLASSES)) assert max_cls len(CLASSES)5.3 现象红外图是三通道伪彩色但模型把它当灰度处理某些预训练模型尤其是老版 YOLOv5默认输入三通道 RGB红外伪彩图也是三通道能直接训练。但如果你不小心用 cv2.imread 读出来再做了灰度转换通道数变成 1模型权重加载会报 shape mismatch。我拆过项目标注和代码都是对的结果在数据读取阶段把红外图转成了灰度整个模型的色彩特征全废了。解决训练脚本中强制检查通道数并保证不做颜色空间转换img cv2.imread(img_path) assert img.ndim 3 and img.shape[2] 3, 红外图必须是三通道伪彩色5.4 现象红外图像亮度整体偏低数据增强把设备阴影当成负样本红外图像和可见光比对比度低、动态范围窄。标准 YOLOv8 的 hsv_v 增强会把亮度随机拉低结果模型学到的是“亮度低的地方都是背景”真实设备区域反而被忽略。解决把 hsv_v 的扰动范围缩小到 0.1~0.2并且用 CLAHE 做预处理提升局部对比度def clahe_preprocess(img): lab cv2.cvtColor(img, cv2.COLOR_BGR2LAB) l, a, b cv2.split(lab) clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) l clahe.apply(l) lab cv2.merge((l, a, b)) return cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)CLAHE 对红外伪彩图的作用是让设备边缘更清晰但注意 clipLimit 别超过 2.5拉太高会出现光晕伪影模型会把光晕边缘当设备轮廓AP 反而下降。6. 最后的落地技巧用 mAP50-95 细分曲线定位模型弱点模型训完之后不要只看一张总的 mAP 表。红外的设备类别差异大Connection 这种大目标好检出PF 这种小目标在远距离红外图里可能只有十几个像素的宽高视觉上接近噪点。我会在验证阶段输出每个类的 PR 曲线数据然后单独看稀有类的 AP50。具体做法是验证时保存每张图的预测结果和真值用 sklearn 手动计算每个类的 AP而不是只依赖框架输出的最后一行from sklearn.metrics import average_precision_score # pred_scores: 预测置信度, pred_labels: 预测类别, true_labels: 真实类别 ap_dict {} for cls in CLASSES: y_true (true_labels cls).astype(int) y_score pred_scores[pred_labels cls] if (pred_labels cls).any() else [0] ap_dict[cls] average_precision_score(y_true, y_score) for cls, ap in sorted(ap_dict.items(), keylambda x: x[1]): print(f{cls}: AP {ap:.3f})把 AP 最低的三个类拎出来去验证集里可视化它们被漏检或误检的图像判断是目标太小、重叠遮挡还是伪彩色外观和训练集差异大。有针对性的补数据或调 anchor。从那以后我每次拿到新的红外数据集都会强制走一遍「文件对齐检查 → 类别统计 → 坐标范围校验 → 分层划分验证集」这条流水线不在数据准备阶段省时间。这份数据集格式齐、标注量大把避坑点处理好单卡训练 YOLOv8s 约 2~3 小时就能出一个可用的变电站设备检测 baseline希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?