基于YOLOv5与PyQt5的绝缘子缺陷检测系统实战

发布时间:2026/9/10 16:24:21
基于YOLOv5与PyQt5的绝缘子缺陷检测系统实战 简介基于YOLOv5与PyQt5实现输电线路绝缘子缺陷检测的完整项目资源面向电力智能运维研发人员、深度学习目标检测学习者及无人机巡检从业者。项目针对人工巡检效率低的问题提供无人机拍摄图片的绝缘子识别与定位方案压缩包共211个文件含53个YAML配置、51个Python脚本、预训练PT模型、GUI界面代码、JPEG/PNG样例图及训练教程文档等整体约83.6MB目录结构清晰便于按需取用。资源内置详细训练教程与标注配置可辅助读者从数据组织、模型训练到界面部署完整走通流程还可借助图形界面实时预览检测效果便于调试与演示。已有655人学习下载适合具备一定Python基础并希望快速落地YOLOv5检测项目的开发者参考。1. 从 zip 到能跑绝缘子缺陷检测系统的四段链路一个 zip 里塞着源码、权重和一份训练教程落地时最卡壳的往往不是模型精度而是三件事数据集目录没对齐、训练参数拍脑袋、PyQt5 推理把界面卡死。这套绝缘子缺陷检测系统的主体是 YOLOv5输入巡线图片或视频流后先由模型逐个框出自爆、破损、闪络等缺陷区域再用 PyQt5 包一层可操作的 GUI——选文件、看结果、导报告都在这里发生。读它之前先明确这是一条从零到能交付的全链路环境、数据、训练、界面四个环节都要走通跳过任何一段后面都补不回来。适合做输电线路运检系统、做毕设或者想把 CV 模型真正交到非算法同事手里的工程师。下面按实际动手顺序展开。2. 准备绝缘子缺陷数据集与环境标签对齐、PyQt5 安装一次到位2.1 为什么自爆缺陷检测还在用 YOLOv5网络结构与选型边界绝缘子缺陷里最难检的是自爆缺陷区域常常只有几十个像素。YOLOv5 的网络结构恰好覆盖这类小目标CSPDarknet 做骨干提取特征PANet 做多尺度融合P3 小目标检测头直接盯低层特征图anchor 机制对固定形态的瓷瓶碎片也比较友好。相比一上来就上 YOLOv8 或 Transformer 检测器YOLOv5 的优势不在单点精度而在整个生态断点续训、多卡、导出 ONNX、后处理替换这些工程步骤都有成熟约定配 PyQt5 时不需要为推理接口额外造轮子。GPU 资源有限或要求 30ms 级响应的场景yolov5s 是稳妥起点。有文章把 Transformer 模型详解讲得天花乱坠但实际项目中要算回本。自爆、破损这类缺陷类别少、背景变化受线路走廊约束CNN 的归纳偏置和小样本稳定性更省事Transformer 检测器要吃大量数据才能体现长程建模优势单类别缺陷数据通常喂不饱它。选型结论明确白天可见光巡视场景YOLOv5 够用把精力留给数据和后处理。2.2 数据集目录、标签格式与标注工具YOLOv5 的训练数据按 images 和 labels 两个根目录组织训练集、验证集分别在子目录里分开同一张图片的标注文件要放在对应路径下、只换后缀名。insulator_defect/ ├── images/ │ ├── train/ │ │ ├── img_0001.jpg │ │ └── img_0002.jpg │ └── val/ │ └── img_0100.jpg ├── labels/ │ ├── train/ │ │ ├── img_0001.txt │ │ └── img_0002.txt │ └── val/ │ └── img_0100.txt └── data.yaml标注文件每行对应一个目标框类别 id 加上归一化的中心点坐标和宽高。下面这行表示类别 0框中心在图片横向 51%、纵向 45% 的位置框宽占图片 3%、高占 1.9%0 0.5123 0.4567 0.0321 0.0189类别建议固定为0 自爆missing、1 破损broken、2 闪络flashover、3 正常normal。正常绝缘子也要参与训练否则模型会把完好的绝缘子也当成背景或误报缺陷这是缺陷检测项目里最常见的标注失误。标注工具用 X-AnyLabeling 或 labelImg 都可以它们都能直接导出 YOLO 格式的 txt自爆目标很小一定要在 1080p 原图上标注不要压缩后标否则框的边界会漂。下表是标注阶段最容易踩的坑建完数据集后逐项检查一遍再进训练检查项错误现象处理方式图像与标签文件名训练报 no labels found文件名去后缀后必须完全一致归一化坐标框画满全图检查 txt 中所有值是否在 0~1 之间类别 id训练时类别数对不上nc 与 names 列表长度一致从 0 开始编号空标签数据加载慢、loss 异常统计行数为 0 的 txt定位后补充或剔除样本2.3 conda 环境、PyTorch 与 PyQt5 安装命令环境建议独立创建不要直接装在 base 里训练和 GUI 调试在同一环境避免后面打包时出现依赖地狱。CUDA 版本先通过nvidia-smi确认下面按 CUDA 11.8 给一组常用组合conda create -n yolo_defect python3.8 -y conda activate yolo_defect pip install torch2.0.1 torchvision0.15.2 --index-url https://download.pytorch.org/whl/cu118 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt pip install pyqt55.15.10 pyqt5-tools安装顺序上先把 PyTorch 装完再装 requirements.txt因为 YOLOv5 的依赖里包含 torch 的常规版本后装会用 pip 自动解析并可能覆盖你刚配好的 CUDA 版本。PyQt5 放在最后装避免它和 OpenCV 的 Qt 插件冲突。装完后用一行命令验证训练侧环境import torch print(torch.__version__, torch.cuda.is_available())输出2.0.1 True表示 torch 能调用 GPUPyQt5 侧没有命令行验证手段直接用下面这段代码启动一个空窗口能弹窗说明 Qt 库和基础插件完整。import sys from PyQt5.QtWidgets import QApplication, QLabel app QApplication(sys.argv) label QLabel(pyqt5 ok) label.show() sys.exit(app.exec_())关于 PyQt5 的版本5.15.10 之后官方主要做维护性更新接口变化不大。如果安装时出现依赖解析非常慢的情况把--index-url换成清华或阿里镜像速度会快很多但 torch 的 CUDA 版本必须从 PyTorch 官方源装。2.4 用脚本切分训练集与验证集数据不多时手工拖文件可以但超过几百张图建议用脚本一次性切分防止耐心耗尽导致目录不齐。下面这个脚本把 images 和 labels 按比例同步切分并把文件移动到位import random from pathlib import Path random.seed(42) src_img Path(raw/images) src_txt Path(raw/labels) val_ratio 0.15 imgs list(src_img.glob(*.jpg)) list(src_img.glob(*.png)) random.shuffle(imgs) val_n int(len(imgs) * val_ratio) for i, img in enumerate(imgs): sub val if i val_n else train txt src_txt / (img.stem .txt) if not txt.exists(): continue # 跳过没有对应标注的图而不是放进训练集 img.rename(Path(finsulator_defect/images/{sub}) / img.name) txt.rename(Path(finsulator_defect/labels/{sub}) / txt.name)逻辑说明先把图片名单随机打乱按占比分成 val 和 train随后把同名的 .txt 一起移动。第 10 行的 continue 是关键保护空标签文件不会进入训练集能减少后面排查“某个 batch 全黑”的时间。切分完输出 train 和 val 两边的图片数量差的太多就检查是不是 glob 后缀没写全。3. 用 YOLOv5 训练绝缘子缺陷检测模型超参数与验证命令3.1 data.yaml 先写对再谈权重初始化训练前先写好数据集描述文件训练脚本第一优先读的就是它。路径用绝对路径最省心换机器时只改 path 一行path: /home/user/insulator_defect train: images/train val: images/val nc: 4 names: 0: missing 1: broken 2: flashover 3: normaltrain 和 val 的值相对于 path 拼接不要在 train 里写全路径否则换环境时到处飘红。权重初始化选--weights yolov5s.pt而不是空配置起步理由有三个预训练权重里的低层特征对瓷瓶纹理有迁移价值小数据集下收敛明显更快训练曲线更平稳方便判断数据质量问题。如果你想从零训练对比效果再把--weights 和--cfg yolov5s.yaml一起传。3.2 最短可跑通训练命令与必调参数表下面是直出模型的训练命令参数按 2000 张左右的数据量给python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 150 \ --cache ram \ --project runs/insulator_defect \ --name exp1 \ --patience 30 \ --device 0参数说明--img 640是输入分辨率自爆缺陷太小就不要降到 416640 是速度与召回率之间的合理值--batch 16在 12GB 显存上跑 yolov5s 比较稳想提速可提到 32 并打开 AMP--cache ram把所有图像一次性缓存进内存机械硬盘训练时也能把显卡喂饱但 16GB 内存的机器慎用改成--cache disk折中--patience 30表示验证集指标连续 30 个 epoch 不涨就提前终止省时间也防过拟合。下表列出训练过程中最常用的几个超参数修改它们直接影响最终部署在 GUI 里的检测效果参数推荐值说明lr00.01迁移学习数据量越小 lr0 越低0.005 更稳batch16~32过小 BN 不稳定loss 曲线抖动明显mosaic0.5~1.0自爆目标小mosaic 过高会切断碎片目标降到 0.1~0.3scale0.5控制训练时随机缩放的幅度小目标可调高到 0.9multi-scale开启每 10 个 batch 随机切换输入尺寸增强鲁棒性--hyp参数可以指定一个超参数文件例如--hyp hyp.scratch-low.yaml默认在轻量化增强配置下训练速度更快。改超参数时不要一次动三个以上否则模型不收敛时不知道是哪个改炸的。3.3 断点续训、类别不均衡与训练坑点训练中途断了不用从头来直接续python train.py --data data.yaml --weights runs/insulator_defect/exp1/weights/last.pt --resume简历读取的是 last.pt包含优化器和 epoch 信息确认 data.yaml 没改动即可。训练文件夹跑乱时--name可以改一个干净的实验名不要覆盖已有 exp1。自爆和闪络在数据集中占比低会导致类别不均衡常见做法是在线增强时对少数类提高复制概率或者在 loss 权重上偏向难例。YOLOv5 没有直接暴露类别权重参数更实用的办法是数据侧过采样把自爆图片复制 2~3 份文件名加后缀让每个 epoch 里能看见更多次。注意不要原地覆盖文件名类别分布虽然变了验证集要保持真实分布。3.4 训练完怎么验证看 mAP 还是看单图效果训练结束后先跑一遍验证脚本python val.py \ --data data.yaml \ --weights runs/insulator_defect/exp1/weights/best.pt \ --img 640 \ --conf-thres 0.25 \ --iou-thres 0.5输出里的 mAP0.5 是主指标mAP0.5:0.95更严格后者低一些正常。重点看每个类别的 AP自爆如果明显低于其他类说明小目标框的质量不行优先调 anchor 或者提高输入分辨率而不是盲目堆 epoch。验证完务必打开 runs/insulator_defect/exp1/ 目录下 val_batch0_pred.jpg 看可视化结果框是否贴边、是否漏了远处的碎片一个窗口就能看出来。GUI 里用的置信度阈值要和验证时保持一致否则评测指标和界面表现会互相矛盾。误检多就往 0.35 调漏检多就降到 0.15然后重新跑 val.py 衡量 mAP 代价。4. 用 YOLOv5 在 PyQt5 中做推理模型加载、线程与 GUI 结果展示4.1 GUI 先定交互流程再谈布局PyQt5 界面建议按“左图右表”的经典结构设计左侧 QLabel 显示检测画框后的图像右侧用 QTableWidget 列出每个缺陷类别和数量底部放置信度阈值滑杆和打开文件、打开摄像头按钮。不要一开始就追求皮肤和动画先把数据流走通。推理必须放在 QThread 里否则图片一多界面直接无响应这是 PyQt5 程序最常见的假死原因。开发时可以在 PyCharm 里配置 PyQt5 的外部工具Settings → Tools → External Tools 添加 designer.exe方便直接编辑 ui 文件。ui 文件生成 py 代码用pyuic5 -x demo.ui -o demo.py即可后续改动只改 ui 再重新生成不要手写界面代码效率差太多。4.2 把 YOLOv5 模型加载和推理封装成独立模块模型加载方式有 torch.hub.load 和 DetectMultiBackend 两条路。打包时 torch.hub 会额外找网络下载配置离线环境容易出问题我一般直接用 DetectMultiBackend 加载本地 pt路径明确后续导出 onnx 也方便。封装成一个类GUI、命令行、测试脚本都能复用import cv2 import torch import numpy as np class DefectDetector: def __init__(self, weights_path, conf_thres0.25, iou_thres0.5): self.conf_thres conf_thres self.iou_thres iou_thres self.device torch.device(cuda if torch.cuda.is_available() else cpu) # 直接加载本地权重不依赖 torch.hub 联网 self.model DetectMultiBackend(weights_path, deviceself.device) self.names self.model.names self.stride self.model.stride def infer(self, img_bgr): img letterbox(img_bgr, new_shape640, strideself.stride)[0] img img.transpose(2, 0, 1)[None] img torch.from_numpy(img).to(self.device) img img.float() / 255.0 pred self.model(img, augmentFalse, visualizeFalse)[0] pred non_max_suppression(pred, self.conf_thres, self.iou_thres) return pred[0].cpu().numpy() # x1 y1 x2 y2 conf cls逻辑说明letterbox 把任意尺寸图像等比缩放到 640 并补边这一步必须和训练时保持一致stride 用模型自带的用来自动对齐缩放倍数图像转成 CHW 后归一化到 0~1再送入模型NMS 在 non_max_suppression 里完成返回的数组前四列是框坐标第五列置信度第六列类别 id。这个类在后续 GUI 线程里被反复调用只做一件事图进框出。4.3 QThread 里做推理信号槽回传结果推理线程要避开一个坑不要在子线程里直接动控件。正确做法是把推理结果通过信号发回主线程主线程负责更新 QLabel 和表格。下面是一个可用的线程骨架from PyQt5.QtCore import QThread, pyqtSignal class DetectionThread(QThread): frame_ready pyqtSignal(object) # 画框后的图像 result_ready pyqtSignal(dict) # 类别统计 def __init__(self, detector): super().__init__() self.detector detector self.frame None self.running True def update_frame(self, frame_bgr): self.frame frame_bgr def run(self): while self.running: if self.frame is not None: frame self.frame boxes self.detector.infer(frame) stats {} for box in boxes: name self.detector.names[int(box[5])] stats[name] stats.get(name, 0) 1 x1, y1, x2, y2 map(int, box[:4]) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(frame, f{name} {box[4]:.2f}, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) self.frame_ready.emit(frame) self.result_ready.emit(stats) self.frame None self.msleep(5)代码里self.frame每次只保留最新一帧处理完才置空这样视频流模式下线程不会因为累积未处理帧而越来越卡。信号frame_ready携带画框后的 BGR 图像result_ready携带统计字典主线程连接这两个信号即可。注意手势不要在 run() 里调用 self.detector.infer() 时再去改界面上任何 QLabel那属于脏操作。4.4 主窗口打开图片、转换 QPixmap 与表格联动主窗口里点击按钮后用 QFileDialog 选图把图像送给线程。OpenCV 读进来的是 BGR转成 QPixmap 显示时要先转 RGB并显式设置每行字节数否则大图上会看到斜条状花屏from PyQt5.QtGui import QImage, QPixmap def bgr_to_pixmap(frame_bgr): rgb cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape qt_img QImage(rgb.data, w, h, ch * w, QImage.Format_RGB888) return QPixmap.fromImage(qt_img) # 槽函数里连接线程信号 def on_frame_ready(self, frame): self.image_label.setPixmap(bgr_to_pixmap(frame).scaled( self.image_label.size(), Qt.KeepAspectRatio)) def on_result_ready(self, stats): self.table.setRowCount(0) for row, (name, count) in enumerate(stats.items()): self.table.insertRow(row) self.table.setItem(row, 0, QTableWidgetItem(name)) self.table.setItem(row, 1, QTableWidgetItem(str(count)))ch * w是步长参数必须写否则图像宽度不是 4 的倍数时会错位。scaled 用 KeepAspectRatio 保持画框后的比例配合显示区域的尺寸自适应。表格联动直接清空重填就行数据量少别用笨重的 model/view 体系。摄像头场景同理只需把 OpenCV 的 VideoCapture 读取循环放在另一个线程里抓到帧后调用detect_thread.update_frame(frame)主界面就会持续刷新。关闭窗口时记得到closeEvent里把running置 False 并wait()否则线程不会销毁程序会卡在退出阶段。5. GUI 推理加速与交付ONNX 导出和 letterbox 坐标还原5.1 导出 ONNX 去掉 PyTorch 依赖交付给没有 GPU 的机器时onnxruntime 比 torch 轻得多。先导出再改推理代码一条命令完成python export.py --weights runs/insulator_defect/exp1/weights/best.pt --include onnx --opset 12对应推理侧改成import onnxruntime as ort sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name sess.get_inputs()[0].name # image 已经过 letterbox 并转为 (1,3,640,640) float32 outs sess.run(None, {input_name: image})onnx 输出的 shape 和 postprocess 与 pt 推理不同导出后要在本机用同一张图比对 pt 和 onnx 的输出框坐标偏差超过 1~2 个像素就检查预处理。ONNX 对 CPU 推理的提升明显换用 CPU 后一帧绝缘子图大约在 100~200ms满足单张检测视频实时预览压力大可先切到 480p 输入再推理。5.2 letterbox 坐标往返界面显示错位的头号原因画框错位最常见的原因不是模型错而是坐标没有还原。letterbox 会先在原图四周补灰边再缩放推理出来的框是补边后的坐标直接画回原图整体向右下偏移。还原公式是固定的img, ratio, (dw, dh) letterbox(frame, new_shape640, stridestride) # 推理得到 x1 y1 x2 y2 后 x1 (x1 - dw) / ratio y1 (y1 - dh) / ratio x2 (x2 - dw) / ratio y2 (y2 - dh) / ratioratio 是缩放比dw、dh 是补边的宽高。把这段放进 DefectDetector.infer 的返回值里GUI 画框时就不需要再知道模型内部细节。验证方法很直接拿一张 1280×960 的图检测框是否精确贴合缺陷边缘。也可以用带背景的绝缘子无人机图试一试框哪怕偏出瓷瓶一个宽度都不合格。5.3 PyInstaller 打包时保住模型和配置文件打包命令里最容易被漏掉的是模型文件和 yaml 配置pip install pyinstaller pyinstaller -F -w --collect-data ultralytics \ --add-data runs/insulator_defect/exp1/weights/best.pt;models \ --add-data data.yaml;. \ main_window.pyWindows 下;是分隔符Linux 用:。缺 Qt 插件会报could not find or load the Qt platform plugin windows把--collect-all PyQt5加进去即可。模型缺失不会启动时立刻报错只有在点“打开图片”后才崩溃所以打包完一定要跑一遍完整的“打开图片→检测→关窗”流程再发出去。给无显卡的同事分发时把 DefectDetector 切到 onnxruntime 推理并只带 best.onnx处理速度稳定且包体更小。conf 阈值建议做成配置文件放在 exe 同目录而不是硬编码在源码里这样现场人员不用重新打包就能调灵敏度。本文还有配套的精品资源点击获取