ARTICLE DETAIL

资讯详情

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

电力红外变压器检测数据集:VOC转YOLO全流程与避坑指南

电力红外变压器检测数据集:VOC转YOLO全流程与避坑指南 简介这是一份电力场景电气设备红外图像变压器检测数据集的配套说明文档面向电力设备缺陷检测研究人员、算法工程师与目标检测方向的学习者。文档围绕VOCYOLO双格式的4271张红外图像数据集展开完整列出ACB、CT、Connection、LA、LBS等14种类别的标注情况包含每类标注框数量、总框数11896的统计以及labelImg画框规则方便使用者快速评估数据分布并规划模型训练。资源以单个docx文件打包大小约1006KB内容还涵盖数据集格式说明、类别中文对照与下载地址指引是一份先看清数据全貌再动手建模的实用参考。已有100人浏览学习适合需要基于该红外数据集开展变压器目标检测实验或验证算法效果的读者。1. 电力场景红外图像变压器检测数据集4271张图能帮上什么忙做电力巡检目标检测的人基本绕不开电力场景电气设备红外图像变压器检测数据集这类资源。变压器是变电所最核心的设备红外图能直观反映发热状态但可见光里那套检测经验在红外图上并不完全适用。这个数据集把电力场景下常见电气设备的红外图像整理成VOC和YOLO两种标注格式共4271张、14个类别核心用途就是训练变压器检测模型。它适合三类人想快速验证红外检测baseline的算法工程师、做电力智能巡检方案评估的从业者以及准备跑通YOLO完整训练链路的入门学习者。红外图像没有颜色和纹理只有温度分布模型学到的东西和常规目标检测数据集完全不同这也是它单独成数据集的价值所在。2. 数据集内部14个类别怎么分VOC和YOLO标签怎么对齐2.1 红外图上分出14类部件划分的思路和难点红外图像里变压器不是一个笼统的目标而是由多个部件构成的组合体。这类数据集之所以把类别拆到14个是为了后续做故障定位时能直接定位到某一发热部件而不是只知道“这里有个变压器”。常见的拆分方式包括变压器本体、高压套管、低压套管、油枕、散热器、呼吸器、分接开关、中性点接地排、绝缘子、避雷器、母排连接、油箱、铁芯夹件和局部发热区域。具体类别名我不一一猜但按电力设备检修的习惯部件级拆分大致就是上面这个尺度。难点在于红外图像里不同部件的温度分布可能很接近。油枕和本体在稳定负荷下温差很小散热器片之间的缝隙在低分辨率下也很难数清楚模型真正能依赖的特征是几何形状、相对位置和热辐射的梯度变化。标注的精度在这里很关键有些数据集把散热器整个框进变压器本体里有些则单独框出来这两种规则的训练结果差别很大。我拿到数据集通常先看一眼标注框尤其关注变压器本体和散热器这两类。前者往往框得很大后者小而密集在格式转换时最容易出错。另一个值得注意的点是红外图像的分辨率通常不如可见光。市场上常见的红外相机探测器分辨率从320×240到1280×1024不等而数据集里的图像尺寸决定了YOLO能学到多细的特征。如果图像宽度只有640imgsz强行拉到960反而是浪费算力因为插值出来的细节并不真实。所以在看数据集时我会先用程序统计所有图片的尺寸分布再定训练分辨率。这一步往往比纠结用yolov8n还是yolov8m更影响结果。2.2 VOC的XML和YOLO的TXT字段与坐标换算VOC格式是PASCAL VOC的标准一个标注对应一个XML文件里面记录文件名、图像尺寸、目标名称和bndbox的xmin、ymin、xmax、ymax。YOLO格式则是一个TXT文件对应一张图每行是“类别ID 中心点x 中心点y 框宽 框高”并且四个数值都要归一化到图片宽高。一个VOC XML的核心内容大致如下annotation filenameimg_0001.jpg/filename size width1280/width height720/height /size object nametransformer/name bndbox xmin120/xmin ymin80/ymin xmax900/xmax ymax650/ymax /bndbox /object /annotation对应的YOLO标签文件则是一行文本0 0.3984 0.5069 0.6094 0.7917。这里0是类别ID0.3984是中心点x归一化后的值0.5069是中心点y0.6094是框宽0.7917是框高。换算关系就是下面这四个公式x_center (xmin xmax) / 2 / img_width y_center (ymin ymax) / 2 / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height字段映射关系我用表格总结如下VOC字段YOLO字段说明object/name类别ID需要先建立类别名到ID的映射bndbox/xminx_center分子(xminxmax)/2后归一化bndbox/yminy_center分子(yminymax)/2后归一化bndbox/xmaxwidth分子xmax-xmin后归一化bndbox/ymaxheight分子ymax-ymin后归一化size/width归一化分母(x方向)图像宽度size/height归一化分母(y方向)图像高度这里最容易被坑的是坐标系的零点。VOC的坐标系以图像左上角为原点x轴向右y轴向下YOLO也是同样的方向所以方向本身没有差异。真正的差异是表示方式一个是绝对像素一个是归一化的中心点和宽高。如果直接把xmin和xmax填到YOLO的宽高字段里训练出来的预测框位置全乱而且这种错误在代码里很难一眼发现。2.3 数据体检先跑一遍类别分布和标签边界拿到数据集的第一件事不是马上开训练而是做一轮数据体检。我会写一个简单的统计脚本检查三件事图片和XML是否一一对应、每个类别的样本数分布、以及有没有越界或零宽高的标注。import os import xml.etree.ElementTree as ET voc_xml_dir VOC2007/Annotations image_dir VOC2007/JPEGImages xml_files [f for f in os.listdir(voc_xml_dir) if f.endswith(.xml)] image_files [f for f in os.listdir(image_dir) if f.endswith(.jpg)] xml_names {f[:-4] for f in xml_files} image_names {f[:-4] for f in image_files} print(缺少图像的XML:, len(xml_names - image_names)) print(缺少XML的图像:, len(image_names - xml_names)) category_count {} for xml_file in xml_files: tree ET.parse(os.path.join(voc_xml_dir, xml_file)) root tree.getroot() for obj in root.iter(object): name obj.find(name).text.strip() category_count[name] category_count.get(name, 0) 1 for cat, count in sorted(category_count.items(), keylambda x: x[1], reverseTrue): print(cat, count)逻辑说明先比较文件名集合找出哪些图片没有标注、哪些标注没有图片这种问题在手工整理的VOC数据集里出现概率很高。然后遍历所有XML里的object标签统计每个类别出现的次数类别不平衡一眼就能看出来。如果某个类别的框数占总框数不到5%后面训练时要么给它加权重要么做针对性增强。更细的检查还要看框本身。我一般会单独写一个循环把所有标注的xmin、ymin、xmax、ymax和图像宽高对比一遍发现有xmax大于图像宽度、ymin小于0这类情况就记下来。出现越界标注时需要写个小脚本把越界坐标裁剪回图像边界内。不处理的话训练时可能出现loss变成NaN的情况而这个锅往往被误扣到学习率或模型结构上。3. 从VOC到YOLO的可复现链路转换脚本、数据划分与训练配置3.1 按YOLO的目录结构整理数据从VOC格式转成YOLO格式不只是改文件后缀还要把目录结构对齐。YOLO训练时默认从data.yaml里指定的路径读训练集和验证集每个子集里分别有images和labels目录labels下面的TXT文件和images下面的图片保持同名。目录和目录的名字没有太多讲究关键是data.yaml里要写对路径。我常用这样的结构dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml的内容也很简单把路径和类别列表写清楚就行path: /home/user/dataset train: images/train val: images/val test: images/test names: 0: transformer 1: bushing 2: oil_conservator 3: radiator这里有个容易出事的细节names里的类别顺序必须和TXT文件里的类别ID完全一致。比如名字列表里第1位写的是bushing但生成label时把bushing的ID写成了2那就变成了另外一个类别。这种错误在数据量小的时候还能靠眼睛发现数据一多就只能靠混淆矩阵去定位了。注意类别顺序一旦确定整个训练过程中都不要改动否则label文件里的ID就和真实类别对不上了。3.2 VOC转YOLO的最小脚本下面是满足日常转换需求的脚本包含类别映射、坐标归一化和结果写入。运行前需要确认VOC XML里的object名称和类别映射是一一对应关系。import os import xml.etree.ElementTree as ET # 类别映射顺序要和data.yaml里的names一致 class_names [transformer, bushing, oil_conservator, radiator] class_to_id {name: i for i, name in enumerate(class_names)} voc_dir VOC2007 yolo_label_dir yolo_labels xml_dir os.path.join(voc_dir, Annotations) jpg_dir os.path.join(voc_dir, JPEGImages) os.makedirs(yolo_label_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() img_width int(root.find(size/width).text) img_height int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text.strip() if name not in class_to_id: continue cls_id class_to_id[name] bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) ymin int(bndbox.find(ymin).text) xmax int(bndbox.find(xmax).text) ymax int(bndbox.find(ymax).text) # 防止越界 xmin max(0, min(xmin, img_width - 1)) xmax max(1, min(xmax, img_width)) ymin max(0, min(ymin, img_height - 1)) ymax max(1, min(ymax, img_height)) x_center (xmin xmax) / 2 / img_width y_center (ymin ymax) / 2 / img_height bw (xmax - xmin) / img_width bh (ymax - ymin) / img_height lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) if not lines: continue base os.path.splitext(xml_file)[0] with open(os.path.join(yolo_label_dir, base .txt), w) as f: f.write(\n.join(lines)) print(转换完成)逻辑说明循环遍历XML时先读出图像原始宽高做归一化分母再逐个object节点做类别映射和坐标换算。写入TXT时保留6位小数精度足够。越界裁剪是为了防止标注框超出图像边界导致训练异常。如果某个XML里没有任何object脚本会直接跳过不会生成空TXT避免训练时读到空label报错。参数说明class_names列表里的顺序必须对齐data.yaml的names顺序。如果某个类别名没有出现在映射里脚本会跳过它所以运行前要留意是否出现了“某个类别被整体丢弃”的情况。输出目录yolo_labels可以按需要改成labels后面结合train/val划分再归档到子目录。3.3 数据划分别把同一设备的不同帧混在一起电力巡检的红外图像有个特点同一台变压器会连续拍很多帧相邻帧几乎一样。如果直接随机划分训练集和验证集里会出现大量相似帧验证分数虚高部署时掉点。我遇到这类数据集会先按设备或拍摄时间段分组再按组划分。没有现成分组信息时就按文件名前缀粗分尽量保证同一设备的一段连续帧不进同一个验证集。这个步骤属于数据清洗范畴很多人会跳过但实际影响远大于换一个模型结构。划分比例上我一般用70%训练、20%验证、10%测试。可以这样切find images -name *.jpg | sed s|.*/||; s|\.jpg$|| | shuf shuffled.txt total$(wc -l shuffled.txt) head -n $((total * 70 / 100)) shuffled.txt train.txt tail -n $((total * 70 / 100 1)) shuffled.txt | head -n $((total * 20 / 100)) val.txt tail -n $((total * 90 / 100 1)) shuffled.txt test.txt逻辑说明先把全部图片ID打乱再按比例切成三段。head取前70%当训练集tail跳过训练集后取20%当验证集最后剩下10%当测试集。更严谨的做法是先按拍摄会话分组再做分层抽样这样验证结果更接近真实部署场景。这里有一个人为因素需要注意我在实际项目里踩过这个坑——用shuf随机划分后测试集里出现了与训练集几乎相同视角的画面导致测试指标看起来不错但换一个变电站的数据就翻车。所以我会在划分前先按文件名前缀或拍摄时间排序把明显连续的帧识别出来再分组化处理。3.4 yolov8训练自己的数据集训练命令和关键参数目录结构准备好之后用YOLO训练就很简单。以ultralytics的使用习惯为例训练命令用这几行yolo detect train \ modelyolov8m.pt \ datadata.yaml \ epochs100 \ imgsz640 \ batch16 \ device0 \ workers4 \ lr00.01逻辑说明modelyolov8m.pt表示加载COCO上的预训练权重m是中等规模比n精度高比l省显存datadata.yaml指向前面配置的数据集文件imgsz640是训练分辨率batch16是批大小device0是第一张GPUworkers4是数据加载进程数。常用参数我整理成了一张表参数建议值说明imgsz640或960红外小目标多时优先960batch16或8显存不足时降到8epochs100-300数据集不大100起跑lr00.01用预训练权重时不要太大mosaic1.0开启马赛克增强degrees0.0变压器基本不会旋转fliplr0.5左右翻转可以开训练时YOLO的损失函数由三个分量组成box_loss用的是CIoU、cls_loss分类损失和dfl_loss分布焦点损失用来优化框的质量。训练日志里会打印这三列。如果box_loss收敛而cls_loss不下降优先检查类别定义是否有重叠。我遇到过散热器和电抗器被标注成同一类造成cls_loss长期不回落的案例最后定位到标签混淆而不是模型问题。3.5 第一次推理验证训练结束后用最少的命令验证效果yolo detect predict \ modelruns/detect/train/weights/best.pt \ sourceimages/val \ conf0.25逻辑说明conf0.25表示置信度阈值。source可以直接给文件夹也可以给单张图片或视频。输出的可视化结果会写在runs/detect/predict目录下人眼过一遍比看指标更直接。重点看三类目标小型套管、呼吸器和局部发热区域红外图里这三类最容易漏检。4. 红外图像训练避坑指南五个常见翻车点4.1 对比度低、温度范围不一致导致模型学不动现象训练到后期loss下降很慢验证集mAP不到0.5输出画面几乎找不到框。原因红外图像不像可见光有丰富纹理很多红外相机的原始输出是单通道灰度灰度集中在较窄的范围里不同设备标定范围还不一致。目标区域和背景的温差可能只有几度反映到像素上差别很小。解决在训练前先做对比度拉伸或直方图均衡把灰度范围归一化到0到255。常见做法是在数据加载阶段增加一个预处理步骤把红外原图映射到均匀分布。另外工业红外相机都会标定做两点校正用来消除非均匀性条纹。如果数据集里的图像明显存在这种条纹可以先做一次校正再训练。不确定时跑一组只改预处理方式的对比实验几分钟就能看出差别。4.2 部件轮廓相近导致误检现象散热器和变压器本体的分类混淆严重预测框大量重叠。原因红外图像里没有颜色和纹理散热器的片状结构和变压器本体的外轮廓在低分辨率下很相似尤其从远处拍摄时两者边缘几乎重合。解决第一加大输入分辨率imgsz从640提高到960第二检查标注框是否把散热器单独框出来如果标注时把散热器包含在变压器本体的框内模型学到的特征会互相污染第三考虑加一个“变压器整体”辅助类别让模型先检测整体再细分类。我在实际项目里会把这类相似部件先合并成一个大类用两级检测来解决而不是死磕单模型。4.3 小目标漏检的坑现象高压套管、呼吸器这类小目标recall很低大目标mAP很高。原因小目标经过多次下采样后在特征图上可能只剩几个像素信息损失严重。电力场景拍摄距离远、目标小是常态小目标漏检几乎是必踩的坑。解决imgsz从640提高到960是最直接的手段训练时开启scale0.5的多尺度增强再不行就换带P2检测头的结构或者用切图推理的方式把大图切成小块逐块检测再拼回原图。实测下来切图方案在红外小部件检测上常比换模型更有效。yolo实例分割在标注有轮廓信息时也能带来额外收益因为mask监督比框监督提供了更多边界上下文。4.4 类别不平衡导致部分类离线现象某个类别的AP曲线走平训练过程中几乎不输出这个类别的框。原因14个类别里本体、套管这类外露部件出现频率高呼吸器、中性点接地这类部件数量少正样本不足很难收敛。解决先画类别分布图如果某个类别占比不到5%考虑合并到上级类别里或者做重采样让这类样本在每个epoch里被多抽样也可以做copy-paste增强把小部件目标粘贴到其他图片中。数据均衡性的影响往往比模型结构变化更明显这是我在多个数据集上验证过的结论。4.5 过拟合与验证集泄露现象训练集loss降到0.1验证集loss却上升精度明显回落。原因4271张图片对现代目标检测模型来说偏少尤其当训练集和验证集包含同一设备的相邻帧验证分数虚高实际部署掉点。解决用预训练权重而不是随机初始化增强强度适中避免把红外图像变成完全不像场景的噪声epochs控制在100到150之间配合早停。划分数据时按设备会话分组是解决验证集泄露最关键的手段。5. 进阶先验证、再部署这个数据集值不值得投入5.1 上线前先做这三步验证在决定用这个数据集上线之前我会先做三件事。第一看混淆矩阵。训练结束后ultralytics会输出confusion_matrix.png我习惯从它开始定位问题类别。那些互相混淆的类要么合并要么回到原始数据检查标注边界。这一步比看mAP曲线要诚实得多mAP看整体混淆矩阵看局部。第二拿没标注的真实数据实测。从现场拍一段红外视频用训练好的模型跑一遍观察有没有持续漏检同一类目标。mAP统计的是标签框和预测框的IoU关系但真实场景里有大量背景比如围墙、树木、其他设备这些都不会在数据集标签里出现。我的习惯是准备一个“野外负样本”文件夹预测时专门看误报率。第三估一下部署成本。有人问过T4 1080p25帧每秒用TensorRT YOLO 640分辨率检测可以支持多少路这个问题没有一个通用答案不同模型尺寸和batch策略差别很大。我的做法是先把模型导出成TensorRT FP16再用实际红外视频压测记录单帧延迟和GPU利用率才算真正知道每路消耗多少算力。我在这里的血泪经验是yolov8m的红外检测比想象中快瓶颈反而在图像解码和预处理上。5.2 两个值得投入的进阶方向如果这个数据集值得投入进阶方向有两个。一是从检测到旋转框检测。套管和避雷器在巡检视角下经常斜着摆放水平框会包进大量背景用OBB方案更贴合实际类似mmrotate训练DOTA数据集的流程可以套用。二是从检测到实例分割。如果标注里包含轮廓信息可以升级到yolo实例分割。红外图像两点校正是另一条预处理方向校正后的图像能显著减少模型对非均匀性伪影的依赖。最后说说我自己的习惯拿到这种数据集先做一轮快速体检再跑一版yolov8m作为baseline把所有指标、混淆矩阵和漏检图片存档之后再慢慢调预处理和模型结构。手里有可靠的baseline后改任何东西都有对照物不至于让模型变成黑匣子。希望帮到你。本文还有配套的精品资源点击获取
返回列表