
简介面向电力设备检测研究者与算法工程师这份数据集说明文档系统整理了4271张电力场景红外图像下的变压器检测标注资源。资源以VOC格式xml与YOLO格式txt成对提供覆盖ACB、CT、Connection、LA、LBS、MCCB、PT、VCB等14个常见设备类别类别涉及空气断路器、电流互感器、连接器、避雷器、负荷开关、塑壳断路器、电压互感器、真空断路器等设备并给出每类的矩形框标注数量与总计11896个框的统计信息还注明采用labelImg工具进行画框标注。压缩包内仅含1个docx文件大小约1006KB适合作为目标检测模型训练前了解数据集构成与质量评估的参考。目前已有100人学习对于需要快速核对数据集类别体系、标注分布及格式规范的研究人员来说这份文档能省去逐张浏览图片的整理时间直接基于标注重心规划训练、验证与模型调优方案是电力设备智能巡检与缺陷识别任务中实用的辅助资料。1. 4271张红外图像做变压器检测这个数据集解决什么巡检痛点电力班组每天背着红外热像仪在变电站里转拍下的设备图少则几百张、多则上千张回去靠肉眼一帧帧翻找发热缺陷。这个过程慢且依赖老师傅经验新员工培训半年也未必能准确判断哪处过热该上报。这个标题里的数据集面向的正是“把人工看图变成自动检测”的第一步4271张电力场景红外图像覆盖变压器及周边电气设备的14个类别同时给出VOC和YOLO两种标注格式。算法工程师拿到手就能直接进训练流程不必纠结格式转换刚入门YOLO的电力从业者也能拿它当结构完整、能跑通全流程的练习底座。下面按数据集结构、格式转换、训练配置和踩坑顺序展开。2. 14个类别与双格式标注先把数据集的底细看清2.1 变压器检测为什么绕不开红外图像变压器在运行中因为负载电流、接触电阻和介质损耗产生的热量会以温升的形式先于可见故障暴露出来。红外热像仪能在不停电、不接触的情况下把这种温度差异拍成图像所以电力行业巡检一直把红外作为发现变压器早期隐患的首选手段。可见光相机在这个场景里反而吃亏白天受光照角度影响同一个套管在不同时段拍出来亮暗差很大夜间又得靠补光很多户外站的设备根本够不着。红外图像和可见光图像在数据结构上的差异也很直接。常见红外相机输出的是一张单通道灰度图整张图的对比度低设备轮廓边缘模糊背景里还经常混着太阳反射、地面热辐射和相邻设备的热量干扰。这些特点对目标检测模型的影响是实打实的灰度信息少模型没法靠颜色区分目标边缘模糊边界框的回归难度变大背景干扰强误检概率比可见光场景高出一截。所以拿到这个数据集后第一件事不是急着训练而是先搞清楚图里的目标和背景长什么样再决定预处理怎么做。另一个值得注意的点是红外相机本身的成像机制。探测器响应不均匀、时间漂移等因素会在画面上留下固定条纹或明暗不均匀的底纹行业里通常用两点校正来消除这类影响。数据集如果已经做过校正图像整体会比较干净如果没做训练时就需要在预处理里做背景减除或归一化否则模型很容易把校正条纹当成纹理特征学进去。这一点在后面避坑章节还会专门展开。2.2 14个类别的常见配置与标注粒度“14类别”在电力红外检测数据集里并不是随便定的它通常对应变压器本体及其周边关联设备的检测范围。常见的类别配置大致包括变压器本体、套管、油枕、散热器、高压引线、低压引线、绝缘子串、避雷器、断路器、隔离开关、电流互感器、电压互感器、母线、电抗器这些目标具体清单以你手上的classes.txt或者labelmap为准。也就是说这张表不是我替你补出来的训练前一定先打开数据集的类别文件确认一遍。类别组常见检测目标标注难点变压器本体类油箱、铁芯区域红外下与背景温差小边界不易卡准绕组附属类套管、油枕、散热器套管细长红外里容易漏标连接部件类高压引线、低压引线线缆红外对比度低时有中断保护设备类避雷器、断路器、隔离开关设备密集框之间容易互相重叠测量设备类电流互感器、电压互感器外形相似标注时容易串类其他设备类母线、电抗器、电容器样本数量少是类别不平衡的根源我在看这类数据集时会重点看清两件事。第一是标注粒度同样一个变压器有的数据集把整个油箱框成一个目标有的把套管、油枕、散热器分别框出来这直接影响模型能学到多细的特征。第二是类别之间是否容易混淆比如电流互感器和电压互感器在红外图像里轮廓高度相似如果这两类样本数差不多还好差得多的话模型就会学偏。2.3 VOC与YOLO标注格式逐字段对照数据集同时给VOC和YOLO两种格式是为了照顾两条使用路径VOC格式适合用labelImg这类工具打开回看人工复核标注质量很方便YOLO格式适合直接进训练脚本省去转换步骤。这两种格式最核心的区别是坐标表达方式VOC用图像里的绝对像素坐标YOLO用相对于图像宽高的归一化坐标。一份VOC标注的XML大致长这样annotation filenameIR_000123.jpg/filename size width640/width height512/height depth1/depth /size object nametransformer/name bndbox xmin120/xmin ymin80/ymin xmax480/xmax ymax400/ymax /bndbox /object /annotation同一张图在YOLO格式里是labels目录下的同名txt文件每一行对应一个目标# class_id cx cy w h全部归一化到0-1 0 0.46875 0.46875 0.5625 0.625其中class_id对应classes.txt里的索引顺序cx、cy是框中心的归一化坐标w、h是归一化宽高。换算关系其实就四个公式cx(xminxmax)/2/widthcy(yminymax)/2/heightw(xmax-xmin)/widthh(ymax-ymin)/height。后面第三章的转换脚本就是这四个公式的落地实现。VOC和YOLO格式的字段差异整理成一张表排查问题时会用得上对比项VOC XMLYOLO txt坐标单位绝对像素值归一化浮点数坐标形式xmin,ymin,xmax,ymaxcx,cy,width,height类别标识字符串名字整数索引文件组织每张图一个XML文件每张图一个同名txt文件修改便利性需借助XML工具解析文本编辑器可直接改这里面最容易踩的坑是类别索引错位。VOC里写的是字符串transformer转成YOLO后变成数字0这个0不是按字母顺序排的而是按你传入的classes列表顺序排的。如果classes列表的顺序和训练用的data.yaml里names的顺序不一致模型训练出来预测的类别就是乱的而且这种错乱从损失曲线里看不出来。所以我在跑训练前一定会做一次双格式交叉校验具体做法放到下一章详细说。3. 把VOC转成YOLO格式转换脚本、交叉校验与边界坑3.1 数据集给双格式之后还需要校验吗有人会觉得数据集既然已经同时给了VOC和YOLO格式那直接拿来训练就行不需要再转换。这个想法对了一半如果两份标注严丝合缝确实不用动。但实际场景里我一般会把转换脚本保留下来因为它同时解决另一个问题——给新增数据做标注时标注工具导出的是VOC格式而训练脚本只认YOLO格式。4271张图只是一个起点你后面自己补充的巡检图片早晚也要走这一条路。更重要的是两份格式之间可能存在细微差异。比如标注工具导出的XML是绝对坐标但YOLO txt可能是用另一套工具生成的坐标在归一化时被四舍五入再比如新旧两个版本的标注里某个文件名前缀改了但XML里的filename字段没改。这种差异不会在训练时直接报错而是让模型学得别扭。所以我的固定动作是用一份脚本读XML算出边界框再去读同名txt做数值比对误差超过0.5%就提示人工复核。3.2 VOC转YOLO的Python脚本下面这个脚本既能做格式转换也能配合交叉校验使用。假设你现在有一张红外图IR_000123.jpg对应的VOC标注在annotations目录下YOLO标注在labels目录下转换的核心代码是这类逻辑import xml.etree.ElementTree as ET from pathlib import Path # 类别顺序必须和训练用的data.yaml完全一致 classes [transformer, bushing, conservator, radiator, hv_lead, lv_lead, insulator, arrester, breaker, disconnector, ct, pt, busbar, reactor] def voc_to_yolo(xml_path: Path, img_w: int, img_h: int) - list[str]: tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text if name not in classes: raise ValueError(f未注册类别: {name} {xml_path}) 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) # 归一化前三件事坐标必须非负宽高必须大于0框不能整体越界 if xmax xmin or ymax ymin: print(f丢弃异常框: {xml_path} {name}) continue cx (xmin xmax) / 2 / img_w cy (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{classes.index(name)} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) return lines这段代码的逻辑只有三层。第一层是类别映射classes列表的顺序决定后期YOLO txt里的整数编号所以它必须和data.yaml里names的顺序一字不差否则就会出现上一章提到的类别错位。第二层是坐标换算把绝对像素值转成归一化浮点数六个小数位的精度足够了不要用更多的位数因为模型读标注时并不需要那么高的精度反而会把文件撑大。第三层是异常框过滤像xmax小于等于xmin这种框在标注工具里并不会被阻止但训练时会导致损失变成NaN或者框宽度为负必须提前拦下来。调用时的常见做法是遍历整个annotations目录对每张图读取实际宽高再调用函数并把转换结果写进labels目录下同名txt。图像的宽高可以从XML里的size节点取也可以直接用cv2.imread读取原图我建议以后者为准因为XML里的数值偶尔会被漏填或者填错。3.3 转换后的验证画框回看与坐标还原转换脚本写完后不能只看txt能不能生成必须把归一化坐标还原成像素坐标在原图上画框回看一次。这一步能发现三种问题框位置整体偏移、框和红外目标没贴合、类别标签串号。下面是一段常用的可视化验证代码import cv2 from pathlib import Path def draw_yolo_boxes(img_path: Path, txt_path: Path, class_list: list[str]): img cv2.imread(str(img_path)) h, w img.shape[:2] with open(txt_path, r, encodingutf-8) as fp: for line in fp.read().strip().splitlines(): cid, cx, cy, bw, bh line.split() cid int(cid) cx, cy, bw, bh map(float, (cx, cy, bw, bh)) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_list[cid], (x1, max(y1 - 5, 20)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1) out_path Path(verify_output) / f{img_path.stem}_check.jpg cv2.imwrite(str(out_path), img) print(f已生成: {out_path})验证时建议把所有标注框叠到一张图上看而不是单张看。因为单张看很难发现“这个框偏了3个像素”的问题叠到同一张图上很多边界框在目标边缘的位置关系会一目了然。我在实际项目里还会顺手统计一下框的宽度高度分布看看是不是存在大量宽度接近整图宽的异常框那种框一般是标注时把背景也框进去了。3.4 这里最容易翻车的三个边界情况第一是文件名后缀不一致。VOC标注的filename字段写的是IR_000123.jpg但图片实际文件名可能是IR_000123.JPGWindows和Linux之间大小写一混脚本就找不到对应关系。我的处理是统一转成小写再去做字典匹配。第二个是classes列表漏项标注时偶尔会把breaker拼成breker转换脚本遇到未注册类别必须直接报错不要静默跳过否则这一张图的标注就丢了。第三个是图像宽高填错XML里width和height写反了转换出的框位置就会偏这类错误靠画框回看能很快抓出来。4. 用YOLOv8训练自己的变压器检测模型数据划分与关键参数4.1 先按设备ID划分数据集别用随机划分把4271张图分成训练集和验证集看似随机抽样就行但实际上这里有一个典型的翻车点这些红外图像很可能是按时间序列连续拍摄的同一个变压器可能拍了十几张甚至几十张。如果随机划分同一台设备的图片会同时出现在训练和验证里模型相当于见过答案再考试验证精度会虚高换到真实巡检场景立刻露馅。我一般会先按文件名里的设备ID字段做分组。比如文件名约定是T01_frame_001.jpg那T01就是一个设备组划分时必须保证同一个设备组的所有图片全部进训练集或全部进验证集不能拆开。划分比例常见做法是85%设备组进训练15%进验证也就是大约4271张图分下来训练3600张左右验证670张左右。import random from pathlib import Path random.seed(42) image_files sorted(Path(images).glob(*.jpg)) # 按设备ID分组约定文件名以设备ID开头例如 T01_frame_001.jpg groups {} for f in image_files: device_id f.name.split(_)[0] groups.setdefault(device_id, []).append(f) device_ids list(groups.keys()) random.shuffle(device_ids) val_device_ids set(device_ids[:int(len(device_ids) * 0.15)]) train_files [f for dev in groups for f in groups[dev] if dev not in val_device_ids] val_files [f for dev in groups for f in groups[dev] if dev in val_device_ids] print(f训练设备组 {len(device_ids) - len(val_device_ids)} 个图片 {len(train_files)} 张) print(f验证设备组 {len(val_device_ids)} 个图片 {len(val_files)} 张)这个脚本的关键点是random.seed固定保证每次重跑划分结果一致。实际工作中改分组规则比改脚本逻辑更常见比如有的数据集文件名里不带设备ID那就需要按拍摄信息或者EXIF信息手动分这种情况我会先做一张设备清单确认没有设备跨集合后才继续往下走。4.2 目录结构和data.yamlYOLOv8训练自己的数据集时目录结构直接决定训练脚本能不能找到标注文件。标准做法是建立images和labels两个目录下面再分train和val子目录两边的图片和同名txt标注一一对应。对于只用txt标注的常规YOLO流程data.yaml里的路径配置也很关键推荐使用绝对路径或者相对于yaml所在目录的路径避免在别的机器上跑训练时还要改一遍配置。dataset/ ├── images/ │ ├── train/ # IR_000123.jpg ... │ └── val/ # IR_000456.jpg ... ├── labels/ │ ├── train/ # IR_000123.txt ... │ └── val/ # IR_000456.txt ... └── data.yamldata.yaml的内容就两块核心信息路径和类别名。path: /data/infrared_transformer train: images/train val: images/val names: 0: transformer 1: bushing 2: conservator 3: radiator 4: hv_lead 5: lv_lead 6: insulator 7: arrester 8: breaker 9: disconnector 10: ct 11: pt 12: busbar 13: reactor写data.yaml时的第一个检查点是names的索引顺序必须和转换那一步的classes列表一致。第二个检查点是train和val的路径写法如果写成images/train这种相对路径它是以yaml文件所在目录为基准解析的如果直接给绝对路径换机器时要改。我一般用绝对路径写在自己的机器上同时注释掉相对路径方便切换。4.3 训练命令、损失函数与参数选择目录和yaml准备好之后训练命令本身很简短yolo detect train \ modelyolov8s.pt \ datadata.yaml \ epochs200 \ imgsz640 \ batch16 \ patience30 \ hsv_h0 hsv_s0 hsv_v0 \ degrees0 scale0.3 translate0.1 \ fliplr0.5 mosaic0.5 \ workers4这行命令里有几个参数是面向红外图像专门调的。imgsz640是按大多数红外图默认分辨率来的如果你的图里目标本身很小比如套管只占几十个像素那就得把imgsz调成1280代价是显存占用和训练时间都翻倍。batch16是常见显存的稳妥值显存低于12G就降到8。patience30表示验证集指标连续30轮不提升就早停4271张图的数据量跑200轮一般不需要等满系统会在100轮左右自己停下来。损失函数在这个过程里是最容易被忽略的一环但恰恰是排查训练问题的第一线索。YOLOv8的损失函数由三块组成回归用的CIoU损失、分类用的BCE损失、还有处理边界框分布用的DFL损失。如果模型预测的框位置偏移但类别判断准确说明CIoU和DFL这两块的权重或学习率不合适如果类别乱判但框贴得很准问题往往出在类别不平衡上而不是损失函数本身。很多人一上来就怀疑损失函数权重有问题实际先用数据检查会更靠谱。数据增强参数对红外图像的影响也很大。默认的HSV增强是给彩色图设计的红外图只有灰度hsv_h、hsv_s、hsv_v这组参数要设成0只保留几何增强。否则模型会在灰度图上接收到毫无意义的颜色扰动训练损失忽高忽低。degrees0是因为细长的套管和引线对旋转特别敏感旋转增强会让框和目标的贴合关系变得不稳定。mosaic增强我一般会保留但把概率降到0.5因为红外图背景比较简单过强的拼图增强会让模型学到错误的背景分布。5. 避坑指南训练电力设备红外模型的5个翻车场景5.1 验证集mAP虚高设备级数据渗漏现象训练过程中验证集的mAP50达到0.85以上但拿这个模型去测试一段新拍摄的红外巡检视频检测框乱跳套管的检出率比训练时低一大截。原因训练集和验证集是随机划分的同一个变压器的时间序列帧同时出现在两边。红外图里同一设备在不同帧的差异很小模型在验证集上“记住”的其实是设备本身的特征而不是泛化出来的类别特征。解决按设备ID分组划分数据集确保同一个设备的所有图片只进入一侧。如果原数据文件名没有设备ID就先用拍摄时间或者录像片段做设备分组再跑划分脚本。5.2 转换脚本报未注册类别classes映射错位现象voc_to_yolo脚本运行到一半抛ValueError提示某张XML里出现train或test之类的名字。原因数据集的XML里存在一个没写进classes列表的类别名或者同一类目标在不同文件里写了两种拼写。更隐蔽的一种情况是classes列表的顺序和标注工具里的顺序不一致脚本不报错但生成的数字编号错位。解决先全量扫描所有XML文件里的name字段去重再和classes列表比对。我一般会在转换脚本里加一段自动统计把所有出现的类别名打印出来人工确认一次后顺手把这个统计输出保存成类别清单训练前再和data.yaml里的names做diff。5.3 误检出条纹伪影红外图像两点校正的残留噪声现象模型在背景区域频繁输出高置信度检测框框里没有任何设备仔细看原图会发现是一个淡淡的竖直条纹或固定亮带。原因红外相机在两点校正过程中会引入固定条纹噪声虽然人眼觉得不明显但在卷积网络的感受野里这种条状结构很容易被当成目标边缘特征。如果数据集里这类条纹没有在预处理阶段处理掉模型就会学出一个“条纹就是设备边缘”的错误映射。解决在训练前对每张图做均值减除背景的处理或者用中值滤波配合归一化把条纹压下去。这里要控制强度过度处理会把变压器本身的微弱热特征一起抹掉常见做法是先统计一批图的灰度直方图再做线性拉伸。5.4 少数类AP不到0.1类别极端不平衡现象整体mAP50看着还行但按类拉出来看电抗器、电容器的AP50不到0.1而变压器的AP50有0.9。原因数据集本身存在天然的长尾分布变压器本体是大目标且样本多电抗器和电容器是小目标且样本少。模型倾向于把头部分类学好因为这是降低总损失的捷径。解决先按类统计样本数找出所有少于100个框的类别。对这类目标考虑复制粘贴增强或者用裁剪图块单独训练小模型不要指望在整图训练里靠损失权重硬拉。更实际的方案是把样本特别少的类别合并成一个大类或者干脆在训练时对这类样本做重复读取过采样。5.5 训练损失不降照搬可见光模型的增强策略现象训练过程中cls_loss持续下降但box_loss几个epoch后就不再动甚至来回抖动训练集上的输出框位置始终对不齐设备轮廓。原因训练配置里开了默认的HSV和随机旋转等增强参数。红外图是单通道的HSV变换会给灰度图引入无效的颜色扰动随机旋转对细长套管目标又特别敏感框和目标的贴合被增强规则反复破坏。解决把degrees、hsv_h、hsv_s、hsv_v这些增强参数全部置零重新跑20轮先确认基线损失能降下来。然后再逐步打开mosaic和scale每开一个增强跑一遍验证集观察mAP50是否有提升没有提升就保持关闭。这个排查顺序能快速定位是增强问题还是模型结构问题。6. 从mAP到部署评估、置信度阈值调整与一个验证习惯训练完成后我习惯先看验证集的混淆矩阵而不是总mAP数字。红外图像的目标之间外形相近电流互感器和电压互感器这类容易串类混淆矩阵能把这种错误直观暴露出来。接着对每个类别单独查AP50找出拖后腿的少数类这一步决定你是直接上线还是回头补样本。置信度阈值也要重新标定。红外检测场景下漏检比误检更危险因为巡检报告漏掉一个过热点可能直到设备故障才被发现。所以线上推理的conf阈值一般会比默认0.25调低到0.15再把NMS的iou阈值从默认0.45调到0.35让相邻的重复框合并得更保守。具体数值要拿一段没参与训练的真实巡检视频实测不要拿训练集的指标硬套。部署端如果要上视频流处理认真做一次耗时压测比纸上算算靠谱得多。把模型导出成ONNX或TensorRT之后在目标机器上跑真实的红外视频帧观察推理耗时分布和解码占用。只凭理论算力推算一路、几路流能不能跑满帧率往往会栽在显存、解码和预处理上实测数据才有参考价值。这些经验归纳起来就一个习惯每次调参后我都拿同一段固定巡检视频做盲测不与训练集、验证集混在一起测出来的指标才敢写进报告。红外数据集的价值不在于标注数量的绝对值而在于能不能把“看到过热”变成“定位设备并报警”。希望这个方向的尝试能帮到你也祝你的模型在现场少翻几次车。本文还有配套的精品资源点击获取