简介这份数据集面向电力设备巡检与目标检测算法开发者提供变电站红外场景下的电压电流互感器等设备标注样本可直接用于训练YOLOv5/YOLOv8、Faster R-CNN等主流检测模型。包内共2000个文件以VOC格式xml标注、YOLO格式txt标注和jpg红外图像为主要类型整体压缩包大小约32.75MB标注由labelImg完成。数据涵盖水平隔离开关、垂直隔离开关、断路器、避雷器、TC电流互感器、TP电压互感器共7个类别总标注框1715个其中TC框数595、TP框数685其他类别从10到262不等不同类别样本量差异明显适合练习如何处理类别不平衡问题。图片文件名以firc_bdz_编号命名便于批量划分训练集与验证集。已有551人学习下载适合需要标准VOC/YOLO双格式数据集进行模型训练、格式转换或目标检测算法比较研究的电力视觉方向开发者使用。1. 变电站红外图像里的电压电流互感器检测889张7类标注能做多少事电压电流互感器是变电站里最需要定期红外测温的设备但巡检拍回来的热像图靠人眼一张张看既慢又容易漏夜班或雨后更是折磨。这个标题里的数据集瞄准的正是这个问题889张变电站红外图像7个类别以电压互感器PT、电流互感器CT为主同时给出VOC的xml标注和YOLO的txt标注整体打成一个7z压缩包。它解决的核心诉求是让没有条件自己下场带电采集红外数据的团队也能直接起步训练一个变电站设备红外目标检测模型再接到巡检流程里。适合两类人一类是电力巡检平台或边缘检测盒子的一线算法工程师另一类是刚入门YOLO、想拿真实工业数据练手的新手。但要先说清楚889张对深度目标检测是偏小的样本量想直接用它是能跑通想直接覆盖各种角度和天气那会翻车。2. 红外图像和可见光的检测逻辑不一样PT/CT在热像图里靠什么被认出来2.1 PT和CT在热像图里的热特征检测目标是“过热点”而不是完整轮廓红外图像是单通道温度数据经过映射得到的常见输出是伪彩色图或灰度图。很多人拿到手习惯性当成普通照片做预处理这是第一个认识上的偏差。可见光检测里模型大量依赖颜色、纹理、明暗对比而这些在热像图里全部变了语义亮白色不再是反光而是高温红色区域不代表物体本色而是温度最高的部位。所以用YOLO训练这类数据时模型真正在学的是“设备轮廓 温度分布形态”两者缺一不可。电压互感器PT容量小、发热量低在热像图里往往是一个均匀温升的柱状或罐状轮廓电流互感器CT通流大连接点和线夹在负荷电流下会形成明显的局部过热点。实际巡检图中同一个间隔里往往并排装着PT和CT靠纯轮廓去分并不容易反而是“过热点落在设备哪个部位”提供了重要线索。因此做格式转换、做数据增强之前先想清楚这一点标注框框住的到底是整个设备还是设备上那个发热异常的区域这会直接影响后面的训练效果。2.2 VOC与YOLO两种标注格式的换算坐标从哪来、到哪去Pascal VOC格式的标注存放在Annotations目录下每个xml文件的bndbox节点给出xmin、ymin、xmax、ymax四个绝对像素坐标左上角为原点。YOLO格式则每张图对应一个同名txt每行是“类别索引 x_center y_center width height”四个坐标值全部归一化到01之间。这个数据集两种都给了省掉了写转换脚本这一步但你要清楚它们的对应关系否则后面自己扩展标注或做数据增强时很容易懵。VOC转YOLO的标准换算公式是# VOC的xmin,ymin,xmax,ymax - YOLO的x_center,y_center,width,height img_w 640 # 实际值从图片读取 img_h 640 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这里最容易出错的不是公式本身而是单位xml里的坐标是像素坐标YOLO要的是归一化坐标如果你把图片宽高填错或者把xmax-xmin当成除以2再除以图片宽框就全飘了。常见错误是写成x_center xmax - xmin / 2 / img_w运算优先级一错结果完全不对。另一个坑是VOC的坐标有的标注工具从1开始计数YOLO归一化默认从0开始虽然一个像素的误差通常不影响训练但转回来做验证时会有1像素偏移强迫症最好对齐。反过来YOLO转VOC时xmin int((x_center - width/2) * img_w)算完要做clip不能小于0也不能大于图片宽高。很多人在这一步懒得clip最后画框时目标贴着边缘就画出了图片边界。2.3 7个类别怎么映射到YOLO类别索引先理清names再动手训练YOLO标注txt每行第0列是类别索引必须从0开始连续编号不能跳号。很多人习惯了COCO的80类有人把类别索引写成5、写成10模型训练时不报错但预测结果里类别和框就全错位了。这个数据集声明有7类以PT和CT为主实际类别名称以你解压后看到的Annotations里的类名为准。我建议拿到手第一件事不是训练而是把类名列表提取出来排好序生成一个固定的7行names文件。一个稳妥做法是扫描所有xml按出现顺序或字母序收集类名然后写进data.yaml的names列表里。要注意顺序一旦定了后续所有标注、训练、评估都必须沿用同一套顺序。如果先用了A顺序训练了一半再调整names顺序那前面的权重全部作废。因为VOC的xml里类名是字符串而YOLO的txt里是整数字符串排序和整数索引的对应关系只取决于你最初怎么映射的这个映射关系就是整个项目的“锚”建议用git把names文件锁定住。3. 把889张图的7z压缩包变成可训练的数据集解压校验与目录组织3.1 用7z命令解压并校验完整性命令行比图形界面更能暴露问题拿到手是.7z压缩包解压本身不难但完整性和正确性校验很容易被跳过。我见过有人解压到一半报错以为是文件损坏直接删了重新下其实可能是下载时丢包。所以第一步永远是先测试压缩包完整性再解压。# 先测试压缩包完整性这一步很快 7z t substation_infrared_889.7z # 测试通过后再解压-o指定输出目录-y跳过确认 7z x substation_infrared_889.7z -o./substation_data -yLinux下需要先安装p7zip-fullWindows下用7-Zip的命令行版本路径要写成7z.exe的完整路径。这里有个血泪经验不要用系统自带的tar去解.7ztar不支持这种格式报错信息会让你误以为是压缩包损坏。另外如果你拿到的包是分卷压缩.7z.001、.7z.002这种只需要对001执行解压命令后面的分卷会自动读取。解压完成后用find统计一下图片数量和标注数量应该和889张对得上。find ./substation_data -name *.jpg | wc -l find ./substation_data -name *.xml | wc -l数字对不上说明传输过程有丢包或压缩包本身不完整这时候不要继续往下做否则后面训练时某些图片读不出、某些标注缺失排查成本高得多。3.2 图片与标注配对检查三个硬检查必须在训练前跑一遍解压完不要急着配data.yaml先用脚本检查图片和标注是否一一对应。这个数据集同时给了VOC和YOLO格式意味着每张图应该对应一个xml和一个txt三者的文件名主体必须一致。常见的损坏情况xml文件名和jpg不一致、txt里某一行类别索引越界、归一化坐标出现大于1的数。这些都是能提前用脚本筛出来的。import os from pathlib import Path root Path(./substation_data) imgs {p.stem: p for p in (root / JPEGImages).glob(*.jpg)} xmls {p.stem: p for p in (root / Annotations).glob(*.xml)} txts {p.stem: p for p in (root / labels).glob(*.txt)} # 硬检查1三个集合的键必须完全一致 missing set(imgs) - set(xmls) - set(txts) print(缺标注的图:, missing) # 硬检查2txt里的类别索引必须在0~6之间 for stem, txt in txts.items(): for line in txt.read_text().strip().splitlines(): cls int(line.split()[0]) if not (0 cls 6): print(f{stem} 类别索引越界: {cls}) # 硬检查3归一化坐标必须在0~1范围内 for stem, txt in txts.items(): for line in txt.read_text().strip().splitlines(): parts list(map(float, line.split())) if any(v 0 or v 1 for v in parts[1:]): print(f{stem} 坐标越界: {line})这段脚本的逻辑很简单但价值很高。第三项检查尤其能筛出那些标注时图片尺寸和实际尺寸不一致导致的问题xml里标注的坐标基于原始分辨率如果后期缩放过图片但没有同步缩放标注归一化后坐标就会超出0~1。遇到这类问题不要手动改一两个文件写脚本统一处理才是正路。3.3 按采集场景切分训练/验证集889张红外图不推荐直接随机划分这是小样本数据集训练最容易踩的隐坑。红外巡检图像的采集方式通常是手持热像仪沿既定路线走一圈同一设备的不同角度、连续帧之间高度相似。如果随机按8:2划分很可能同一设备的同一轮拍摄画面同时出现在训练集和验证集里模型其实是“记住了”而不是“学会了”验证集mAP虚高换到新场景立刻现原形。正确做法是按采集批次或设备ID分组切分。具体到这个数据集你可以先看图文件名很多巡检数据集的命名里含点位编号或日期段按这些字段分组保证同一个设备在同一次巡检里的连续帧全部进同一个集合。如果文件名看不出分组信息有一个土办法对图片做感知哈希聚类把高度相似的帧归为一组再切分。import os, shutil, random from collections import defaultdict groups defaultdict(list) for f in os.listdir(images): # 假设文件名按 station_A_20240101_001.jpg 格式命名 parts f.split(_) group_key _.join(parts[:3]) # 用站点日期做分组 groups[group_key].append(f) train_files, val_files [], [] for key, files in groups.items(): random.shuffle(files) split int(len(files) * 0.85) train_files.extend(files[:split]) val_files.extend(files[split:])889张图按85:15切大约能拿到750张训练、140张验证量不大但分布更真实。如果条件允许还可以用5折交叉验证跑一遍看模型在不同划分下的稳定性再决定最终用全量训练还是留一部分做验证。4. 用YOLOv8训练自己的红外数据集配置、命令与损失函数层面的取舍4.1 先写对data.yaml类别顺序错一个字母前面全白干把目录重排成YOLO习惯的结构images/train、images/val、labels/train、labels/val。注意YOLO训练时默认txt标注和图片在同一个父目录下txt文件放在labels目录里与图片目录平级而不是放在Annotations这种历史遗留目录里。这个数据集给的是VOCYOLO两套所以labels目录是现成的你只需要把图片按划分规则移动到images目录下。# data.yaml路径可以写绝对路径避免相对路径出错 path: /data/substation_infrared_889 train: images/train val: images/val nc: 7 names: 0: current_transformer # CT 1: potential_transformer # PT # 2~6按压缩包里Annotations里实际出现的类名顺序补全 # 顺序必须和labels/*.txt里的索引严格一致这里最值得强调的还是names顺序。YOLO训练时txt第0列的数字会直接作为索引到names里取名字如果names顺序和解压出来的标注索引不一致训练过程不会报任何错但val输出里所有类名都是错的。保险做法是用第一节的检查脚本把全部txt里的索引集合提取出来确认是06连续再按这个顺序填names。4.2 训练命令与关键参数迁移学习比从零训练稳得多889张图从零训练不现实普遍做法是加载COCO预训练权重做迁移学习。COCO里没有红外图像预训练模型没见过过热像图纹理但低层边缘、轮廓特征仍然可以复用比随机初始化强太多。# 用yolov8n.pt做迁移学习先不用s或m小样本下小模型更稳 yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs150 \ batch8 \ imgsz640 \ patience30 \ project./runs \ namesubstation_ir_640参数怎么选实践经验比理论更重要。epochs给150配合patience30做早停如果loss还在下降就让它继续。batch的大小取决于显存8G以下显存用8稳妥24G以上可以到16或32但小数据集batch太大反而容易欠拟合不必一味往上堆。imgsz640是性价比最高的选择红外图像里PT/CT这类目标一般不是特别小640分辨率在速度和精度之间最好平衡。如果发现小目标漏检严重可以试一次1280但889张图撑大分辨率容易抖动验证集mAP可能不升反降。损失函数层面YOLOv8默认用的是CIoU框回归损失加BCE分类损失加DFL这套组合在大多数目标检测任务里已经调得比较平衡普通场景不需要动它。你要关注的是训练日志里的box_loss和cls_loss曲线如果box_loss降得慢而cls_loss正常说明框回归有问题优先检查标注坐标是不是有问题而不是改损失函数参数。改损失函数权重在小数据集上是玄学一改就翻车的情况远多于收益。4.3 数据增强参数红外伪彩色图必须谨慎对待HSV扰动这是红外数据集和可见光数据集最大的分水岭。Ultralytics训练默认会做hsv_h、hsv_s、hsv_v的随机扰动对普通照片来说这是提升泛化能力的免费午餐但对红外伪彩色图来说就是毒药。伪彩色图的颜色映射关系是固定的亮白代表高温、深蓝代表低温HSV颜色空间里把色相随机翻转等于把每张图的温度标尺随机换了一套“过热点”的颜色语义被彻底打乱模型学到的东西全是噪声。yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs150 \ batch8 \ imgsz640 \ patience30 \ augmentTrue \ hsv_h0.0 hsv_s0.0 hsv_v0.0 \ degrees10.0 \ fliplr0.5 \ mosaic1.0hsv三项全关掉是红外伪彩色图训练的底线操作。degrees给到10度小角度旋转可以接受超过30度会破坏设备顶部朝上的空间先验不建议。fliplr左右翻转对多数变电站设备是安全的但如果你的类别里有单侧散热器这类不对称特征翻转会让模型学混乱这时候关掉fliplr。mosaic把四张图拼在一起训练对889张这种小样本有很强的正则效果建议保留。要注意的是红外图像不同帧温度标尺不同拼接后边框处会出现温度跳变这属于可接受的噪声不用太焦虑。5. 避坑红外小样本检测的5个常见翻车点5.1 图片发黑或发白16bit温度图被当成8bit读现象训练时大量图片读出来是全黑或全白loss直接炸掉或者验证集mAP为0。原因红外相机导出的图像可能是16bit PNG甚至带温度信息的单通道图像素值范围是065535普通cv2.imread按8bit读大于255的值全被截断成255于是整张图一片白。解决训练前统一检查所有图片的dtype和位深16bit图先按比例缩放到0255再保存成8bit或者用cv2.imread(..., cv2.IMREAD_UNCHANGED)读取后手动归一化。5.2 loss猛降但验证集mAP不动同一设备的连续帧泄漏现象训练loss一路降到零点几val mAP却卡在0.5上不去偶尔还往下掉。原因随机划分时把同一设备同一轮巡检的画面切进了训练集和验证集模型靠记住画面把loss压低遇到真正没见过的新画面就露馅。解决严格按采集批次分组切分或干脆用交叉验证。看val结果时不要只看mAP挑几张现场实拍图推理一下比任何指标都直观。5.3 开了HSV增强后过热点特征失效现象训练loss降到0.2但推理时把背景里的高温水泥地误检成设备置信度还不低。原因默认的HSV增强把伪彩色图的温度映射色相打乱了模型学到的“红色发热”这种隐含规律被破坏只能退化成纯轮廓匹配。解决把hsv_h、hsv_s、hsv_v全部设成0。这个坑极其隐蔽因为训练曲线一切正常直到部署到现场才暴露。5.4 VOC转YOLO时类别索引跳号现象训练不报错但预测结果里画出来的框全是错的比如标注CT的框显示成避雷器。原因VOC的xml里类名是字符串转换脚本里没有把字符串映射成连续整数索引或者映射时用了旧版COCO的类别编号导致索引从5开始跳着排。解决转换完成后用检查脚本筛一遍txt里的索引必须确认是06的全部整数且不重复、不缺失。这一步十秒钟的事不做的代价是训练几小时后全部作废。5.5 COCO预训练权重直接硬迁漏检率居高不下现象用yolov8n.pt在红外数据上微调了150轮推理时对清晰可见的PT目标就是框不出来。原因虽然迁移学习能复用低层边缘特征但COCO模型的高层特征完全是围绕可见光纹理组织的红外图像的温度分布纹理对它来说完全是陌生分布直接微调等于让高层特征从头学。解决这不是加epoch能解决的要调整数据分布。可以尝试把输入做标准化处理让红外图灰度分布的均值和方差更接近自然图像或者先用无监督方式在同场景红外图上做预训练权重适配。最简单有效的方法是在微调时冻结前10层只训练高层特征让低层保持通用边缘提取能力。6. 部署前多做一个“高温中心偏移”验证红外检测比mAP更值得看的指标6.1 校验脚本预测框中心和框内最热像素位置的偏移量mAP只能告诉你框和标注框的重合度但红外的检测目标本质是“发热部位”模型如果学的是设备轮廓而不是过热点mAP照样能刷得不错到了现场却会把旁边发热的隔离开关误检成CT。我在实际项目里习惯在验证阶段加一道高温中心偏移检查把预测框和图像温度分布叠加计算框中心和框内最高温像素点的归一化距离。距离大说明模型定位的是形状而不是热源这样的模型部署出去迟早翻车。import cv2 import numpy as np def hot_spot_offset(gray, box): gray: 8bit灰度红外图 box: (x1, y1, x2, y2) 像素坐标 返回: 框中心与框内最热像素点的归一化距离 x1, y1, x2, y2 [int(v) for v in box] roi gray[y1:y2, x1:x2] if roi.size 0: return None max_idx np.unravel_index(np.argmax(roi), roi.shape) hot_y, hot_x max_idx center_x, center_y (x2 - x1) / 2, (y2 - y1) / 2 diag np.sqrt((x2 - x1) ** 2 (y2 - y1) ** 2) return np.sqrt((hot_x - center_x) ** 2 (hot_y - center_y) ** 2) / diag # 遍历验证集预测框统计偏移量分布 for img_path, box in test_samples: gray cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) offset hot_spot_offset(gray, box) # 偏移量大于0.3的框标记为“疑似形状匹配而非热源匹配”这段脚本的判别逻辑很简单真正的过热点检测模型预测框中心应当落在发热区域附近。偏移阈值先看0.3如果大量预测框偏移超过这个值就回到训练侧去检查数据增强和标注方式。这个指标不能替代mAP但它能在部署前把“看着精度不错、现场一用就废”的模型筛出去。6.2 从验证到部署640分辨率在T4上用TensorRT跑到多路拉流是现实需求验证通过后导出模型走TensorRT加速是常规路径。YOLOv8的导出命令是yolo export modelruns/substation_ir_640/weights/best.pt formatengine halfTrue device0halfTrue打开FP16精度。T4这类推理卡上用TensorRT FP16跑640分辨率的检测单路推理的耗时很低真正吃资源的是1080p RTSP拉流的解码。多路监控视频流在这里的现实瓶颈往往在网络解码和显存带宽而不是检测网络本身。我自己的习惯是先把高温中心偏移脚本固化到模型评测流程里每次训练完先过这关再过mAP再谈部署。这个习惯帮我挡掉了至少两次现场误检事故也希望帮到你。本文还有配套的精品资源点击获取