尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

高压输电线玻璃绝缘子缺陷检测全链路:从VOC标注到YOLOv8推理

高压输电线玻璃绝缘子缺陷检测全链路:从VOC标注到YOLOv8推理 简介面向电力运维与计算机视觉开发者这套项目围绕高压输电线玻璃绝缘子缺陷检测提供了基于深度学习的完整实现方案。压缩包共47个文件包含13个Python脚本、14个样本图像、4张效果展示图、模型配置与README说明文档整体约11.74MB脚本覆盖数据标注转换、数据增强、训练集划分及YOLO检测等关键环节。项目从数据预处理、模型训练到缺陷定位与分类一路贯通并附效果展示图片便于直观验证算法在复杂背景下的识别能力。由于该场景对裂纹、破损、污染等缺陷敏感这套工程化代码对电力巡检智能化落地有直接参考价值同时目录结构清晰便于按模块查阅和移植。已有94人学习浏览适合需要快速上手绝缘子缺陷检测或在此基础上做二次开发的工程与研究人员。1. 高压输电线玻璃绝缘子缺陷检测项目从图像到检测报告的全链路实现高压输电线路上的玻璃绝缘子长期暴露在野外自爆、裂纹、闪络和污闪是最常见的缺陷类型其中玻璃绝缘子自爆后只剩钢帽在巡检图像里往往只占几十像素是典型的小目标难题。这个缺陷检测项目把计算机视觉和深度学习结合提供了一条可复现的完整链路用xml2label.py把VOC标注转成YOLO格式TXT用gen_empty_label.py给无缺陷样本生成空标签配合aug.py增强经tool/split.py划分数据集后由yolo.py训练模型最后用detecte.py做推理和结果可视化。相当于工业缺陷检测项目里“数据准备—训练—推理—部署”的Pipeline全拆开适合正在做巡检算法落地、需要参考真实工程源码的开发者。下面按这个流程把关键代码、参数和坑位讲透。2. 数据工程底座XML转YOLO格式、空标签与数据增强2.1 为什么绕不开标签格式转换缺陷检测项目里最耗费时间的往往不是模型结构而是数据。训练一个YOLO系列模型标签是归一化的txt文件每行表示一个目标类别ID、中心点x、中心点y、宽度w、高度h。而主流标注工具默认保存为Pascal VOC的XML因此必须做一个中间层转换。项目里的xml2label.py就是干这个的。这件事看起来简单但我在实际项目中吃过亏一是坐标必须归一化否则不同分辨率图像下模型学到的尺度不一致二是类别索引从0开始类别列表一旦定下来就不要乱动否则重新标注后还要改映射三是标注框的坐标有时会被标反转换时要做min/max保护。如果没有这道保护训练时loss会反复震荡检测框全是异常宽高比。xml2label.py的核心逻辑大致如下# xml2label.py 核心转换逻辑 import xml.etree.ElementTree as ET def convert(xml_path, out_txt_path, classes, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): name obj.find(name).text if name not in classes: continue cls_id classes.index(name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) xmin, xmax min(xmin, xmax), max(xmin, xmax) ymin, ymax min(ymin, ymax), max(ymin, ymax) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h box_w (xmax - xmin) / img_w box_h (ymax - ymin) / img_h x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) box_w min(box_w, 1.0) box_h min(box_h, 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) with open(out_txt_path, w, encodingutf-8) as f: f.write(\n.join(lines))这段代码做的事情是解析XML里每个object的类别名和bndbox边界框按类别列表映射成整数ID再把边界框归一化到0到1之间。归一化后的坐标不依赖图像尺寸模型在推理不同分辨率时才能保持一致的输出尺度。min/max防御性写法能挡住最常见的标注坐标顺序错误。如果xml里混入不在classes里的类别代码会直接跳过避免脏标签进入训练。2.2 无缺陷样本gen_empty_label.py生成空标签的坑绝缘子缺陷检测里最容易忽略的是正常样本。模型如果只在有缺陷的图像上训练会把杆塔、导线、鸟巢都当成异常推理时误检率高到没法看。解决方法是给无缺陷图像生成空标签文件让YOLO把它们作为纯背景负样本参与训练。我一般把原始图像分成两类一类是有缺陷的走labelImg标注流程另一类是无缺陷的只放图像。然后跑一遍gen_empty_label.py# gen_empty_label.py 为缺失标签的图像生成空txt import os from pathlib import Path IMG_SUFFIX {.jpg, .jpeg, .png, .bmp, .tif} ROOT Path(datasets/insulator) for img_path in ROOT.rglob(*): if img_path.suffix.lower() not in IMG_SUFFIX: continue label_path img_path.with_suffix(.txt) if not label_path.exists(): label_path.write_text(, encodingutf-8) print(fgenerated empty label: {label_path})脚本的核心就是遍历数据集根目录下所有图片找到同名txt不存在就创建一个空文件。空文件内容为空表示这张图里没有任何待检测目标。实际使用中要注意训练前先清空labels目录重新生成避免上一个项目残留的旧txt被误认空标签文件必须存在否则YOLO训练时会报标签缺失。另外tif格式在巡检数据里很常见后缀列表里别漏掉。2.3 aug.py数据增强翻转到Mosaic的边界巡检图像通常只有几百张直接训练YOLO很容易过拟合所以项目里的aug.py承担了数据增强职责。常见做法是组合水平翻转、旋转、亮度扰动、随机裁剪。针对绝缘子这种细长目标增强不是越多越好旋转角度过大容易让目标出界增强后标签坐标要同步变换。增强方式参数建议适用场景注意事项水平翻转p0.5左右对称的绝缘子串标签x坐标镜像旋转±15°以内不同悬挂角度超过30°目标易截断亮度扰动±30%逆光、阴天巡检图高光会加剧玻璃反光误检HSV饱和度±25%积灰、污闪样本与污染类别强相关Mosaic4张拼1张小目标数量不足验证阶段要关闭表格里看起来都是常规操作但参数值要结合缺陷类型调整。对于裂纹这种弱纹理目标亮度扰动超过30%会把裂纹细节洗掉模型反而学不到关键特征。饱和度扰动对污染检测有帮助但会让玻璃的高光区域看起来更像裂纹所以我会把饱和度扰动控制在±25%以内同时增加逆光样本模拟。2.4 数据划分与训练文件列表划分数据集时最怕数据泄漏。同一串绝缘子被切成多张图时如果随机划分训练集和验证集会包含同一目标的相似视角导致验证mAP虚高。tool/split.py如果只按图像名随机分我会先按绝缘子串ID分组再按组划分。命令行调用方式一般是python tool/split.py \ --image_dir datasets/insulator/train_images \ --label_dir datasets/insulator/labels \ --train_ratio 0.8 \ --seed 42 python gen_train_valid_txt.py \ --data datasets/insulator \ --out_dir datasets/insulatorsplit.py的train_ratio表示训练集比例剩余归验证集seed固定随机种子让实验可复现。train_ratio我一般从0.8开始如果某个缺陷类别样本太少就改成0.85或0.9但验证集至少留15%否则评估结果波动太大。gen_train_valid_txt.py负责生成train.txt和valid.txt每行一个图像路径YOLO的数据配置里直接引用这两个文件。注意Windows上路径分隔符是反斜杠生成时统一转成/避免训练时路径解析失败。3. 训练配置与yolo.py把YOLOv8落到绝缘子缺陷检测上3.1 yolo.py在项目里的角色项目里的yolo.py并不是从零复现一个目标检测算法而是把模型初始化、数据集配置、训练超参数集中管理起来。从文件位置和调用方式看它更接近一个训练入口实际网络结构和损失函数用的是YOLOv5/v8的现成实现。就玻璃绝缘子这类小目标缺陷检测而言我一般直接选择Ultralytics YOLOv8因为v8的anchor-free设计、C2f结构和Decoupled Head对中小目标更友好且工程封装完善切换训练和推理都方便。这个YOLOv8缺陷检测项目是很典型的深度学习实战项目案例先验证默认配置能跑通再针对缺陷小、背景杂的问题调整训练参数。我最开始做这类项目时总想着改模型结构后来发现几百张巡视图上把数据整理干净带来的收益远大于魔改网络。3.2 数据集配置文件YOLOv8训练前需要一个data yaml内容如下# datasets/insulator/insulator.yaml path: datasets/insulator train: train.txt val: valid.txt names: 0: crack 1: broken 2: pollution这个文件里的names顺序必须和xml2label.py里的classes保持一致。项目摘要提到的裂纹、破损、污染正好对应三类缺陷。如果只检测自爆和裂纹可以减少names数量但一定重新跑一遍xml2label.py和gen_empty_label.py避免旧标签类别索引错位。path字段在Windows下建议写绝对路径或者用相对路径时保证当前工作目录在datasets的上一级。3.3 训练超参数怎么定yolo.py里的参数没有标准答案但有几个默认值值得参考。我通常在YOLOv8n预训练权重上微调而不是从头训练因为ImageNet预训练能让模型在几百张绝缘子图上更快收敛。参数示例值作用调参建议modelyolov8n.pt预训练权重显存不足换yolov8n追求精度换yolov8sepochs300训练轮数小数据集建议300起步imgsz640输入分辨率长图可试1024但显存占用翻倍batch16批大小单卡24G可以到32lr00.001初始学习率微调用0.001从头训练才用0.01lrf0.01最终学习率预留0.001到0.0001区间cacheTrue缓存图像到内存小数据集提速明显workers8数据加载进程Windows建议4避免worker崩溃这张表里最重要的三个参数是imgsz、lr0和batch。imgsz越高小目标保留的像素越多但训练和推理都更慢lr0设成0.01在迁移学习下经常loss爆炸0.001更稳batch如果太小BN层的统计量不稳定导致验证集mAP波动大。3.4 训练入口代码yolo.py的训练核心代码一般长这样# yolo.py 训练入口 from ultralytics import YOLO if __name__ __main__: model YOLO(yolov8n.pt) model.train( datadatasets/insulator/insulator.yaml, epochs300, imgsz640, batch16, lr00.001, lrf0.01, device0, cacheTrue, workers8, fliplr0.5, mosaic1.0, mixup0.0, projectruns/insulator, nameglass_defect, seed42 )这里fliplr0.5让水平翻转以50%概率生效mosaic1.0表示每轮训练都使用四合一拼图mixup0.0关掉混合增强。我关掉mixup是因为绝缘子缺陷像素少mixup会让多个目标重叠后产生模糊标签损失函数在分类上变得不稳定。project和name指定输出目录训练好的best.pt和last.pt都在runs/insulator/glass_defect/weights下。3.5 训练中要盯的三个指标训练时我会盯着bbox_loss、cls_loss和验证集mAP50。loss下降平滑但不代表模型一定在变好关键看mAP50是否在40到50轮后开始爬升。如果loss一直降、mAP不动优先回去检查标签序号和边界框是否归一化正确而不是调学习率。玻璃绝缘子的小缺陷很容易出现在混淆矩阵里比如crack被误判成broken说明两者形态太接近应补充区分性样本。训练中断时Ultralytics会自动保存last.pt恢复时在model.train里加一行resumeTrue即可。长轮次训练建议加上patience50验证mAP连续50轮不更新就自动早停省下的时间可以用来处理数据错误。4. detecte.py推理置信度阈值、NMS与批量输出4.1 推理脚本的整体设计detecte.py是项目的检测入口。实际部署时面对的往往是批量巡检图片而不是单张图所以脚本要考虑三点支持CPU/GPU两种运行环境能遍历整个目录输出检测结果并且结果能直接被检测报告程序使用。项目源码里保留了detecte.py这个名字我建议在自己分支里改成detect_infer.py避免后续混淆。4.2 批量推理代码# detecte.py 批量推理核心代码 from pathlib import Path import cv2 from ultralytics import YOLO def main(): src_dir Path(datasets/insulator/test) out_dir Path(runs/detect/glass_defect) out_dir.mkdir(parentsTrue, exist_okTrue) model YOLO(runs/insulator/glass_defect/weights/best.pt) conf_thres 0.25 iou_thres 0.45 imgsz 640 for img_path in sorted(src_dir.glob(*.jpg)): img cv2.imread(str(img_path)) results model.predict( sourceimg, confconf_thres, iouiou_thres, imgszimgsz, verboseFalse ) for r in results: for box in r.boxes: cls_id int(box.cls[0]) conf_score float(box.conf[0]) if conf_score conf_thres: continue x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) label f{model.names[cls_id]} {conf_score:.2f} cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, label, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite(str(out_dir / img_path.name), img) print(f{img_path.name} done) if __name__ __main__: main()model.predict传入的是cv2读取的numpy数组返回结果对象里保存了坐标、类别和置信度。box.xyxy[0]是tensor类型用map(int, ...)转成整数坐标才能画框。conf0.25是默认推荐值但对绝缘子小目标我会在验证集上分别试0.15、0.20、0.25三档看漏检和误检的取舍。iou0.45控制NMS框合并的激进程度设太低会把同一缺陷的多个检测框合并成一个设太高则一个缺陷出现多个框。verboseFalse避免每张图打印详细日志批量跑时省下大量I/O。4.3 从检测框到检测报告项目摘要里提到“生成相应的检测报告”工程上我一般把检测框汇总成JSON和CSV两种格式JSON给前后端项目实战里的Web平台调用CSV让运维人员在Excel中筛选。输出字段可以这样设计字段类型说明image_idstr原始图像文件名class_namestr缺陷类别scorefloat置信度bboxlist[x1, y1, x2, y2]areaint缺陷像素面积生成汇总的代码很简单# 生成检测汇总 report.py import csv, json def save_report(results_summary): with open(report.json, w, encodingutf-8) as f: json.dump(results_summary, f, ensure_asciiFalse, indent2) with open(report.csv, w, newline) as f: writer csv.DictWriter(f, fieldnamesresults_summary[0].keys()) writer.writeheader() writer.writerows(results_summary)results_summary是一个列表每个元素对应一个检测框。area字段在代码里通过bbox宽高相乘得到单位是像素。生成报告之前先按置信度降序排列优先展示最可疑的缺陷运维人员不用从几百行CSV里翻。4.4 效果展示中容易忽视的问题项目自带的1-4.png效果图展示了训练样本、增强结果和检测可视化。从实际测试看如果推理图像里的误检框集中在杆塔角钢、导线间隔棒附近问题通常不在模型而在第二章说的空标签覆盖不足。这时候回去跑一遍gen_empty_label.py再补一点背景负样本比直接调大conf有效得多。调大conf确实能减少误检但真实缺陷的置信度往往也在0.25附近阈值一提就把缺陷也滤掉了。5. 落地调参绝缘子小目标、玻璃反光与类别不平衡的处理技巧5.1 大图切片推理绝缘子串横跨整张巡检图时直接resize到640会把单个绝缘子压成十几个像素。我采用切片推理原图按512×512切patch相邻patch重叠20%每个patch单独跑模型再把检测框映射回原图坐标最后在整图上做一次NMS合并重叠框。切片尺寸不是固定的图像宽度超过2000像素时用原图宽度的1/4作为patch边长通常比较稳。5.2 玻璃反光引起的误检玻璃绝缘子表面的高光区域在纹理上和裂纹很像训练阶段增强太激进反而会加重视觉混淆。我一般在aug.py里把HSV饱和度扰动控制在±25%另加一个亮度模拟分支增强逆光拍摄的高光效果。推理阶段如果输入图像过暗先做一次CLAHE对比度增强但增强参数必须和训练阶段保持一致否则模型看到的特征分布变了mAP会明显下降。5.3 背景负样本的比例控制空标签文件本身没有类别信息但YOLO会把对应图像作为背景参与损失计算。经验值是无缺陷图占总图的30%到50%。太少时模型没见过足够背景误检率升高太多时模型过度保守真实缺陷也被当成背景。如果数据集里无缺陷样本很少最简单的办法是用cutout随机遮挡有缺陷的区域生成一张负样本而不是去网上找一堆风格完全不同的图片。5.4 看单类别AP而不是只看mAP绝缘子缺陷里自爆和破损在形态上接近污染又和玻璃老化相似整体mAP50过了0.85不代表每一类都可用。我会在Ultralytics的results目录里打开per-class AP曲线如果某个类别比其他类低15个百分点以上先补充该类别样本再考虑focal loss。实践证明复制同一张缺陷图三份做增强往往比修改损失函数带来的精度提升更直接。本文还有配套的精品资源点击获取
返回列表