
简介输电线绝缘子缺陷检测数据集聚焦电力巡检场景提供已划分的YOLO格式图片与标注面向目标检测入门者及电力设施智能化巡检开发者可直接用于YOLO系列模型训练。数据包含约600张jpg图像和对应txt标签其中训练集约480张、验证集约120张类别仅defect一种同时提供独立的class文件用于类别名称映射。压缩包内共1203个文件整体大小42.88MB除图像标注外还包含1个无需修改即可运行的Python可视化脚本和1张示例图片随机传入任意一张图片即可绘制边界框并保存结果便于快速核查标注质量。目前该数据集已有123人学习浏览适合目标检测入门者、电力视觉项目开发者以及进行YOLO系列改进实验的研究人员使用小体量便于快速迭代实验。使用该数据集可省去数据整理与格式转换环节快速进入模型搭建和检测效果验证阶段。1. 输电线绝缘子缺陷图像检测数据集先看资源构成再定训练方案输电线路巡检照片堆在硬盘里绝缘子破损、自爆、闪络全靠人眼一格格看一天下来眼睛先投降。想训练一个目标检测模型替人盯图卡住你的往往不是模型结构而是数据图片有了标签对不对类别文件在哪数据划分做好没有这套输电线绝缘子缺陷图像检测数据集把图片、标签、类别 class 文件、数据可视化脚本打包在一起并已完成数据划分拿到手可以直奔训练。它面向的是输电线路视觉巡检这一具体场景解决的是“标注质量不可见、数据不可复现”的痛点。适合三类人做电力缺陷检测的算法工程师需要用完整流程跑通实验的研究生以及刚开始接触目标检测数据集处理、想照着完整样例动手的新手。后面的章节按“结构 → 划分 → 可视化 → 避坑 → 体检”的顺序展开每一步都能落到命令行和脚本上。2. 数据集的目录与标注格式image、label、class 文件如何一一对应拿到这种带 class 文件的数据集第一件事不是打开训练脚本而是把目录结构摸清楚。这类数据集的常见布局沿用的是 YOLO 生态的标准图片、标签、类别清单三者对齐之后训练器才知道去哪里读标注。目录不对后面每一步都会报错。2.1 目录骨架images / labels / classes.txt 先对齐先看最常见的一种目录组织方式YOLO 系训练器基本都认这套结构dataset/ ├── images/ │ ├── train/ # 训练图片约 70% │ ├── val/ # 验证图片约 20% │ └── test/ # 测试图片约 10% ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt # 类别清单一行一个类名 ├── data.yaml # 训练配置入口 └── visualize_labels.py # 标注可视化脚本images 与 labels 的子目录名必须完全一致train 对着 trainval 对着 val。YOLO 训练器找标签的规则是拿到图片路径后把 images 换成 labels、把后缀换成 .txt目录名只要错一个字母训练时就会报出大量 “label not found”。很多人以为数据集坏了其实是目录结构没对齐。classes.txt 每行一个类名行号从 0 开始就是类别 ID常见类别会包括正常绝缘子insulator、破损broken、自爆missing、闪络flashover等具体名称以数据集作者定义为准。train/val/test 的比例设定不止看数量还要看每个集合里缺陷类是否都出现。test 是最后要留出来做“闭卷考试”的数据调参阶段最好不要去碰。标题里写“已做数据划分”意思是这个动作作者已经完成了但你要知道它大概是按什么原则分的否则后面自己扩数据时很容易把划分原则破坏掉。这种 images/labels/class 的布局也对应目标检测常用标注工具LabelImg、X-AnyLabeling的默认导出习惯。你后续自己新增一批标注只要按同样结构丢进 images/all 和 labels/all再重新跑一次划分脚本就行。2.2 一条 YOLO 标签的解析归一化坐标还原成像素框labels 目录下的每个 .txt 文件和同名图片一一对应里面每一行代表一个目标框。下面这段代码把一行标注拆开并换算成可以直接画图的像素坐标# show_label.py —— 读取一条 YOLO 标注并还原成像素坐标 def yolo_line_to_pixels(line, img_w, img_h): cls_id, xc, yc, w, h line.split() cls_id int(cls_id) xc, yc, w, h map(float, (xc, yc, w, h)) x1 (xc - w / 2) * img_w y1 (yc - h / 2) * img_h x2 (xc w / 2) * img_w y2 (yc h / 2) * img_h return cls_id, (x1, y1, x2, y2) # 用法需要先拿到原图的真实宽高 img_w, img_h 4160, 3120 # 可以通过 cv2.imread(img).shape 获取 with open(labels/train/sample.txt) as f: for line in f: line line.strip() if not line: continue cls_id, box yolo_line_to_pixels(line, img_w, img_h) print(cls_id, box)这段代码把标签里每一行的 5 个数字拆开第一个是类别 ID对应 classes.txt 里的行号后四个都是 0 到 1 的归一化值表示框中心点坐标和框的宽高。注意这里是“中心点 宽高”格式不是“左上角 宽高”。这个格式很容易看错有人把 xc、yc 当成左上角画出来的框全部偏向右下而且越往右下偏得越厉害。img_w、img_h 一定要用原图真实分辨率从图片文件读取不要从文件名猜。这张图和标签一一对应图片分辨率不会写进标签文件里所以任何需要还原像素坐标的脚本都得先把原图读一遍。读图的开销不大但对你排查标注问题时非常关键。2.3 class 文件就是 ID 字典顺序错一个全部标签废掉classes.txt 看起来只是个文本清单价值在于把类别 ID 固定下来。假设文件内容是 insulator、broken、missing、flashover那么标签里第一列数字 0、1、2、3 就分别代表这四个类。如果有人打开 class 文件把 missing 和 flashover 换了一行标签不查不报错但模型训练出来的预测结果会整体错位可视化脚本一画框就会露馅。我处理多个数据集合并时会先建一个统一的类别映射表比如把某个旧数据集的 “cls_2” 映射到主清单的 “missing”再对整个 labels 目录做一次重写。宁可写一次性脚本把所有数字替换一遍也不要手工改 classes.txt 的顺序因为标签文件可能有上千个手工改早晚翻车。改完之后用 2.2 的解析函数抽查几张图确认类别数字和实际画面内容一致再进训练。如果你拿到的是 COCO 格式类别清单在 json 的 categories 字段里标注是像素坐标而不是归一化值标题里明确带 class 文件的数据集说明它更贴近 YOLO 生态。实际项目中经常需要写 COCO 转 YOLO 的脚本核心逻辑就是“像素坐标除以原图宽高、类别 ID 重映射一遍”这里不多展开。3. 数据划分7:2:1 之外绝缘子缺陷集还要防样本泄漏数据划分是这套数据集里已经替你做完的动作但收到手还是得先判断划分是否科学。划分不是把图片文件随机分到三个文件夹这么简单对于输电线路巡检图随机划分几乎必然造成数据泄漏验证集指标会好看得离谱。3.1 划分第一原则按杆塔/绝缘子串分组别按帧随机抽同一台无人机飞同一段线路拍同一个绝缘子串连续几张画面高度重叠。如果这些很像的图同时出现在 train 和 val模型相当于把“背诵过”的画面拿来考试val mAP 会很高一到新杆塔上 AP 直接掉。我一般会要求按拍摄任务分组同一杆塔、同一时段拍的一组图片放进同一个子集组与组之间不允许跨集合。第二个原则是分层抽样。绝缘子缺陷数据集天然类不平衡正常绝缘子几百张自爆可能就几十张。如果纯随机分val 或 test 里可能一个自爆样本都没有测出来毫无意义。做法是先统计每个组里缺陷类别的数量把组作为抽样单位用 stratify 参数保证三个集合都覆盖所有缺陷类别。常见比例是 train 70%、val 20%、test 10%。如果样本总量不到 300 张我会砍掉 test只保留 train/val用交叉验证代替固定测试集否则 test 里可能只有几十张图指标波动太大。3.2 划分脚本用 sklearn 做组级分层抽样# split_by_group.py # 按“组ID 类别标签”做分层划分保证同一杆塔的图不跨集合 import os, shutil from collections import defaultdict from sklearn.model_selection import train_test_split IMG_ALL images/all LAB_ALL labels/all groups defaultdict(list) for img in os.listdir(IMG_ALL): gid img.split(_)[0] # 约定文件名前缀是杆塔/拍摄任务 ID label_path os.path.join(LAB_ALL, img.replace(.jpg, .txt)) # 读取标签收集该组包含哪些类别 with open(label_path) as f: cls_ids sorted({line.split()[0] for line in f if line.strip()}) groups[gid].append((img, label_path, cls_ids)) # 为每个组生成一个代表标签是否含缺陷类作为分层依据 group_ids list(groups.keys()) group_y [1 if any(c in (1, 2, 3) for _, _, c in groups[g]) else 0 for g in group_ids] # 第一刀分出 train 70%其余 30% tr_groups, tmp_groups train_test_split( group_ids, test_size0.3, stratifygroup_y, random_state42) # 第二刀把 tmp 再按 2:1 分为 val / test tmp_y [1 if any(c in (1, 2, 3) for _, _, c in groups[g]) else 0 for g in tmp_groups] val_groups, test_groups train_test_split( tmp_groups, test_size1/3, stratifytmp_y, random_state42) for split_name, g_list in [(train, tr_groups), (val, val_groups), (test, test_groups)]: os.makedirs(fimages/{split_name}, exist_okTrue) os.makedirs(flabels/{split_name}, exist_okTrue) for g in g_list: for img, label, _ in groups[g]: shutil.copy(img, fimages/{split_name}/{os.path.basename(img)}) shutil.copy(label, flabels/{split_name}/{os.path.basename(label)})脚本先从文件名前缀提取组 ID比如 IMG_0451_01.jpg 里的 IMG_0451再遍历每个组里的标签文件收集该组出现过的类别集合生成组级标签向量。第一次 train_test_split 用 stratify 保证训练集和临时集合里的缺陷类别比例接近第二次把临时集合按同样方式切成 val 和 test。这样做之后同一个组内的图片永远只进入一个子集泄漏问题从源头堵住。test_size0.3 表示先留出 30% 给 valtest再 test_size1/3 是把这 30% 按 1:2 切相当于 val 20%、test 10%。random_state42 固定随机种子保证任何机器上重跑结果一致。stratify 依赖的组级标签是“是否含缺陷类”不是每个类别的精确数量如果你想更严格可以把组级标签改成多维向量每个缺陷类一列。注意如果某个缺陷类只出现在一个杆塔组里分层也无法保证 test 包含该类样本。此时优先补数据而不是硬调划分脚本。3.3 生成 data.yaml让 YOLO 系训练器直接认路划分完成后训练器需要一份配置文件告诉它数据在哪、有几个类。data.yaml 长这样# data.yaml —— 数据划分完成后的训练入口 path: /absolute/path/to/dataset # 改成你本地实际路径 train: images/train val: images/val test: images/test nc: 4 names: 0: insulator 1: broken 2: missing 3: flashover这是 YOLO 系列训练时都要读的配置。path 写绝对路径最省事如果写相对路径则相对于当前工作目录。train/val/test 的值是相对 path 的目录。nc 必须与 classes.txt 行数一致names 的顺序必须与 classes.txt 一致否则类别 ID 错位。很多人用 YOLOv8 系训练自己的数据集第一轮训练就报 “AssertionError: nc does not match” 或者出现标签 ID 越界问题大多出在这一步classes.txt 和 data.yaml 没对齐。最稳的做法是用 Python 读 classes.txt 自动生成 names 列表而不是手写手写少一行就是一次事故。这份文件在“已做数据划分”的数据集里通常已经写好你只需要把 path 改成自己机器上的路径。4. 数据可视化脚本训练前把标注质量摊开看拿到数据集先别急着训练。标注质量不检查模型就是在垃圾上拟合。可视化脚本的价值是把抽象的 txt 数字变成一张张画好框的图让标注错位、类别错误、框没贴边的“手滑”一眼暴露。4.1 画框脚本把 YOLO 标注画回原图# visualize_labels.py —— 检查标注质量 import cv2 import os # 从 classes.txt 读取类别顺序即 ID with open(classes.txt) as f: CLASSES [line.strip() for line in f if line.strip()] COLORS [(0, 255, 0), (0, 0, 255), (255, 0, 0), (0, 255, 255)] def yolo_line_to_pixels(line, img_w, img_h): cls_id, xc, yc, w, h line.split() cls_id int(cls_id) xc, yc, w, h map(float, (xc, yc, w, h)) x1 (xc - w / 2) * img_w y1 (yc - h / 2) * img_h x2 (xc w / 2) * img_w y2 (yc h / 2) * img_h return cls_id, (int(x1), int(y1), int(x2), int(y2)) def draw_one(img_path, label_path, out_path): img cv2.imread(img_path) img_h, img_w img.shape[:2] with open(label_path) as f: for line in f: line line.strip() if not line: continue cls_id, (x1, y1, x2, y2) yolo_line_to_pixels(line, img_w, img_h) color COLORS[cls_id % len(COLORS)] cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, CLASSES[cls_id], (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2) cv2.imwrite(out_path, img) # 批量对 val 全部画一遍 os.makedirs(vis/val, exist_okTrue) for f in os.listdir(images/val): label flabels/val/{f.replace(.jpg, .txt)} draw_one(fimages/val/{f}, label, fvis/val/{f})脚本先读原图拿真实宽高再把归一化坐标还原成像素框画到图上并写类别名。批量循环覆盖整个 val 集输出到 vis 目录。没有这个脚本你看到的标签只是一串数字画完框正常绝缘子被标成自爆这类问题会非常刺眼。类别名和颜色要从 classes.txt 读不要写死在代码里。如果 class 文件是 4 类而代码里写死 5 个颜色后来合并数据集时大概率越界。cv2.putText 的字体大小 0.8 是相对默认字体在 4K 原图上会偏小可以按图像宽度缩放font_scale img_w / 2000框线宽度同理。批量画框时顺手统计一下空标签文件。空标签在 YOLO 训练里不算错误但会让模型把该区域当背景。如果空标签占 30% 以上说明漏标严重需要退回占 5% 以内可以保留因为确实可能一张图里没有任何缺陷目标。4.2 统计脚本类别直方图与 bbox 尺寸分布# bbox_stats.py —— 对数据集做统计体检 import glob import matplotlib.pyplot as plt counts {} aspects [] for label in glob.glob(labels/**/*.txt, recursiveTrue): with open(label) as f: for line in f: line line.strip() if not line: continue cls_id, xc, yc, w, h line.split() cls_id int(cls_id) w, h float(w), float(h) counts[cls_id] counts.get(cls_id, 0) 1 aspects.append(w / h if h 0 else 0) # 类别直方图 plt.bar(counts.keys(), counts.values()) plt.xticks(list(counts.keys()), [line.strip() for line in open(classes.txt) if line.strip()]) plt.title(Class Distribution) plt.savefig(vis/class_dist.png) # 宽高比直方图 plt.hist(aspects, bins50) plt.title(BBox Aspect Ratio Distribution) plt.savefig(vis/aspect_dist.png)统计脚本遍历所有标签文件每行解析一次聚合出类别数量、宽高比分布。宽高比直方图尤其能反映绝缘子的特点整体绝缘子的框宽高比经常到 1:6 甚至更夸张如果训练器用的还是默认锚框你会在训练日志里看到正样本匹配率很低。这段统计能帮你决定两件事输入分辨率和锚框策略。如果大量 bbox 的归一化大边小于 0.05说明小目标很多训练和推理时都不要把图压到 640如果宽高比分布明显长条就不要手动锁默认锚框让 YOLO 训练前的自动锚框聚类自己算。4.3 把可视化脚本当验收工具从“玄学”到可复现跑一遍脚本不等于验收用脚本跑出来的结果做抽检记录才是。常见做法是每次清洗一批数据后从 val 里随机抽 50 张把画好框的图交给复核人统计框与目标边缘的贴合合格率连续三次抽检合格率低于 95%退回重标。这个动作能把“标注质量”从一句模糊的评价变成一个具体数字。这套可视化脚本的复用边界也需要说清楚换数据集时只需要改 classes.txt 和图片路径逻辑不用动但单张 4K 图上如果超过 50 个框输出图会字体重叠、看不清需要先按区域裁剪再画。不要小看这一步很多项目的模型在“理论上很好”的数据集上翻车最后回溯都是标注阶段的手滑。可视化脚本要做的就是让手滑在训练前现形。5. 避坑绝缘子缺陷检测数据集最常见的 5 个翻车点这部分是血泪经验。以下 5 个问题我在不同数据集上反复见到按出现频率排序逐个说清现象、原因和解决手段。5.1 缺陷样本太少自爆类 AP 接近 0先别急着调模型现象是训练完看各类别 AP正常绝缘子很高broken、missing、flashover 几乎为 0然后开始怀疑模型不行。原因在于缺陷类在数据集中占比常低于 5%而目标检测训练按 batch 全局统计少数类被多数类淹没。解决做法是先去 4.2 用直方图确认各类数量对缺陷类做复制粘贴增强把缺陷区域从原图抠出来贴到没有缺陷的背景图上注意贴的位置要符合实际绝缘子串附近不要贴到天空和导线空白处。再配合 mosaic 增强并给少数类的损失加权。不要一上来就换模型先把类别分布拉到能训练的比例。5.2 绝缘子是长条目标默认锚框匹配不上正样本少现象是训练时锚框匹配到的正样本少损失曲线居高不下或者检测结果里绝缘子被框成半截。原因是 YOLO 默认锚框面向通用目标接近正方形而绝缘子串整体的宽高比经常超过 1:5默认锚框与真实框的交并比达不到匹配阈值导致正样本不足。解决做法是训练时开启自动锚框聚类YOLOv5 和 YOLOv8 在训练前都会基于你的标签重新聚类锚框前提是别手动锁死默认锚。同时把输入分辨率提高长边建议 1280 以上。如果自动聚类后锚框数量还不够覆盖宽高比范围可以手动在模型配置里再加两个长条形锚框。5.3 高分辨率大图里的小缺陷缩到 640 就丢信息现象是 4K 无人机照片里自爆缺陷可能只占几十个像素整图缩到 640 后只剩两三个像素模型根本学不到。原因是常规训练流程把整图直接 resize小目标被下采样抹掉。解决做法是采用滑窗切图把 4K 图切成 1024 或 1280 的 patchoverlap 取 50%训练和推理都走切图流程。这种思路在遥感图像目标检测里是标配输电线路巡检图场景几乎可以照搬。推理时可以用 SAHI 库把 patch 结果拼回原图避免边界处漏检切图时注意不要把同一个目标切成两半还不留 overlap否则漏检率会明显上升。5.4 标注边界不统一同一个缺陷两种框法模型学到“手抖”现象是可视化脚本画框后发现同一类别的框大小忽大忽小有的只包住缺陷局部有的把整个绝缘子串都框进去损失函数在两种框之间震荡收敛很慢。原因是标注标准里没有明确“缺陷框的最小外接矩形边界”每个人按自己理解画。解决做法是在标注规范里写死“缺陷框必须框住缺陷最小外接矩形并保留不超过 5% 的边距正常绝缘子统一框整个瓷瓶组。”然后拿 200 张样本做重标用可视化脚本重新画框对比标注员之间的重合度不一致的退回。标注一致性检查是数据集质量里投入产出比最高的一项往往比换模型结构更见效。5.5 划分泄漏val 虚高上线就翻车现象是训练时 val mAP 超过 90%一到新杆塔实测 AP 掉到 60% 以下。原因是同一杆塔、同一架次拍的图被随机分到了 train 和 val相当于“开卷考试”。解决做法是按第 3 章的组级划分把同一任务 ID 的图片放进同一个子集。划分完成后抽检两个子集里是否存在文件名前缀一致的图片有就直接挪走重新划分。这个检查不是可选项我在每次换数据后都会跑一遍哪怕数据集作者说已经划分好了我也会用脚本验证一次因为文件在拷贝和二次整理过程中很容易被冲乱。6. 训练前跑一遍喂料体检验证脚本与检查清单6.1 三条命令先自查图片计数、标签计数、类别 ID# 图片数量与标签数量是否一致 find images/train -name *.jpg | wc -l find labels/train -name *.txt | wc -l # classes.txt 行数是否等于 data.yaml 的 nc cat classes.txt | wc -l # 检查标签文件里第一列的最大值是否越界 awk { if ($1 max) max $1 } END { print max } labels/train/*.txt第一个对比在 train、val、test 三个集合里都要做数量不一致说明有孤儿文件。标签多出来训练器不一定报错但会浪费时间图片多出来则意味着部分图没有被监督。awk 命令输出的数字是标签里最大的类别 ID它必须小于 classes.txt 的行数等于行数或更大就是越界立即查是哪一批文件造成的。6.2 喂料体检清单检查项通过标准失败处理图片/标签数量一致train、val、test 各自相等用脚本删除孤儿标签或孤儿图片类别 ID 不越界标签最大 ID classes.txt 行数写映射脚本重写标签空标签占比空 txt 不超过 5%剔除空标签图或退回补标可视化抽检随机 50 张框与目标贴合率 95%退回标注复核类别分布缺陷类数量占总标签 5%复制粘贴增强后再训练锚框匹配自动锚框聚类后覆盖 1:5 以上宽高比提高分辨率或手动加长条锚框这些检查都做完再进训练。我现在拿到任何数据集第一件事都是跑可视化脚本因为跳过它后面所有调参都会变成对着黑匣子猜猜错的成本比检查贵得多。希望帮到你。本文还有配套的精品资源点击获取