简介:本资源为面向电力场景变电站设备检测的红外图像数据集,适用于从事电力设备智能巡检、红外目标检测算法研究与教学的人员,可支撑电压电流互感器、避雷器、断路器及隔离开关等关键设备的识别模型训练与验证。包内共2000个文件,以891个txt标注文件、889个xml标注文件和889张jpg红外图像为主,同时提供Pascal VOC与YOLO两种标注格式,压缩包约32.75MB,便于直接接入主流检测框架。数据集共标注7个类别,涵盖Chave_H_230kV、Chave_V_230kV、DISJUNTOR、Pararraio_69kV、Pararraio_230kV、TC、TP,总标注框数达1715个,其中TC与TP样本较为丰富,适合开展多类别目标检测实验。目前已有551人学习下载,可作为电力红外图像检测课题的基线数据,帮助读者快速完成数据加载、格式转换与模型训练验证。
1. 889张红外图、7类互感器:这份VOC+YOLO双格式数据集到底能干什么
变电站红外测温巡检的朋友大概率都遇到过这个尴尬:手里攒了几百上千张红外图,想跑个自动检测,结果发现公开数据集要么是可见光场景,要么类别对不上,要么只有 VOC 没有 YOLO 标签,光格式转换就得折腾一整天。这份 889 张、7 类别的变电站红外图像电压电流互感器检测数据集,恰好卡在这个缺口上——它同时给了 VOC 和 YOLO 两套标注,拿到手就能直接喂给 YOLOv5/v8 训练,不用再自己写转换脚本。
它解决的核心问题是:把「红外图像里识别互感器」这件事从零散标注变成可复现的训练流程。适合三类人——做电力设备智能巡检的算法工程师、拿变电站红外做毕设或论文的学生、以及想验证红外目标检测方案但缺数据的团队。889 张不算大,但 7 个类别覆盖了电压互感器、电流互感器等关键设备,配合红外图像特有的热特征,足够跑通一条完整的训练-验证链路。下面我从数据本身、环境搭建、训练配置到踩坑,一步步拆开讲。
2. 先看清数据:VOC 与 YOLO 双格式的目录结构和类别映射
拿到一个 7z 压缩包,第一件事不是急着解压训练,而是先搞清楚里面到底装了什么。这份数据集的核心价值在于「双格式」——同一批图像配了两套标注体系,VOC 用 XML,YOLO 用 TXT。理解两者的差异和对应关系,决定了你后面能不能顺利切换框架。
2.1 VOC 与 YOLO 标注格式的本质差异
VOC 格式的标注是 XML 文件,每个目标记录<bndbox>下的xmin/ymin/xmax/ymax,这是绝对像素坐标,原点在图像左上角。YOLO 格式则是每行一个目标,格式为class_id x_center y_center width height,四个值都是相对于图像宽高的归一化值,范围 0 到 1。这个差异看着简单,但转换时最容易翻车的地方在于:VOC 的坐标是整数像素,YOLO 要求浮点归一化,四舍五入的精度损失、边界框超出图像范围、类别名到类别 ID 的映射顺序,任何一个环节出错都会让训练 loss 不降。
常见做法是先用脚本把 VOC 的类别名统计出来,生成一个固定的classes.txt,再按这个顺序转 YOLO。我一般会强制要求类别顺序和data.yaml里的names完全一致,否则 YOLO 会把「电压互感器」当成「电流互感器」来学,mAP 直接崩。
2.2 解压后应该看到的目录树
解压 7z 之后,合理的目录结构大致是这样(不同打包方式可能略有差异,以实际为准):
dataset/ ├── JPEGImages/ # 889 张红外图像,jpg 格式 ├── Annotations/ # VOC 格式 XML 标注,与图像同名 ├── labels/ # YOLO 格式 TXT 标注 ├── ImageSets/ │ └── Main/ │ ├── train.txt # 训练集图像名列表 │ ├── val.txt # 验证集图像名列表 │ └── trainval.txt └── classes.txt # 7 个类别名称先跑一条命令确认图像和标注数量对得上:
# 统计图像数量 ls JPEGImages/*.jpg | wc -l # 统计 VOC 标注数量 ls Annotations/*.xml | wc -l # 统计 YOLO 标注数量 ls labels/*.txt | wc -l三个数字应该都是 889(或接近,取决于是否有空标注图)。如果 YOLO 的 txt 数量明显少于图像数,说明有图片没有目标,这在红外巡检里很正常——有些图只拍了背景。但要注意,YOLO 训练时没有目标的图如果 txt 为空文件,某些版本会报错,需要提前处理。
2.3 七个类别与红外图像的特点
7 个类别具体名称以classes.txt为准,通常涵盖电压互感器、电流互感器等不同设备或不同状态。红外图像和可见光最大的区别是:目标没有纹理和颜色,只有温度分布形成的灰度或伪彩。这意味着基于纹理的传统检测方法基本失效,必须依赖深度网络学习热特征。互感器在红外图里通常表现为比背景亮的区域(发热)或特定形状的冷热对比,标注时边界框往往比可见光更宽松,因为热扩散会让边缘模糊。
提示:训练前务必用脚本可视化几张图的标注框,确认框的位置和类别没错位。红外图对比度低,肉眼检查比看 loss 曲线更早发现问题。
3. 环境搭建与格式转换:从 Anaconda 到 YOLO 可训练状态
数据看清楚了,接下来是把它变成 YOLO 能吃的格式。虽然数据集号称双格式,但实际训练时你大概率还是要自己生成data.yaml和划分训练验证集。这一章把环境配置和转换脚本一次讲透。
3.1 Anaconda 环境与 YOLO 依赖安装
我习惯用 conda 建独立环境,避免和系统里的包打架。YOLOv8 对 PyTorch 版本有要求,截至我写这篇时的稳定组合是 Python 3.9 + PyTorch 2.0+ + CUDA 11.8(如果你有 N 卡)。没有 GPU 也能跑,只是慢。
# 创建环境 conda create -n yolo_infrared python=3.9 -y conda activate yolo_infrared # 安装 PyTorch(以 CUDA 11.8 为例,无 GPU 去官网选 CPU 版本) pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装 ultralytics pip install ultralytics # 验证 yolo checksyolo checks会输出环境信息,重点看 CUDA 是否可用、版本是否匹配。如果显示 CPU only 而你有显卡,多半是 PyTorch 装成了 CPU 版,重装即可。这一步的坑在于:conda 和 pip 混用可能导致依赖冲突,我一般全程用 pip 装 YOLO 相关包,conda 只负责建环境。
3.2 生成 data.yaml 与训练验证集划分
YOLO 训练需要一个data.yaml告诉它图像路径、类别数和类别名。同时要把 889 张图按比例分成 train 和 val,常见 8:2 或 7:3。下面这个脚本一次性完成划分和 yaml 生成:
import os import random import yaml # 路径配置 img_dir = 'dataset/JPEGImages' label_dir = 'dataset/labels' output_dir = 'dataset' classes = ['class1', 'class2', 'class3', 'class4', 'class5', 'class6', 'class7'] # 替换为实际类别名 # 收集所有图像名(不含扩展名) images = [f.split('.')[0] for f in os.listdir(img_dir) if f.endswith('.jpg')] random.seed(42) # 固定随机种子,保证可复现 random.shuffle(images) # 8:2 划分 split = int(len(images) * 0.8) train_list = images[:split] val_list = images[split:] # 写 train.txt / val.txt with open(os.path.join(output_dir, 'train.txt'), 'w') as f: f.write('\n'.join([os.path.join(img_dir, i + '.jpg') for i in train_list])) with open(os.path.join(output_dir, 'val.txt'), 'w') as f: f.write('\n'.join([os.path.join(img_dir, i + '.jpg') for i in val_list])) # 生成 data.yaml data = { 'path': os.path.abspath(output_dir), 'train': 'train.txt', 'val': 'val.txt', 'nc': len(classes), 'names': classes } with open(os.path.join(output_dir, 'data.yaml'), 'w') as f: yaml.dump(data, f, allow_unicode=True) print(f'训练集 {len(train_list)} 张,验证集 {len(val_list)} 张')逻辑说明:random.seed(42)保证每次划分结果一致,方便复现实验。path用绝对路径避免 YOLO 找不到文件。nc必须等于classes长度,否则训练时类别索引越界。参数方面,划分比例可以按需改成 7:3,但验证集别少于 100 张,否则 mAP 波动大。
3.3 VOC 转 YOLO 的校验脚本
虽然数据集可能已经带了 YOLO 标签,但如果你拿到的是纯 VOC 版本,或者想自己重新生成,这个转换脚本能救命:
import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, img_w, img_h, classes): 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 classes: continue cls_id = classes.index(cls_name) bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) # 归一化并限制在 0-1 x_center = max(0, min(1, (xmin + xmax) / 2 / img_w)) y_center = max(0, min(1, (ymin + ymax) / 2 / img_h)) w = max(0, min(1, (xmax - xmin) / img_w)) h = max(0, min(1, (ymax - ymin) / img_h)) lines.append(f'{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}') return lines关键点:max(0, min(1, ...))是防止标注框超出图像边界导致 YOLO 报错。:.6f保留六位小数,精度足够。转换后建议随机抽 10 张图用cv2.rectangle画框验证,别嫌麻烦,这一步省了后面 loss 不降能查半天。
4. 训练配置与参数调优:889 张图怎么跑出可用模型
数据就绪,环境配好,现在进入训练。889 张图属于小数据集,直接上大模型容易过拟合,参数设置要偏保守。这一章讲模型选型、关键参数和训练过程监控。
4.1 模型选型:YOLOv8n 还是 v8s
小数据集优先选轻量模型。YOLOv8n(nano)参数量约 3.2M,v8s(small)约 11.2M。889 张图用 v8n 足够,v8s 可能过拟合。如果你有预训练权重,从yolov8n.pt开始迁移学习,比从头训练收敛快得多。
# 从预训练权重开始训练 yolo detect train \ data=dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ project=runs/infrared \ name=exp1参数说明:epochs=100对小数据集够用,配合patience=20早停防止过拟合。imgsz=640是 YOLO 默认输入尺寸,红外图分辨率如果远大于 640,可以适当调大但显存吃紧。batch=16根据显存调整,8G 显存跑 v8n 的 640 尺寸大概能到 16。lr0=0.01是初始学习率,迁移学习时可以降到 0.001。
4.2 红外图像训练的关键参数调整
红外图和可见光不同,有几个参数值得单独调。第一是hsv_h/hsv_s/hsv_v色彩增强,红外伪彩图如果做了这些增强可能引入噪声,建议调低或关闭。第二是flipud上下翻转,变电站设备安装位置固定,上下翻转可能产生不存在的场景,建议设为 0。第三是mosaic,小数据集用 mosaic 增强能提升泛化,但红外图拼接后热分布不连续,可以试 0.5 而不是默认 1.0。
# 针对红外图像调整增强参数 yolo detect train \ data=dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ hsv_h=0.0 hsv_s=0.0 hsv_v=0.0 \ flipud=0.0 \ mosaic=0.5 \ project=runs/infrared \ name=exp2这些值不是绝对的,我一般会跑两组对比:一组默认增强,一组关闭色彩增强,看验证集 mAP 哪个高。红外数据集小,增强策略的影响比模型结构还大。
4.3 训练过程监控与指标解读
训练启动后重点看三个输出:box_loss、cls_loss、mAP50。box_loss下降说明边界框回归在收敛,cls_loss下降说明分类在学。如果box_loss震荡不降,检查标注框是否有大量超出边界或宽高为 0 的情况。mAP50是 IoU 阈值 0.5 时的平均精度,889 张图 7 类别,能到 0.7 以上就算可用。
# 训练完成后在验证集上评估 yolo detect val \ model=runs/infrared/exp2/weights/best.pt \ data=dataset/data.yaml \ imgsz=640评估输出会给出每个类别的 precision、recall、mAP。如果某个类别 mAP 特别低,大概率是该类别样本太少。7 个类别 889 张图,平均每类 127 张,但实际分布可能不均,长尾类别需要额外补充数据或做重采样。
5. 避坑与排查:红外数据集训练最常见的五个翻车现场
这一章是我自己踩过的坑,按「现象 → 原因 → 解决」写,你遇到问题时可以直接对号入座。
5.1 现象:训练启动就报「No labels found」
原因:YOLO 找不到标签文件,通常是data.yaml里的路径写错,或者 labels 目录名不是 YOLO 默认的labels。YOLO 默认在图像同级目录找labels文件夹,如果你的结构是JPEGImages和Annotations,它不会自动去读 XML。
解决:确认data.yaml的train和val指向的是图像列表文件,且每张图对应的 txt 在labels目录下。用ls labels/ | head确认文件存在。如果只有 VOC 格式,先跑第 3 章的转换脚本。
5.2 现象:loss 一直不降,mAP 接近 0
原因:类别映射错位。VOC 转 YOLO 时类别顺序和data.yaml的names不一致,导致模型学的是错位的标签。或者归一化坐标算错,框全跑到图像外。
解决:抽一张图,用脚本把 YOLO 标签画出来,和原图对比。如果框位置明显偏移,检查归一化时的宽高是否用错(比如用了 XML 里的width而不是实际图像宽)。类别顺序用classes.txt固定,别每次转换重新排序。
5.3 现象:验证集 mAP 高但实际推理漏检严重
原因:训练集和验证集划分时没有打乱,或者同一设备的连续帧被分到了同一侧,导致验证集和训练集分布过于相似,mAP 虚高。红外巡检图往往是连续拍摄,相邻帧差异极小。
解决:划分前先按拍摄时间或文件名排序,再间隔采样划分,而不是随机打乱。或者用GroupShuffleSplit按设备分组划分。889 张图如果来自几十个变电站,按站划分更合理。
5.4 现象:训练到一半显存溢出(CUDA out of memory)
原因:batch设太大,或者imgsz超过显存承受范围。YOLOv8 训练时还会缓存数据增强结果,实际显存占用比推理高。
解决:先把batch降到 8 或 4,再考虑降imgsz到 512。如果还不行,用amp=False关闭混合精度(会慢但省显存)。另外检查有没有其他进程占着显卡,nvidia-smi看一眼。
5.5 现象:推理时置信度阈值调不好,要么漏检要么误检
原因:红外图像目标边缘模糊,模型输出的置信度分布和可见光不同。默认 0.25 的阈值可能不适合。
解决:用yolo detect predict时加conf=0.4试,或者跑一批验证图画出 precision-recall 曲线,找 F1 最大的阈值。我一般会在验证集上扫一遍 0.1 到 0.9 的阈值,选误检和漏检平衡点。
注意:红外图像里互感器的热特征受环境温度、负载影响大,同一设备不同时间拍的红外图差异可能比不同设备还大。如果实际场景跨季节跨时段,889 张可能不够,需要持续补充数据。
6. 进阶技巧:用两点校正和盲元检测预处理提升红外图像质量
训练跑通只是第一步,真正让模型在变电站现场可用,还得在输入图像上做文章。红外原始图有两个固有问题:非均匀性和盲元。这一章讲两个预处理技巧,以及怎么验证它们对检测的提升。
6.1 红外图像两点校正的工程实现
红外焦平面阵列的响应非均匀性会让图像出现固定图案噪声,表现为竖条纹或网格。两点校正是最常用的非均匀性校正方法:在黑体两个不同温度下采集响应,计算增益和偏置系数,对原始图像逐像素校正。工程上如果没有黑体标定数据,可以用场景自适应方法近似——取多帧图像的平均作为参考,计算每个像素的增益。
import numpy as np import cv2 def two_point_correction(img, ref_low, ref_high): """ img: 待校正红外图像(单通道) ref_low: 低温参考帧 ref_high: 高温参考帧 """ img = img.astype(np.float32) ref_low = ref_low.astype(np.float32) ref_high = ref_high.astype(np.float32) # 计算增益和偏置 gain = (ref_high - ref_low) / (ref_high.mean() - ref_low.mean() + 1e-6) offset = ref_low - gain * ref_low.mean() # 校正 corrected = gain * img + offset # 归一化到 0-255 corrected = cv2.normalize(corrected, None, 0, 255, cv2.NORM_MINMAX) return corrected.astype(np.uint8)逻辑说明:gain和offset是逐像素的,ref_high.mean()和ref_low.mean()是全局均值,用来稳定除法。1e-6防止除零。校正后归一化到 8 位方便后续处理。参数方面,ref_low和ref_high如果没有黑体数据,可以用同一场景不同时间的两帧代替,但效果会打折扣。
6.2 盲元检测与补偿的快速方案
盲元是红外探测器里响应异常的点,表现为恒亮或恒暗的孤立像素。检测方法很简单:对图像做中值滤波,原图和滤波结果的差值超过阈值的像素判为盲元。
def blind_pixel_correction(img, threshold=30): """ 盲元检测与中值补偿 threshold: 差值阈值,根据图像动态范围调整 """ median = cv2.medianBlur(img, 5) diff = cv2.absdiff(img, median) mask = diff > threshold # 用中值替换盲元 corrected = img.copy() corrected[mask] = median[mask] return corrected, maskthreshold=30是经验值,红外图动态范围小的时候可以降到 15。medianBlur的核大小 5 适合孤立盲元,如果盲元成簇,需要加大核或改用形态学方法。返回的mask可以可视化,看看盲元分布是否集中在某些区域——如果集中,可能是探测器局部损坏,校正只能缓解不能根治。
6.3 预处理前后对比验证方法
做完预处理,怎么证明它有用?别凭感觉,跑一组对照实验。把 889 张图分成两组:A 组原始图,B 组预处理后图,用同样的训练参数各跑一次,对比验证集 mAP。
| 实验组 | 预处理 | mAP50 | 推理速度 (ms/图) |
|---|---|---|---|
| A | 无 | 待测 | 待测 |
| B | 两点校正+盲元补偿 | 待测 | 待测 |
如果 B 组 mAP 提升不到 1 个点,而推理速度明显下降,那预处理就不划算。我自己的经验是:盲元补偿对小目标检测提升明显,两点校正对整体对比度提升有帮助,但计算开销要看实现是否用 GPU 加速。CPU 上跑两点校正,889 张图可能要几分钟,训练前预处理一次可以接受,推理时实时做就不现实。
从那以后我每次拿到红外数据集,都强制先跑一遍盲元检测可视化,确认没有大面积坏点再开始训练。这个习惯帮我省了好几次「模型怎么调都不行,最后发现是数据本身有硬件缺陷」的后悔药。希望帮到你。
本文还有配套的精品资源,点击获取