简介:本资源为面向输电线路电力金具检测任务的YOLO目标检测数据集,适合电力巡检、计算机视觉方向的学习者与算法工程师使用,可解决真实场景下金具样本获取难、标注格式不统一的问题。压缩包共约2000个文件,整体819.31MB,以1985个xml标注文件为主,另含少量txt、html与py脚本,分别对应标签数据、环境搭建与训练教程文档以及数据集划分工具。资源采用labelimg标注,标注框质量较高,同时提供voc、coco和yolo三种格式标签,分文件夹存放,可直接接入YOLO系列模型训练。随包附赠环境搭建、训练案例教程与训练集、验证集、测试集划分脚本,便于按需自定义数据划分。目前已有210人学习下载,适合希望快速复现电力金具检测实验、搭建完整训练流程的读者参考使用。
1. 输电线路电力金具检测:为什么 10000 张图的数据集值得先跑通再谈模型
输电线路巡检从人工登塔拍照转向无人机自动巡检之后,真正的瓶颈早就不是飞不飞得起来,而是拍回来的几万张图里,螺栓、销钉、防振锤、均压环这些电力金具到底有没有缺陷。我见过太多团队一上来就调 YOLO 结构、换主干网络,结果 mAP 卡在 0.5 上不去,回头一查,训练集里一半图片的标注框是歪的,还有几百张图压根没有对应标签文件。这个标题里的东西——10000 张输电线路电力金具图片,配 VOC、COCO、YOLO 三种格式标签,外加划分脚本和训练教程——本质上解决的就是这个前置问题:让你在动手改模型之前,先把数据这一关走顺。
它适合三类人:刚接触 YOLO 目标检测、想找一个真实工业场景练手的新手;手里有巡检图但标注格式混乱、需要统一到 YOLO 训练管线的算法工程师;以及做电力智能巡检产品、需要快速验证金具缺陷检测可行性的落地团队。数据集本身不是终点,它是让你把「数据准备 → 格式转换 → 划分 → 训练 → 验证」这条链路完整跑一遍的载体。下面我按自己实际处理这类数据集的顺序,把每一步拆开讲。
2. 三种标签格式到底怎么选:VOC、COCO、YOLO 的差异与转换逻辑
2.1 先搞清楚三种格式各自长什么样
VOC 格式是 XML 文件,一张图对应一个.xml,里面用<object>节点记录每个目标的类别名和边界框的xmin/ymin/xmax/ymax。它的特点是可读性好,用文本编辑器打开就能看懂,但解析起来要写 XML 解析代码,而且坐标是绝对像素值,换分辨率就得重算。
COCO 格式是一个大的 JSON 文件,所有图片、标注、类别都塞在同一个annotations.json里。图片信息在images数组,标注在annotations数组,类别在categories数组,标注框用[x, y, width, height]表示,同样是绝对像素。它的优势是标准化程度高,很多评测脚本和预训练模型直接吃 COCO 格式,缺点是单文件巨大,改一条标注要动整个 JSON。
YOLO 格式最简单,一张图对应一个.txt,每行是类别索引 中心x 中心y 宽 高,全部归一化到 0~1 之间。它没有类别名,类别靠一个classes.txt或data.yaml里的names列表按索引对应。训练时读取最快,但可读性最差,脱离类别列表就看不懂。
| 格式 | 文件形态 | 坐标表示 | 类别存储 | 适合场景 |
|---|---|---|---|---|
| VOC | 每图一个 XML | 绝对像素 xmin/ymin/xmax/ymax | XML 内 name 字段 | 标注工具交换、人工检查 |
| COCO | 单个 JSON | 绝对像素 x/y/w/h | categories 数组 | 标准化评测、多模态预训练 |
| YOLO | 每图一个 TXT | 归一化中心点+宽高 | 外部 names 列表 | YOLO 系列直接训练 |
2.2 从 VOC 转 YOLO:一个能直接用的转换脚本
实际拿到手的原始标注大概率是 VOC 格式,因为 LabelImg 这类工具默认就导出 XML。要喂给 YOLO,必须先转成归一化 TXT。下面这个脚本我用了很多次,处理电力金具这种类别不多(通常 5~15 类)的场景足够稳。
import os import xml.etree.ElementTree as ET # 类别列表,顺序决定 YOLO 标签里的类别索引,必须和 data.yaml 的 names 一致 CLASSES = ["bolt", "pin", "damper", "grading_ring", "insulator"] def convert_voc_to_yolo(xml_dir, out_dir, classes): os.makedirs(out_dir, exist_ok=True) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(".xml"): continue tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() # 读取图片宽高,用于归一化 size = root.find("size") w = int(size.find("width").text) h = int(size.find("height").text) lines = [] for obj in root.iter("object"): name = obj.find("name").text if name not in classes: continue # 跳过不在类别表里的目标,避免索引错乱 cls_id = classes.index(name) 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) # 转成中心点+宽高的归一化值 cx = (xmin + xmax) / 2.0 / w cy = (ymin + ymax) / 2.0 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}") txt_name = os.path.splitext(xml_file)[0] + ".txt" with open(os.path.join(out_dir, txt_name), "w") as f: f.write("\n".join(lines)) convert_voc_to_yolo("annotations_xml", "labels_yolo", CLASSES)逻辑说明:先解析 XML 拿到图片宽高,再遍历每个object,把绝对坐标转成归一化中心点格式。CLASSES的顺序就是最终 YOLO 标签里的类别索引,一旦定了就不能改,否则标签全错。参数上,xml_dir是 VOC 标注目录,out_dir是输出 TXT 目录,classes必须和训练时data.yaml的names完全一致。如果某张图没有目标,会生成一个空 TXT,这是正常的,YOLO 训练时会把空标签当作负样本。
2.3 COCO 格式的用途和转换注意点
COCO 格式在这个数据集里更多是给评测和跨框架用的。如果你要用 MMDetection 或者做 COCO mAP 评测,就需要把 VOC 或 YOLO 转成 COCO。转换时最容易翻车的地方是category_id必须从 1 开始,不能从 0 开始,而 YOLO 的类别索引是从 0 开始的,中间要做一次加一。另外 COCO 的bbox是[x, y, width, height],不是[xmin, ymin, xmax, ymax],转换时width = xmax - xmin,别直接抄 VOC 的坐标。图片的id和标注的image_id要能对上,建议用文件名哈希或递增整数统一管理,否则评测时会出现大量漏检。
3. 数据集划分脚本:训练集、验证集、测试集怎么分才不翻车
3.1 划分比例不是拍脑袋,要看类别分布
电力金具检测有个特点:正常样本远多于缺陷样本,而且不同金具出现频率差异大。如果直接按 8:1:1 随机分,很可能某个稀有缺陷类别在验证集里一张都没有,训练时 loss 降得好看,一验证就崩。我一般先统计每个类别的实例数,再按类别做分层抽样。10000 张图如果缺陷样本占比低,训练集可以放到 8.5 甚至 9,验证集留 0.5~1 就够,测试集单独留一批不同线路、不同拍摄批次的图,用来验证泛化。
import os import random from collections import defaultdict def split_dataset(label_dir, img_dir, out_txt, ratios=(0.8, 0.1, 0.1), seed=42): random.seed(seed) # 按类别统计每张图包含哪些类别,用于分层 img_to_classes = defaultdict(set) for txt in os.listdir(label_dir): if not txt.endswith(".txt"): continue stem = os.path.splitext(txt)[0] with open(os.path.join(label_dir, txt)) as f: for line in f: if line.strip(): img_to_classes[stem].add(line.split()[0]) # 按主类别分组,保证每个类别在验证集有代表 groups = defaultdict(list) for stem, classes in img_to_classes.items(): key = sorted(classes)[0] if classes else "empty" groups[key].append(stem) train, val, test = [], [], [] for key, stems in groups.items(): random.shuffle(stems) n = len(stems) n_train = int(n * ratios[0]) n_val = int(n * ratios[1]) train += stems[:n_train] val += stems[n_train:n_train + n_val] test += stems[n_train + n_val:] with open(out_txt, "w") as f: for name, lst in [("train", train), ("val", val), ("test", test)]: for stem in lst: f.write(f"{name}/{stem}\n") split_dataset("labels_yolo", "images", "split.txt")逻辑说明:先扫描所有标签文件,记录每张图包含的类别集合,再按类别分组做分层抽样,避免稀有类别全被分到训练集。ratios是训练/验证/测试比例,seed固定后结果可复现。输出split.txt每行是子集/文件名,后续生成 YOLO 的train.txt、val.txt时直接按这个文件过滤即可。注意图片和标签必须同名同 stem,否则对不上。
3.2 划分完必须做的两项检查
第一项是数量核对:训练集、验证集、测试集的图片数加起来必须等于原始总数,不能有遗漏或重复。第二项是类别覆盖核对:统计每个子集里每个类别的实例数,如果验证集里某个类别实例数为 0,要么调整分层策略,要么在训练时对该类别做重采样。我习惯把这两项检查写成一个小脚本,每次划分完跑一遍,比事后翻车再回头查省事得多。
提示:划分脚本里的随机种子一定要固定并记录,否则换台机器跑出来的划分不一样,实验没法复现。
4. 用 YOLO 训练电力金具检测模型:配置、命令与参数调优
4.1 环境准备与 data.yaml 配置
训练前先把目录结构理清楚。常见做法是images/train、images/val、labels/train、labels/val分开,然后写一个data.yaml指向这些目录。YOLOv8 及之后的版本用 YAML 配置,老版本 YOLOv5 也类似。
# data.yaml path: /data/power_fittings train: images/train val: images/val test: images/test nc: 5 names: ["bolt", "pin", "damper", "grading_ring", "insulator"]nc是类别数,必须和names长度一致,也必须和转换脚本里的CLASSES长度一致。path是数据集根目录,train/val/test是相对路径。如果路径写错,训练启动时会直接报找不到图片,不会静默跳过,这点比某些框架友好。
4.2 启动训练的命令与关键参数
yolo detect train \ data=data.yaml \ model=yolov8s.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ patience=30 \ workers=8 \ project=runs/power_fittings \ name=exp1参数说明:model选yolov8s是精度和速度的折中,电力金具目标通常不大,yolov8n可能欠拟合,yolov8m以上在 10000 张图上容易过拟合。imgsz=640是默认值,如果金具在图中占比很小,可以提到 960 或 1280,但显存和训练时间会明显上升。batch=16在 8G 显存上比较稳,显存不够就降到 8 并配合accumulate。lr0=0.01是初始学习率,lrf=0.01是最终学习率比例,patience=30表示 30 轮没有提升就早停。workers按 CPU 核数设,设太大反而会拖慢数据加载。
4.3 训练过程中该盯哪些指标
启动后重点看三个东西:box_loss是否稳定下降、mAP50是否在验证集上持续上升、cls_loss有没有异常波动。如果box_loss降但mAP50不涨,大概率是标注框质量问题,回去检查转换后的 TXT 有没有越界或宽高为负。如果cls_loss震荡厉害,可能是类别不平衡,考虑对稀有类别做过采样或调整损失权重。训练日志里还会输出每类的 AP,电力金具里螺栓和销钉容易混,如果这两类 AP 明显低于其他类,说明特征区分度不够,可以尝试提高输入分辨率或增加这两类的样本。
5. 避坑与排查:电力金具数据集训练中最容易翻车的 5 个点
5.1 标签文件与图片不对应,训练时大量图片被跳过
现象:训练日志显示train: 0 images或实际加载图片数远少于预期。原因:图片和标签的 stem 不一致,比如图片叫IMG_001.jpg,标签叫IMG_001.xml.txt,或者划分脚本输出的路径和data.yaml里的目录结构对不上。解决:写一个校验脚本,遍历images目录,检查每个图片文件在labels目录下是否有同名.txt,没有的就列出来人工处理。同时确认data.yaml里的train路径是相对于path的,不要写成绝对路径又拼错。
5.2 归一化坐标越界,导致训练 loss 异常
现象:训练初期box_loss就很大,或者出现 NaN。原因:VOC 转 YOLO 时,某些标注框的xmax超过了图片宽度,或者xmin > xmax,归一化后中心点或宽高超出 0~1 范围。解决:在转换脚本里加边界裁剪,xmin = max(0, min(xmin, w)),xmax = max(0, min(xmax, w)),宽高同理,并且过滤掉宽或高小于 1 像素的无效框。转换完再跑一遍统计,看有没有坐标不在 0~1 之间的行。
5.3 类别索引错位,模型把螺栓认成销钉
现象:训练能跑,但混淆矩阵里两个类别大量互错,或者验证时类别名和实际对不上。原因:转换脚本里的CLASSES顺序和data.yaml里的names顺序不一致,或者中途增删了类别但没重新生成标签。解决:把类别列表单独存一个classes.txt,转换脚本和data.yaml都从这个文件读取,保证唯一来源。每次改类别后,必须重新跑一遍转换和划分,不能只改 YAML。
5.4 验证集里稀有类别实例为零,mAP 虚高
现象:整体mAP50看起来不错,但某个类别 AP 为 0 或者没有显示。原因:随机划分时稀有缺陷类别全被分到训练集,验证集里没有该类别样本,评测时该类直接不计入或计为零。解决:用分层抽样划分,确保每个类别在验证集里至少有 10~20 个实例。如果某类总实例数本来就少于 50,考虑把它合并到相近类别,或者单独做一轮针对性训练。
5.5 图片分辨率与模型输入不匹配,小目标漏检严重
现象:大金具检测正常,螺栓、销钉这类小目标大量漏检。原因:原始巡检图分辨率很高(比如 4000×3000),直接缩放到 640 后小目标只剩几个像素,特征丢失。解决:训练时提高imgsz到 960 或 1280,或者先对原图做切块,把大图裁成带重叠的小图再标注和训练。切块时注意重叠区域要足够大,避免目标被切断。推理时也可以用同样的切块策略,再把结果拼回去。
6. 从能跑到好用:提升电力金具检测精度的几个实操技巧
数据集跑通、模型能训练之后,真正决定能不能上线的,是那些训练脚本之外的细节。我自己的习惯是,每次实验前先固定一个基线,比如yolov8s + imgsz 640 + 150 epochs,记录下各类 AP,然后每次只改一个变量,看哪类指标动了。电力金具检测里,提升最明显的往往不是换模型,而是数据层面的调整。
第一个技巧是难例挖掘。训练完一轮后,用模型在验证集和测试集上推理,把漏检和误检的图挑出来,人工重新检查标注。我遇到过一批防振锤的图,标注框只框了锤头没框到连接线,模型学到的特征就是残缺的,补标之后该类 AP 直接涨了十几个点。这个流程可以迭代两三轮,每轮都能挤出一些精度。
第二个技巧是锚框和输入尺寸的匹配。YOLO 默认锚框是基于 COCO 聚类的,电力金具的宽高比和 COCO 里的常见目标差别很大,螺栓偏细长,均压环偏圆。如果用的是带锚框的 YOLO 版本,建议在自己的训练集上重新跑一遍 k-means 聚类,生成适配的锚框尺寸。输入尺寸方面,如果小目标多,imgsz提到 960 通常比换更大的模型更划算。
第三个技巧是推理阶段的置信度和 NMS 阈值调整。训练时的默认阈值不一定适合上线。电力金具缺陷检测通常宁可误报也不能漏报,所以置信度阈值可以适当调低,比如从 0.25 降到 0.15,同时把 NMS 的 IoU 阈值从 0.45 调到 0.5 或 0.6,减少密集目标被误抑制的情况。这两个参数没有绝对最优,要在测试集上画 P-R 曲线,根据业务能接受的误报率来定。
| 调整方向 | 具体操作 | 预期影响 |
|---|---|---|
| 难例挖掘 | 推理后挑漏检误检图重新标注 | 稀有类别 AP 提升明显 |
| 锚框重聚类 | 对训练集标注跑 k-means | 小目标召回率提升 |
| 输入分辨率 | imgsz 从 640 提到 960 | 小目标漏检减少,显存上升 |
| 推理阈值 | conf 降低、NMS IoU 提高 | 召回率上升,误报可能增加 |
最后一个习惯:每次训练完,把data.yaml、划分文件、转换脚本、训练命令和最终权重一起归档,标注清楚日期和改动点。电力金具检测项目往往要迭代很多轮,没有这份记录,过两周自己都记不清哪次改了什么。我吃过这个亏,后来强制自己每次实验建一个文件夹,里面放一个README写清楚这次和上次的差异,再也没出现过「这个权重到底是哪版数据训的」这种问题。希望帮到你。
本文还有配套的精品资源,点击获取