ARTICLE DETAIL

资讯详情

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

输电线路红外过热目标检测:基于YOLO的小样本数据集训练实践

输电线路红外过热目标检测:基于YOLO的小样本数据集训练实践 简介面向电力巡检、无人机巡检与计算机视觉研究者该数据集提供2253张不同场景下的输电线路红外过热图像目标为单一类别过热区域可直接用于目标检测模型的训练与验证。压缩包共2000个文件其中Pascal VOC格式xml标注文件1999个另有1个txt说明文件总大小33.57MB下载解压即可使用文件结构简洁便于划分训练集与验证集。已有120人学习下载适合具备目标检测基础、希望获得真实电力红外样本的开发者也可用于电力设备红外故障诊断相关研究。每张图像均配有精细标注同时兼容VOC与YOLO两种主流格式可直接接入YOLO、Faster R-CNN等常见检测框架省去标注格式转换环节红外过热样本覆盖多种实际运行场景有助于模型学习过热区域的温度分布特征从而及早识别故障隐患提升输电线路智能巡检的整体效果。1. 2253张红外单类数据比想象中更适合做巡检落地验证做电力巡检算法的人最容易遇到的情况是搜“数据集下载”半天下回来一个几千张的通用目标检测包跑起来精度还行真拿到现场又不敢用。反而是这套电力场景输电线路红外过热检测数据集VOCYOLO双格式2253张1类别看起来不显眼却正好踩中巡检场景的两个事实过热缺陷样本在公开数据里本来就稀缺而落地时只关心“热点区域有没有框准”。红外图里布雷密度低一张图往往只有一处发热目标所以“1类别”不是缺陷而是这类任务本来的形态。适合拿它做两件事验证检测管线能不能吃红外数据以及把迁移学习、阈值选择这一套调参流程完整练一遍。2. 输电线路红外过热的检测对象为什么模型只学“过热”就够了2.1 红外图没有颜色只有温度场热斑与伪彩是模型的两种输入红外热像仪成像靠的是物体表面的辐射测温温度越高辐射出度越大传感器转换成灰度后再映射成显示亮度或伪彩。输电线路上的过热部位比如耐张线夹、引流板、压接管、并沟线夹因为接触电阻增大或者氧化腐蚀运行温度比正常导线高一截在热像图里表现为一块亮度突出的区域。这就是检测任务里唯一的“目标”。难的不是找到热斑而是排除背景。白天太阳暴晒下绝缘子、杆塔、导线、植被都会升温红外图里的灰度对比被压得很平。更麻烦的是现在的红外热像仪普遍开了DDE数字细节增强背景层次被拉得很丰富热斑反而被压缩成一块不太突出的亮斑。深度学习模型要学的并不是“全图哪里最亮”而是“局部灰度突变加上金具形状”的组合特征。检索里常见到 firc-dataset 这种命名代表电力红外检测专用数据和通用红外行人、车辆数据集完全是两码事你要是拿后者做预训练后面有得折腾。这个特点决定了数据集规模不需要很大。2253张图目标类别只有1个图像内容高度聚焦全是输电线路的红外视角不存在跨场景的域漂移问题。相比通用目标检测动辄几万张这个规模足够让模型把“热斑 金具外形”这个固定模式记住前提是训练时别自己把数据搞脏。2.2 VOC与YOLO双格式一张图两套标注的差异与归一化规则压缩包名字里写明了VOCYOLO格式解压后常见做法是同时存在两套目录一套是VOC风格的JPEGImages、Annotations、ImageSets/Main另一套是YOLO风格的images和labels。两套标注描述的是同一批图的同一个目标但存储方式和坐标体系完全不同。对比项VOC格式YOLO格式文件粒度每张图对应一个XML文件每张图对应一个txt文件坐标形式bndbox里是xmin、ymin、xmax、ymax像素绝对坐标一行一个目标x_center、y_center、width、height归一化到01类别标识object的name字段字符串整数class_id从0开始多目标处理一个XML里多个object节点一个txt里多行每行一个目标读取依赖需要额外维护class_names映射表训练时直接读数字编号YOLO格式的归一化规则看起来简单但容易手滑。x_center和y_center是目标框中心点除以原图宽和高width和height是框宽高除以原图宽和高四个值全部落在0到1之间。注意两个细节第一顺序是中心点坐标在前宽高在后不是xmin、ymin、width、height第二除数必须用原图尺寸不是标注尺寸也不是resize后的尺寸。很多转换脚本写错一个除号框就偏了。双格式存在的原因很实际不同训练框架和标注工具读取习惯不一样YOLO官方训练脚本直接读txt最快而LabelImg、LabelMe这类工具原生读写VOC。拿到双格式数据集意味着你不用再满世界找转换工具解压后挑一套用就行。但我的建议是无论用哪套都要自己写一个转换脚本过一遍原因后面第3章细说。2.3 1类别的真实含义优化目标退化成“热源/背景”二分类很多人看到“1类别”会觉得数据简单其实不是。目标检测的损失里分类损失只负责判断“这是不是过热目标”但回归损失还要负责把框的位置和大小调准。单类任务的分类压力小回归压力一点没少。更关键的是样本不平衡。一张红外巡检图里热斑区域通常只占全图的2%到6%剩下全是背景。模型在训练时看到的绝大多数候选框都是负样本如果损失函数里对简单负样本没有抑制梯度会被背景主导模型很快就学会“什么都不框”也能把loss压得很低。单类检测真正的难点就在这里目标种类不用区分但要学会在大量背景干扰下把热斑捞出来。所以在后续训练里我一般会关注两个信号分类损失是不是降得太快以及回归损失在后期是不是还在缓慢下降。如果分类损失前20个epoch就趋近于0说明模型在偷懒如果回归损失一直降不动多半是anchor和输入分辨率的搭配出了问题。这两个信号对应的排错方法放在第4章和第5章。3. 把VOC转成YOLO格式转换脚本与四个边界坑3.1 解析XML的转换脚本坐标顺序与归一化是两个独立陷阱拿到解压目录后我的习惯是先做一次VOC到YOLO的转换。虽然yolo最新版本训练时能直接读VOC内部有转换逻辑但生成的缓存文件看不到一旦标签有问题排查成本更高。自己转出来的txt可以直接按行检查心里有底。import xml.etree.ElementTree as ET import os voc_root Annotations yolo_root labels class_map {hotspot: 0} # 单类别也要写清楚映射后续加类别时不容易乱 def voc2yolo(xml_path): tree ET.parse(xml_path) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) if w 0 or h 0: print(f跳过异常尺寸: {xml_path}) return [] lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_map: continue 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) if xmin xmax or ymin ymax: print(f发现退化框: {xml_path}) continue x_center ((xmin xmax) / 2) / w y_center ((ymin ymax) / 2) / h box_w (xmax - xmin) / w box_h (ymax - ymin) / h lines.append(f{class_map[cls_name]} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) return lines这段脚本的逻辑是先解析XML里的size字段拿到原图宽高再遍历所有object节点取出bndbox里的四个像素坐标换算成中心点加宽高的归一化格式。保留6位小数足够训练用不要用round截断也不要画蛇添足乘以什么缩放系数。参数说明里最值得强调两点。第一class_map里写了{hotspot: 0}如果数据集实际用的类别名不是hotspot而是fever、overheat之类的词一定要先打开几个XML看name字段再定映射否则转换出来的txt全是缺失类别。第二函数开头对w和h做了非正校验这在红外数据集里不是多余的有些标注工具会导出空的size节点。3.2 用ElementTree做安全解析别用字符串截取处理XML我见过有人用正则去抓bndbox之间的内容理由是写起来短。这个做法在VOC文件上很不可靠。标注里可能出现truncated、difficult字段类别名也可能带空格比如“ferrule clip”字符串截取很容易把结构搞碎。推荐的做法就是上面代码里的ElementTree。它按节点层级取数不依赖文本格式即使XML里多了注释或者自定义字段也不会读错。另一个好处是root.iter(object)能跳过嵌套结构带来的不确定性比findall(.//object)更稳。提示转换脚本跑完以后先别急着训练。数一下生成的txt数量和XML数量是否一致。如果少了文件多半是某个XML里size字段异常或者没有任何object节点被保留把打印出来的异常路径逐个看一遍。3.3 四个边界坑类别ID、目录划分、图片路径、宽高判空转换环节最容易踩的坑集中在四个地方我按踩到的频率排一下。类别ID写错。训练配置里的nc是1但txt第0列写的是class_id如果映射表顺序和训练时data.yaml里的类别顺序不一致模型会把“过热”当成别的编号去学单类场景下还看不出明显报错只能看到混淆矩阵很奇怪。所以转换脚本里的class_map必须和后续训练配置文件里names列表的顺序一一对应。目录划分丢失。VOC格式用ImageSets/Main里的txt文件划分train和valYOLO格式没有这个文件靠的是文件夹路径。如果解压后所有jpg和txt都堆在同一个目录训练脚本默认全部当训练集验证就没了。我一般按8:2的比例把2253张图分成约1800张训练、450张验证划分时注意不要打乱同一杆塔的连续帧这点在第4章单独讲。图片路径配错。YOLO的txt里不存图片路径训练时靠data.yaml里的train和val路径去拼文件名。如果目录里混有.jpg和.png两种扩展名或者文件名有重号训练进程会静默跳过部分图片表现为数据集总量比预期少。转换完成后扫一遍文件名确认扩展名统一。宽高判空。部分XML的size字段是0或者缺失脚本里如果不做w 0 or h 0的校验会出现除零错误整个转换中断在一个文件上。加上校验之后至少能定位到具体是哪张图出了问题。3.4 转换完用可视化脚本验证不要直接扔进训练器转换完成后强烈建议抽20张图把txt里的坐标画回去眼见为实。这一步能发现归一化公式写反、宽高顺序颠倒、类别id错位这些“看着没问题、一训练就翻车”的隐患。import cv2 img cv2.imread(images/train/000123.jpg) img_h, img_w img.shape[:2] with open(labels/train/000123.txt) as f: for line in f: cid, xc, yc, bw, bh map(float, line.split()) x1 int((xc - bw / 2) * img_w) y1 int((yc - bh / 2) * img_h) x2 int((xc bw / 2) * img_w) y2 int((yc bh / 2) * img_h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) print(fclass{int(cid)}, box({x1}, {y1}, {x2}, {y2}))这段代码做的事很简单把归一化坐标还原成像素坐标画框并打印。检查时重点看三样东西框有没有贴住热斑边缘、有没有明显偏移、class_id是不是0。红外图的背景在伪彩下颜色丰富但框应该始终锁在发热金具上而不是框住整片导线。4. 训练2253张图的常见问题排查5个翻车点照着这套数据踩过的坑按出现频率排序基本就是下面这5条。它们不是互相独立的很多时候一起出现。4.1 现象训练100轮loss不降、mAP纹丝不动loss曲线一直平着走val mAP50卡在个位数。原因多半是anchor和输入分辨率不匹配。yolo系列的默认anchor按COCO数据集聚类得到目标尺寸在几十到几百像素之间而输电线路红外图里的热斑往往只占全图几个百分点属于典型小目标。在640×640的输入下这些默认anchor对热斑来说太大了正样本匹配数量极少模型学不到东西。解决方法是两条路同时试。一是把输入分辨率提高到1280让热斑在特征图上的像素占比大一些二是开启autoanchor让训练脚本根据当前数据集重新聚类。判断是否有效不看最终mAP看前10个epoch的box_loss有没有明显下降趋势。如果1280显存不够就退回640并调低mosaic增强的比例让模型先看到“干净”的小目标。yolo损失函数里box_loss和cls_loss分开显示红外小目标场景通常是box_loss拖后腿这点能帮你确认问题方向。4.2 现象训练集mAP很高验证集全程为0这是最迷惑人的一种情况。训练集已经过拟合到0.9验证集的表现却像是模型什么都没学会。大多数时候问题不在模型在数据划分。红外巡检图往往来自同一相机对同一线路的连续拍摄相邻帧之间场景几乎一样。如果是按文件名随机划分train和val同一个杆塔的不同拍摄帧极可能同时出现在两边模型在训练时见过几乎相同的图像验证时自然高分。一旦划分里有几张差异大的图成绩立刻崩。这不是模型不行是数据泄漏。解决方法是按场景分组划分。先看文件名里有没有设备编号或时间戳按前缀聚合后再分train和val。如果文件名没有规律可以用图像直方图做简单聚类把相似的帧分到同一组再用组为单位划分。2253张图听起来多按场景一分真正独立的样本可能只有几百组。4.3 现象把绝缘子、杆塔背景框成目标推理结果里模型把正常的绝缘子串或导线接头也框了出来还给了高置信度。这个现象在伪彩红外图上特别常见。原因在于伪彩映射。很多红外热像仪导出的JPEG是铁红、彩虹这类伪彩图模型看到的颜色不是温度而是调色板映射后的RGB值。同一个温度区间用不同调色板导出颜色完全不同。如果训练集混合了多种伪彩风格模型很容易学到“蓝色背景要忽略红色背景要框住”这种错误规则而不是学温度特征。解决办法是统一输入。最干净的做法是把所有图转成灰度图再训练细节见第6章如果不想转至少确认全部训练图像的伪彩风格一致并在预处理时做一次直方图均衡降低调色板差异带来的干扰。检查方法也简单统计train和val目录里图像的通道均值差异超过一个阈值说明数据来源不统一。4.4 现象yolo混淆矩阵的总合对不上、每次算都不一样训练日志里打印的混淆矩阵有人较真去加总发现行和列的总合不是1。换个置信度阈值再算一次数字又变了这就是热词里常说的“yolo混淆矩阵总合不唯一”。原因在于混淆矩阵本身就是在特定超参下计算出来的。yolo训练日志里的confusion matrix默认用conf0.25和iou0.45去匹配预测框和真实框低于阈值的预测全部算作背景。你把阈值得高到0.5匹配结果当然变改成0.1又多出一堆误检。同一个模型不同conf阈值下的混淆矩阵本来就不该相同。如果只关心过热目标这一类不用纠结官方图。固定conf0.25和iou0.5自己写推理脚本对验证集逐张计算TP、FP、FN再做人工抽检。单类任务的正确做法是选一个固定的判断口径而不是反复换阈值看哪个好看。4.5 现象训练中loss突然暴涨或变NaN训练到一半loss从0.05突然跳到十几后续无法恢复严重的直接NaN。常见原因之一是batch size太小BatchNorm统计量在震荡。红外图像动态范围大前几个epoch权重还没稳定batch越小BN的均值和方差估计越不稳。我一般把batch设为8或16起步不要用2、4去省显存。V100这种卡上跑yolobatch8和batch2的速度差距不大稳定性差距却很明显。如果显存实在有限就把mosaic增强比例调低并考虑冻结前10层先跑20轮等loss曲线稳定后再解冻全量微调。BN崩溃还有一个诱因是学习率过大尤其用了高分辨率输入时建议学习率从0.001线性缩放batch翻倍学习率也能适当跟着调。5. 训练参数基准预训练权重、增强配置与一套能直接抄的默认值5.1 要不要下载yolo预训练模型迁移收益要看域差异“yolo预训练模型下载”是很多人拿到数据集后问的第一件事。我的回答是要下但别指望它直接给你精度。预训练权重的价值集中在浅层特征边缘、纹理、局部对比度。红外热斑虽然和可见光里的物体长得不一样但它的边缘梯度和局部纹理结构和普通图片的低层特征是有共通之处的。用COCO上训好的权重做初始化训练初期的收敛速度明显比随机初始化快。对于2253张这种小数据集这意味着可以用更少的epoch达到同样精度。但也要清醒红外图和自然图像的域差异很大尤其伪彩映射后颜色分布完全不同。预训练权重提供的只是起点后面所有层都需要充分微调。一个靠谱的做法是下载yolov5s或yolov8n这类小体量权重冻结前3层先训练20轮让后面的层适应当前数据分布解冻后再全量训练50到100轮。如果你看到loss一开始就降得特别快不要高兴太早很可能是模型在利用背景特征而不是目标特征验证集上很快会露馅。5.2 一套可直接套用的训练参数从输入分辨率到早停给2253张红外单类数据定一套基准配置我会这样写参数建议值说明输入分辨率640×640起步显存允许时试1280热斑目标小高分辨率有明显收益总epoch100150小数据集训练收敛快没必要300轮batch size816过小容易触发BN崩溃优化器SGD或AdamWlr0.0010.01建议配合线性缩放学习率mosaic增强0.5全开容易让小目标在拼图里更小autoanchor开启让anchor重新适配热斑尺寸早停patience20连续20轮val无提升就停train/val划分8:2按场景分组防止连续帧泄漏这套参数不是最优解但是个能跑通的起点。调整时每次只动一个变量不要同时改分辨率和batch不然翻车了都不知道是哪一步导致的。训练完成后把训练过程里yolo保存的混淆矩阵图和loss曲线图拿出来看一眼确认没有出现第4章说的那几个典型异常。5.3 验证口径用F1曲线选置信度阈值而不是只看mAP50单类目标检测的落地难点不在模型在推理时置信度阈值选多高。阈值设0.1误检框满天飞设0.9又可能漏掉真正的发热点。mAP是对所有阈值下的综合表现但实际部署时你必须选定一个固定的conf。一个实用的做法是用验证集推理让模型输出所有候选框把conf从0.05到0.95按步长0.05扫一遍对每个阈值计算precision、recall和F1画出F1曲线。F1最高点对应的那个置信度就是当前数据下最合适的阈值。对输电线路巡检场景漏检的代价大于误检可以在F1最高点的基础上再往下调0.05留一点安全余量。这个“阈值扫描”的习惯值得固化成脚本。数据更新、模型重训之后阈值也要跟着重新扫。我见过太多项目模型换了阈值还用旧的结果部署效果忽好忽坏。6. 三个进阶方向旋转框、灰度通道与自举数据扩充6.1 旋转框检测现有水平标注没法直接转想上mmrotate就得重标输电线路的耐张线夹、绝缘子串大多是倾斜长条状水平框会框进大量背景导致回归损失变大。旋转框检测能显著降低背景干扰但现实问题是现有数据集是水平框标注水平框没有角度信息没法从VOC里的xmin、ymin直接算出旋转角度所以“VOC转旋转框”不是转换而是重标。如果真想试常见的路线是走mmrotate训练DOTA格式数据集。DOTA格式每行是x1 y1 x2 y2 x3 y3 x4 y4 class_name difficult四个角点按顺时针排列。你可以用旋转框标注工具在原始红外图上重新标注一批先拿几十一百张做对比实验看看旋转框在验证集上的mAP50是否真的比水平框高。我的经验是目标越细长旋转框收益越大如果热斑本身接近圆形旋转框带来的提升可以忽略。6.2 伪彩红外图转灰度读入三通道复制是兼容框架的常用做法如果确认训练集里混了多种伪彩风格最彻底的解法就是全部转成灰度。很多yolo框架不支持单通道输入所以常见做法是把灰度图复制成三通道import cv2 gray cv2.imread(images/train/000123.jpg, cv2.IMREAD_GRAYSCALE) img_3c cv2.merge([gray, gray, gray]) cv2.imwrite(images_gray/000123.jpg, img_3c)这段代码把三通道伪彩图压成灰度再复制回三通道。模型看到的三通道数值完全一致不会再从颜色上学到虚假的“温度”规律。做这个操作有个前提确认原始图像本身是单通道数据导出成伪彩的。如果原图已经是真彩色这个转换就没有意义。判断方法很简单直接在单通道下看热斑还能不能分辨能分辨就转不能分辨就说明信息本来就在颜色里。6.3 用高置信度预测做自举扩充给2253张续命2253张图训练出来的模型在相同相机和巡检线路上部署精度通常是够用的。但如果想扩充数据集最省钱的办法不是去搜更多数据而是自我迭代用当前模型对一批新的红外巡检视频抽帧推理只保留置信度高于0.7且与已有标注没有重叠的预测框人工抽查一遍后并入训练集。这个做法的成立条件是数据同源。新增图片来自同一红外相机、同一巡检视角域漂移很小伪标签的可信度才会高。每新增一批数据都要重新按场景划分train和val不能让新样本全部堆进训练集却把原来的验证集污染了。我给自己定了个习惯每加100张图就重跑一次验证集的F1曲线重新选阈值不让旧参数伴随新数据一直错下去。这套流程看起来啰嗦但比闷头攒数据更可靠。希望帮到你。本文还有配套的精品资源点击获取
返回列表