绝缘子缺陷识别数据集:COCO转YOLO与小样本目标检测实战

发布时间:2026/10/11 18:30:46
绝缘子缺陷识别数据集:COCO转YOLO与小样本目标检测实战
简介面向电力巡检与计算机视觉领域的工程师、科研人员和高年级学生这套绝缘子缺陷识别数据集可用于输电线路绝缘子缺陷检测模型的训练、验证与评估。数据覆盖盘损坏、绝缘子、污闪等典型缺陷标注正确识别率约92.5%能够作为深度学习目标检测任务中的直接训练样本。压缩包共1603个文件其中1598张jpg图片为原始可见光图像3个json文件为COCO格式标注结果2个txt文件用于说明类别与数据划分等信息压缩包整体大小79.74MB。数据组织方式清晰加载后即可用于模型训练目前已有702人学习下载。拿到这份数据后可直接用YOLO系或MMDetection等框架开展实验免去自行采集和标注的重复劳动也能按json中的类别字段筛选不同缺陷样本辅助分析模型在盘损坏、污闪等场景上的检测效果。数据集规模适中适合做小样本迁移学习、课程设计或算法论文的对比验证是一份工程实用性强、上手门槛较低的绝缘子缺陷检测数据集。1. 绝缘子缺陷识别数据集为什么1598张图能撑起92.5%的识别率绝缘子缺陷识别这几年在电力巡检项目里几乎是标配需求无人机绕着绝缘子串飞一圈回来把视频抽帧剩下的工作就是算法能不能在图上把破损、污闪这类缺陷框出来。这篇笔记要拆的正是一个1598张图片、COCO JSON格式标注的绝缘子缺陷识别数据集——标注了盘片破损、绝缘子本体、污闪三类目标给出92.5%的正确识别率。先给结论这个数量在深度学习里属于典型的小样本但配合迁移学习和合理的类别处理跑出90%以上的mAP50并不稀罕真正的坑反而不在模型在标注格式转换和类别不平衡。适合正在做电力视觉检测、无人机巡检算法以及一切被小数据集困扰的检测工程师参考。2. 翻开COCO JSON三类缺陷标注的结构、分布与解析拿到数据集第一步不是急着训练而是把COCO JSON彻底读懂。很多人栽在“JSON能打开”这个错觉上——能打开不代表结构对得上训练脚本更不代表类别分布能用。我一般会先回答三个问题标注了哪些类、框是什么坐标系、每个类有多少目标。这三个问题全答清楚才开始写训练代码。2.1 三个类别到底标注了什么盘片破损、绝缘子本体与污闪标题里写的“光盘损坏”在做绝缘子检测的项目里通常指盘片破损也就是瓷质或玻璃绝缘子伞裙的崩边、掉块、裂纹。这类缺陷是巡检最想抓的因为它直接关联到绝缘性能下降。第二个类别“绝缘子”指绝缘子本体实际训练里往往承担“定位”职责——先找到绝缘子在哪再去看上面有没有破损第三个“污闪”是污秽闪络留下的电灼痕迹表现为表面发黑、有闪络通道和破损的区域特征差异很大。这三类在COCO JSON里的记录方式相同都是一个多边形或边界框加一个category_id。COCO的边界框格式是左上的x、y坐标加宽高单位是图像像素不是归一化值。这一点必须时刻记住因为后面转YOLO格式时要做坐标变换一不小心就翻车。category_id类别名项目里的口语叫法典型视觉特征1disc_damage破损/光盘损坏/伞裙破损边缘缺损、裂纹、掉块形状不规则2insulator绝缘子本体成串的伞裙结构轮廓规整面积大3pollution_flash污闪/污秽闪络表面发黑、有树枝状放电痕迹颜色异常2.2 用json查询函数读懂annotations结构写出统计脚本COCO JSON的顶层一般有images、annotations、categories三块images里记录每张图的文件名和宽高annotations里才是真正的标注categories是类别表。我的习惯是先用Python把这三个字段的结构打印出来确认字段名没有特殊改动再写统计逻辑。有些标注工具导出的JSON只有bbox而没有segmentation或segmentation是空列表这不算坏数据但代码要能容忍。import json from collections import defaultdict coco_path annotations/instances_train.json with open(coco_path, r, encodingutf-8) as f: coco json.load(f) # categories: 拿到类别id到名称的映射 cat_id2name {cat[id]: cat[name] for cat in coco[categories]} print(类别映射:, cat_id2name) # 统计每个类别的目标数量 cat_count defaultdict(int) img_count len(coco[images]) for ann in coco[annotations]: cat_count[ann[category_id]] 1 print(图片总数:, img_count) for cat_id, name in cat_id2name.items(): print(f类别 {name}: {cat_count.get(cat_id, 0)} 个目标) # 查前5个标注的bbox字段确认是 [x, y, w, h] 还是别的顺序 for ann in coco[annotations][:5]: print(bbox样例:, ann[bbox], segmentation长度:, len(ann.get(segmentation, [])))逻辑说明这段脚本先读取COCO JSON建立category_id到类别名的映射再遍历annotations统计每个类别的目标总数。最后打印前几个bbox样例和segmentation长度用来确认数据格式是否符合预期。参数说明coco_path换成你本地实际路径如果数据集的categories定义里id不是从1开始而用了0那后面转YOLO格式做类别映射时要小心代码里不要硬编码id。2.3 数据体检1598张图的类别分布与标注框特点统计完数量还不够我建议再做一轮“数据体检”每个类别到底有多少目标、标注框的面积分布、整张图的分辨率范围。绝缘子缺陷场景有个共性规律绝缘子本体框往往又长又窄破损和污闪的框相对小。如果你的训练图像是4K航拍图模型输入缩到640时一个小破损可能只剩十几个像素这直接影响后面的训练策略。import os, json image_info {} with open(annotations/instances_train.json, r, encodingutf-8) as f: coco json.load(f) for img in coco[images]: image_info[img[id]] (img[width], img[height]) # 统计bbox面积按类别分组 area_dist defaultdict(list) for ann in coco[annotations]: x, y, w, h ann[bbox] area w * h area_dist[ann[category_id]].append(area) for cat_id, areas in area_dist.items(): areas.sort() print(f类别{cat_id}: bbox数量{len(areas)} 中位面积{areas[len(areas)//2]:.0f})逻辑说明这段脚本把每个标注框的面积按类别汇总输出目标数量和面积中位数。如果某一类目标数量只有几十个或者中位面积远小于其他类后续就要单独处理这类样本否则模型很容易把它忽略。参数说明面积用的是像素平方不同分辨率数据集之间没有直接可比性但同一个数据集内部可以横向对比统计完最好再随机挑几张图把标注画出来确认坐标没有错位。3. 把COCO JSON转成YOLO能吃的格式转换脚本与数据划分策略COCO格式不是不能直接训练mmdetection就能原生读取。但绝大多数做电力巡检落地的同事还是会选择YOLO系列原因不外乎生态成熟、部署方便、文档多。所以拿到这个数据集后我做的第一件事永远是写一个COCO转YOLO的脚本并且把训练集和验证集划分一并完成。3.1 为什么非转不可COCO格式与训练框架的适配YOLO系列训练时读取的标注是“每张图对应一个txt文件”每一行是“类别id 归一化中心x 归一化中心y 归一化宽 归一化高”。COCO是“一个JSON包含所有图的标注”而且坐标是左上角加宽高的像素值。两种格式之间不是简单改个后缀必须做坐标换算。更关键的是类别idCOCO的category_id和YOLO需要的类别序号往往不一致转格式时如果只复制不映射训练出来的模型会张冠李戴。另一个让我坚持转格式的原因是增量标注。cvat标注平台和labelme都能导出COCO JSON但团队里标注员更习惯导出后再转成YOLO的txt直接训练整个流程更短不用每次改训练框架的配置。3.2 COCO转YOLO的标注转换脚本以YOLO格式为例转换脚本的核心就是遍历annotations把每个bbox从[x, y, w, h]变成中心点和宽高再除以图片宽高做归一化。下面这段脚本我一直在用换数据集只改三个参数JSON路径、图片目录、输出目录。import json, os coco_json annotations/instances_train.json img_root images/train out_root labels/train os.makedirs(out_root, exist_okTrue) with open(coco_json, r, encodingutf-8) as f: coco json.load(f) # 类别映射把COCO category_id映射到连续的YOLO类别序号 # 注意必须和训练时data.yaml里的类别顺序一致 cat_mapping {1: 0, 2: 1, 3: 2} # disc_damage, insulator, pollution_flash img_id2info {img[id]: img for img in coco[images]} img_anns {} for ann in coco[annotations]: img_anns.setdefault(ann[image_id], []).append(ann) for img_id, anns in img_anns.items(): img img_id2info[img_id] width img[width] height img[height] txt_path os.path.join(out_root, img[file_name].replace(.jpg, .txt).replace(.png, .txt)) lines [] for ann in anns: if ann[category_id] not in cat_mapping: continue x, y, w, h ann[bbox] cx (x w / 2) / width cy (y h / 2) / height nw w / width nh h / height # 防止归一化后超出边界略作截断 cx min(max(cx, 0.0), 1.0) cy min(max(cy, 0.0), 1.0) nw min(max(nw, 0.0), 1.0) nh min(max(nh, 0.0), 1.0) yolo_cls cat_mapping[ann[category_id]] lines.append(f{yolo_cls} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) with open(txt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) print(f转换完成: {img[file_name]} - {txt_path}) print(COCO转YOLO结束)逻辑说明脚本先建立image_id到图片信息的映射再把每个标注按image_id分组。遍历每张图时用图片宽高把bbox换算成归一化的中心点坐标和宽高写入同名的txt文件。注意末尾对坐标做了截断防止浮点误差导致标注越界。参数说明cat_mapping必须手动确认COCO里的id和YOLO的类别序号不是一回事尤其是如果数据集categories里id从0开始映射表就要对应调整图片后缀名我习惯统一用小写如果文件名大小写混用这里的replace也要做兼容。转换后一定要抽查。我见过最贵的翻车就是白转换了半天最后发现文件名对不上训练时一半图片没有标注。3.3 训练集与验证集划分按图划分而不是按目标划分划分数据集有条铁律必须按图片划分不能按目标划分。如果同一张图既出现在训练集又出现在验证集相当于模型见过答案再考试mAP虚高没有任何意义。电力巡检视频抽帧出来的图像往往高度连续相邻帧几乎一样随机划分时这张进了训练集那张进了验证集性能会好看得一塌糊涂换到真实无人机数据立刻露馅。import os, random all_images [f for f in os.listdir(images/train) if f.endswith((.jpg, .png))] random.seed(42) random.shuffle(all_images) val_ratio 0.15 val_count int(len(all_images) * val_ratio) val_set set(all_images[:val_count]) train_set set(all_images[val_count:]) print(f训练集图片数: {len(train_set)}验证集图片数: {len(val_set)}) with open(train.txt, w) as f: for name in train_set: f.write(fimages/train/{name}\n) with open(val.txt, w) as f: for name in val_set: f.write(fimages/train/{name}\n)逻辑说明固定随机种子后把图片列表打乱按比例拆成训练集和验证集并输出文件清单供训练框架读取。注意valid是validate的常用缩写不是valid数据。参数说明val_ratio我一般设15%到20%这个数据集1598张图15%意味着验证集约240张每个类别的目标数量还不算太少如果某个类别目标极少建议再做一次分层划分保证验证集里至少出现该类别的样本否则指标会失真。4. 训练配置决定成败小样本目标检测的调参要点数据转好、路径配好接下来就是训练。很多人以为训练就是把命令跑起来等结果实际上1598张图的数据集对超参非常敏感。参数调不准模型不是过拟合就是不收敛这部分是整条链路里最需要花时间的地方。4.1 预训练权重小样本的起点别从零开始从随机权重训练1598张图的目标检测器结果大概率惨不忍睹因为数据量不足以让模型学到丰富的视觉特征。常见做法是加载COCO预训练权重做迁移学习。就算COCO的类别是人的日常物体模型在COCO上学到的边缘、纹理、形状特征对绝缘子的伞裙结构同样有效。现在不少新检测器像DEIM这类也会放出自己训好的COCO预训练权重如果框架支持优先选与部署backbone匹配的权重。我一般会在训练脚本里设置一个参数前10到15个epoch冻结backbone只训练检测头让模型先适应新数据集的目标尺度等loss稳定后解冻再整个网络一起微调。对这类小数据集这个策略远比一上来就全量训练稳定。4.2 训练超参数图片尺寸、batch、学习率与epoch绝缘子破损是典型的小目标问题输入图片尺寸直接决定小目标存活的概率。1024或1280会比640有明显改善但显存占用也会涨。batch size看显卡显存8或16是常见选择。学习率从0.01起步比较安全小数据集上过大的学习率会在前几个epoch就把预训练权重毁掉。epoch设在50到80之间配合早停。超参数推荐值说明imgsz1024或1280破损框很小尺寸太低压不住漏检batch8到16显存够就取大值小batch配合小学习率lr0.01开始可配余弦衰减迁移学习阶段不要超过0.05epochs50到80小数据集训太久一定过拟合patience10到15验证mAP连续不升就停下面是一份使用YOLO系列训练这个自己数据集的data.yaml和命令把路径和类别换成自己的即可。# data.yaml path: /data/insulator_defect train: train.txt val: val.txt names: 0: disc_damage 1: insulator 2: pollution_flashyolo detect train \ modelyolov8n.pt \ datadata.yaml \ imgsz1280 \ epochs60 \ batch16 \ lr00.01 \ patience12逻辑说明data.yaml定义了数据集根路径、训练集与验证集的图片清单、类别名names的索引顺序必须和前面COCO转YOLO时用的cat_mapping一致。训练命令加载COCO预训练权重指定图像尺寸1280训练60轮早停耐心值12轮。参数说明如果你显存有限imgsz先降到1024batch改成8时学习率相应降到0.005左右batch减半学习率不减会导致梯度震荡。4.3 数据增强参数把增强开大不一定好YOLO默认开启mosaic、随机翻转、HSV扰动等增强对小数据集确实有用但绝缘子缺陷场景有个特殊点污闪特征依赖颜色变化HSV增强里的色相和饱和度扰动一旦开太大污闪样本的外观会被改得面目全非模型学不到真实特征。这个增强参数就属于“越用力越坏事”。我一般会把hsv_h从默认的0.015降到0.005hsv_s从0.7降到0.2保留几何增强和翻转。mosaic保持开启能有效提升模型对遮挡和小目标的鲁棒性。增强参数的调整没有绝对最优关键是想清楚你的缺陷特征依赖什么保护它不被破坏。5. 避坑小样本绝缘子检测最容易翻车的5个点这部分是我在这类小样本缺陷检测项目里的血泪经验。每一条都真实发生过每一条都能通过肉眼观察指标或文件提前发现不需要什么高深的黑匣子诊断技巧。5.1 训练loss一路下降验证mAP却在原地打转现象训练loss稳定下降看起来一切正常验证集mAP却几乎不涨甚至反复震荡。原因最常见的是学习率偏大加数据增强过强模型在训练集上不断拟合增强后的噪声没学到稳定的类别特征。其次是数据划分问题验证集和训练集重叠严重或验证集样本太少导致mAP波动剧烈。解决先关闭mosaic和旋转增强训一轮验证mAP是否立刻改善再把学习率降到之前的五分之一重新训练。如果指标恢复说明是增强过强逐步恢复增强并观察验证集表现。最后确认划分时使用的是固定随机种子不会每次训练得到不同验证集。5.2 转换后所有框都变成了同一类现象训练时某个类别完全检不出来打开预测结果一看模型把大量目标都预测成同一个类别。原因COCO转YOLO时类别映射写错比如COCO的category_id从0开始而cat_mapping里却写了{0:0, 1:1, 2:2}结果把类别顺序整体错位。另一个可能是data.yaml的names顺序和转换脚本的cat_mapping不一致。解决转格式后必须抽查txt文件。随意打开一张图对应的txt把前几个标注的类别id和原图标注画出来对照。这一步十分钟就能做完但能省下好几个小时的训练时间。我现在的习惯是转换完立刻写一个可视化脚本把标注画回图上确认。5.3 破损碎片目标小整图推理基本漏检现象验证集里绝缘子本体检得挺好破损和污闪的漏检率很高尤其破损碎片只有几十个像素时几乎全部漏掉。原因输入图像缩放到640或1024时小目标的像素占比太小下采样后特征几乎消失。这是目标检测的经典困境不是模型单一参数能解决的。解决优先把imgsz提到1280如果显存不够把原图按绝缘子串位置裁剪成多个区域分别推理。另一种思路是对破损类别单独训练一个“放大检测器”先检测绝缘子串再在绝缘子区域内检测破损相当于两阶段定位。这类两阶段做法在电力巡检项目里很常见比硬调一个大模型管用得多。5.4 污闪类样本太少验证集上recall惨不忍睹现象训练结束后污闪类别的recall远低于其他类别甚至为零。同类问题在破损类别上也会出现。原因1598张图里如果污闪目标只有几十个类别分布严重不平衡模型训练时绝大多数负样本来自其他类别污闪类别学不透。这就是标题里92.5%正确识别率背后隐藏的真相——整体指标好看不代表每个类别都能用。解决最简单的办法是给少数类别提高权重或复制少样本图片增强其采样频率。也可以把含有污闪的图片单独抽出来做精细增强后再加入训练集。如果目标检测框架支持每个类别的loss加权给污闪类别2到3倍权重能明显改善。数据扩充的长期方案放在最后一章说。5.5 COCO JSON里segmentation字段为空导致的解析翻车现象写脚本读取标注时有的annotations没有segmentation字段有的有但内容是空列表按统一逻辑读取时报错或者把空列表当成无效标注丢掉。原因标注工具导出COCO格式时有些框是由算法自动生成的只写了bbox没有画多边形所以segmentation为空。这不是坏数据只是格式不完整。解决训练目标检测时只要bbox有效就足够读取代码要兼容segmentation缺失的情况。我的写法是用ann.get(segmentation, [])而不是直接索引。此后再确认bbox四项都是正数宽高不小于1就当作合法标注。6. 从92.5%到可交付验证指标、误检分析与三个扩数据方向前面说的都是“怎么跑通”最后落到“怎么交付”。92.5%是个漂亮数字但你给客户看的时候不能只说正确识别率还得证明指标可信、知道哪里会误检以及对新场景有持续扩数据的手段。6.1 用mAP复现92.5%的正确识别率正确识别率在目标检测里通常不是一个标准指标。客户说的92.5%落到工程师嘴里可能是mAP50、mAP50-95也可能是精确率。我的建议是以mAP50为主指标mAP50-95做参考两个一起报。mAP50在90%以上算正常水平mAP50-95落在70%上下也不意外毕竟小目标和多类不平衡会拖低高IoU指标。训练结束后直接看each_class的AP确认三个类别之间没有谁被牺牲掉。yolo detect val modelruns/detect/train/weights/best.pt datadata.yaml imgsz1280逻辑说明这条命令用训练时保存的best.pt在验证集上跑评估输出整体mAP和每个类别的AP。参数说明imgsz必须和训练时一致否则mAP会偏差如果希望在测试集上评估把data.yaml里的val指向测试集清单。评估结果里如果某一类的AP比平均低20个百分点那就回到第5章的避坑清单逐个排查。6.2 从混淆矩阵找误检方向yolo训练完会在结果目录里自动生成混淆矩阵和预测样例图这一步不要跳过。混淆矩阵里如果破损和绝缘子本体互相混淆说明两类在语义上确实有交叠——破损的伞裙区域本质上是绝缘子的一部分模型区分不了边界很正常。处理方法是在标注时给破损目标更严格的边界只标明显缺损的区域不要把整串绝缘子圈进去。如果污闪被误检为破损多半是颜色特征被HSV增强破坏回看第4章的增强参数。6.3 让数据集变厚的三个落地方向1598张图总有被榨干的时候。第一个方向是用cvat这类标注平台组织标注员对新增巡检视频抽帧补标导出COCO JSON后继续走第3章的转换流程第二个方向是视频抽帧做半监督用现有模型给无标注帧打伪标签人工只修正高置信度误检能把标注成本降一半第三个方向是按缺陷类别扩充难题样本比如专门收集污闪、破损严重样本而不是再补一万张没有缺陷的绝缘子正常图——对模型来说正常图再多也不如几十张有缺陷的难样本有价值。我在这类电力巡检项目里的习惯是每次模型交付都附带一份“可复现说明”把数据划分随机种子、增强参数、训练命令写成固定配置免得好不容易跑出来的结果过两周就复现不了。数据集小更需要这种纪律性。希望这些经验能帮你在自己的绝缘子缺陷识别数据上少走一段弯路做出真正能扛住野外巡检的模型。本文还有配套的精品资源点击获取