
简介面向YOLO算法训练与评估的输电线路目标检测数据集特别适用于计算机视觉方向的学生、算法工程师以及电力行业自动化巡检系统开发者。内容聚焦输电线路典型场景覆盖电线、绝缘子、铁塔等关键组件的标注信息能够帮助模型精准识别线路部件的具体位置与类别。资源包采用zip压缩格式共2000个文件全部为XML标注文件内含目标边界框坐标与分类标签压缩包整体约366.78MB。目前已有511人学习/下载既可直接作为训练数据也适合开展数据增强与模型对比实验。XML标注文件可转换至YOLO所需的txt格式省去人工标注与格式转换环节较丰富的样本数量与典型线路要素有助于提升模型在复杂背景、不同光照条件下的检测鲁棒性为输电线巡检、异常状态监测等实际应用提供可靠的数据支撑。1. 先看这份输电线路数据集3334张图能解决巡检里的什么问题做输电线路巡检的同行应该都遇到过这个场景无人机飞了一整天回来拷出几千张照片分成三份交给不同的人盯屏幕看到眼睛发酸最后还是漏掉了一个绝缘子破损的放电痕迹。等检修人员爬上铁塔发现问题一次非计划停电单子下来整个班组都要复盘检讨。yolo算法-输电线路数据集这份3334张带标签的zip包就是冲着这个痛点来的——所有图像都是VOC格式的XML标注边界框、类别名都齐了喂给yolov5或yolov8系列模型可以训练出能自动识别绝缘子、铁塔、导线状态的目标检测模型。适合无人机巡检团队、电力视觉方向的研发工程师以及缺少真实工业数据的学生做课设或原型验证。2. 把XML标注转成YOLO训练格式目录结构与转换脚本2.1 先认清这份数据集的原始目录形态解压zip后第一件事不是急着跑训练而是先弄清楚目录里有哪些东西。这份数据的文件命名是img_0793_3236.xml这种连续编号每一个xml对应一张同名的jpg图像。常见的存放方式有两种一种是图像和xml平铺在同一目录另一种是分为JPEGImages和Annotations两个子目录。无论哪种转换前都要先用脚本全量扫描一遍否则后面训练时老出现“No labels found”报错。find . -name *.xml | wc -l find . -name *.jpg | wc -l这两条命令分别统计xml和jpg数量核对是否都是3334个。这里有个小坑如果xml比jpg多几个说明有标注但图像缺失如果反过来说明有些图像根本没标注。两者都意味着数据集不干净需要先筛掉不一致的文件对而不是直接进训练流程。我在拿到这类工业数据集后一般会再顺手统计一下xml文件大小分布低于1KB的xml大概率是空标注也要单独拎出来看。2.2 VOC格式的XML里写了哪些关键信息打开任意一个xml里面是标准Pascal VOC标注结构。用Python读一下某个文件就能确认类别名边界框字段是否完整import xml.etree.ElementTree as ET tree ET.parse(img_0793_3236.xml) root tree.getroot() filename root.find(filename).text size root.find(size) width int(size.find(width).text) height int(size.find(height).text) for obj in root.findall(object): name obj.find(name).text bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) ymin int(bndbox.find(ymin).text) xmax int(bndbox.find(xmax).text) ymax int(bndbox.find(ymax).text) print(filename, width, height, name, xmin, ymin, xmax, ymax)这段代码做的事情很基础读取图像尺寸和每个目标的类别名、边界框坐标。width和height在转换归一化坐标时是分母绝对不能搞错。如果xml里没有size节点而是直接给绝对坐标转换策略也要跟着调整。还有一条容易被忽略的xml里name字段的拼写必须完全一致比如“insulator”和“Insulator”在YOLO类别映射里是两个不同类别后面训练会直接导致类别数对不上。2.3 转换脚本从VOC坐标到YOLO归一化坐标YOLO系列训练需要的是txt格式标注每行是一个目标格式为“类别id x_center y_center width height”四个数值都是归一化到0-1区间的浮点数。这里的关键是坐标换算逻辑先算出目标中心点和宽高再分别除以图像宽度和高度。import os import xml.etree.ElementTree as ET # 实际使用时把下面几个路径改成你解压后的目录 xml_dir ./Annotations img_dir ./JPEGImages labels_dir ./labels os.makedirs(labels_dir, exist_okTrue) class_names [] def voc_to_yolo(xml_path, output_path, img_width, img_height): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: class_names.append(name) class_id class_names.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) # 归一化到0-1注意中心点和宽高的计算顺序 x_center (xmin xmax) / 2.0 / img_width y_center (ymin ymax) / 2.0 / img_height w (xmax - xmin) / img_width h (ymax - ymin) / img_height # 过滤掉宽高为0或负数的异常框 if w 0 or h 0: continue if x_center 0 or y_center 0 or x_center 1 or y_center 1: continue lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(output_path, w) as f: f.write(\n.join(lines)) # 遍历所有xmlimg_width和img_height从xml的size节点读取 for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue xml_path os.path.join(xml_dir, xml_file) tree ET.parse(xml_path) root tree.getroot() width int(root.find(size/width).text) height int(root.find(size/height).text) output_path os.path.join(labels_dir, xml_file.replace(.xml, .txt)) voc_to_yolo(xml_path, output_path, width, height) with open(./classes.txt, w) as f: f.write(\n.join(class_names))这段脚本有几个参数值得细说。img_width和img_height是归一化的分母建议从xml的size节点里动态读取而不是用固定值因为这份数据集里图像尺寸可能不一致。class_id用的是列表中首次出现的顺序也就是说类别顺序完全依赖遍历xml文件的先后顺序这有个隐患如果第二次跑脚本时文件顺序变了类别id对不上。稳妥做法是先扫一遍所有xml把name集合排序后再分配id这样classes.txt的顺序是稳定的。提示转换前一定要备份原始Annotations目录。脚本跑完如果发现坐标方向错了或者类别对不上原始XML还在就能快速补救。转换标注这种事后悔药必须留一手。2.4 转换后必做的三项校验第一条是文件数量校验labels目录下的txt数量必须等于xml数量。第二条是类别数量校验打开classes.txt检查如果这份数据集的XML里混进了非电力组件的类别名比如背景里的鸟或建筑物需要决定是保留还是过滤。第三条是坐标合法性校验写个简单脚本统计txt里是否有负数或大于1的数值YOLO训练遇到非法坐标会直接报错甚至导致loss变成NaN。四个边界坑要单独拿出来说。第一图像宽高从xml读但有些标注工具不会写size节点这时要用PIL或cv2读取实际图像尺寸。第二box坐标超出图像边界常见于人工标注时手抖拉过头需要在归一化前先clamp到图像范围内。第三xml里存在重复目标名会把同一目标写两遍需要按坐标去重。第四jpg和xml同名但不同后缀比如大小写.JPG与.jpg混用在Windows下没事部署到Linux服务器上就会找不到图。这四类坑在转换后校验阶段全都能被自动脚本抓到别省这一步。3. 训练配置与模型选型从yolov5s到yolov8n的适配细节3.1 data.yaml到底怎么正确写法网上检索“yolov8训练自己的数据集”至少一半人卡在data.yaml配置上。YOLO系列的数据配置文件不长但每个字段都直接决定训练是否正常启动。这份输电线路数据集需要自建一个yaml文件指定路径、类别数量和类别名。# transmission_line.yaml path: E:/yolo_dataset/transmission_lines # 数据集根目录改成你的实际路径 train: images/train # 相对path的训练集目录 val: images/val # 相对path的验证集目录 nc: 5 # 类别数量按实际XML扫描结果改 names: [insulator, tower, wire, damper, grading_ring]path字段用绝对路径最省心YOLO虽然支持相对路径但解压目录一旦移动就会全部失效。train和val指向的是images子目录标注文件不需要单独写路径YOLO会自动在同级labels目录里找同名txt。这里面最容易翻车的点是nc和names个数不一致比如names写了5个但实际标签只有4类训练时会在读取数据阶段直接抛错。我的习惯是先用上一节的classes.txt核对names确认数量完全对齐再启动训练。3.2 训练启动命令与关键参数解读确认数据划分没问题后直接跑训练命令。数据量只有3334张这个规模在yolov8下用默认参数就能出效果但有几个参数必须人工干预。yolo detect train datatransmission_line.yaml modelyolov8n.pt epochs200 batch16 imgsz640 device0 workers4 patience30逐个说参数含义。epochs设为200对这个数据量足够收敛再多就会过拟合训练日志里val_loss会先降后升。batch16在8GB显存的显卡上配合yolov8n可以跑如果显存紧张就降到8。imgsz是训练分辨率输电线路的小目标多分辨率可以从640拉到960代价是显存占用上升和训练速度变慢需要在速度和精度之间做权衡。workers是数据加载线程数Windows下建议设成4设太高容易报DataLoader worker相关的内存错误。patience30是早停参数连续30轮验证集指标不提升就自动停。3.3 yolov5s还是yolov8n模型选型的三维比对这份3334张的数据集模型选择我按三个维度来比精度上限、推理速度、显存占用。yolov8n是轻量版模型文件约6MB左右推理速度快适合部署到无人机机载边缘设备代价是小目标召回率略低。yolov5s是经典方案社区生态最成熟网络上有大量针对电力场景的调参案例遇到问题容易搜到解决方案。yolov8m则精度更高但显存占用和训练时间都上去了。搭建一个简单对比表作为参考模型精度基准推理速度显存占用适用场景yolov8n中最快最低边缘设备、实时监控yolov5s中高快低通用训练、快速验证yolov8s高中中离线分析、精度优先我的建议是先用yolov8n跑通全流程确认数据本身没问题再换yolov8s刷最终精度。不要在第一次训练时就上大模型一旦数据有问题三四天的训练时间全浪费了。而且网上那些yolo算法讲解ppt把结构拆得很细真正落地时最耗时间的反而是数据和参数不是网络结构。3.4 训练完成后看哪几个指标确认模型质量训练结束后不要只看best.pt就完事。打开runs/detect/train目录下的results.png重点看三组曲线。第一组是val/box_loss和val/cls_loss这两个值应该整体下降且在训练后期趋于平稳如果出现大的尖峰说明学习率或数据有问题。第二组是metrics/mAP50和metrics/mAP50-95mAP50反映的是普通目标的检测精度mAP50-95更严格对小目标和定位精度的惩罚更大。第三组是confusion_matrix.png里面能看出哪些类别之间互相误检——比如绝缘子和均压环这种外观相似的部件经常被搞混。验证集里单独挑几张跑一次预测最直观。别只看指标数字要真看检测框画在图像上的效果。输电线路场景里框的位置有没有把部件完整包住、有没有把背景山体误框成导线这些从指标上看不出来但一张可视化图就能说明问题。4. 避坑清单输电线路检测常见的五个翻车点4.1 小目标漏检严重mAP50虚高但实际难用现象训练完mAP50有0.85看起来很漂亮但把模型拿到无人机实拍视频里跑绝缘子破损那种几十像素大小的小目标几乎全部漏检。原因绝缘子在远景图像里往往只有几十个像素imgsz640把原图缩得很小小目标的特征在多次下采样后基本丢光了。mAP50的IoU阈值是0.5稍微蒙中一点就算命中造成指标虚高。解决训练分辨率拉到1280让模型在更高分辨率下学小目标细节。推理时用SAHI这类切片推理工具把大图切成小块分别检测再合并。实测中这两种方案对小目标召回率的提升最明显比换大模型有效得多。鸟类目标检测的数据集和遥感小目标数据集也有同样的问题处理思路是通用的。4.2 光照变化导致误检率飙升现象训练集里大部分是晴天正午拍的图模型在阴天或逆光条件下把远处的山脊误检成导线把暗色背景识别成绝缘子。原因数据集的光照分布太单一模型学到的是“在特定亮度下的纹理特征”而不是真正的形状特征。输电线路本身在现代天空背景下对比度就不高一旦光影条件变化特征分布直接偏移。解决训练时打开hsv_h、hsv_s、hsv_v这些数据增强参数yolov8对颜色扰动有内置实现默认值其实已经开了但还可以加强亮度扰动。数据侧更有效找几个阴天、黄昏的巡检视频抽帧补几百张图做第二轮微调训练。从那以后我每次做工业视觉项目都会先问一句能不能搞到失败场景的图。4.3 训练时报错class数对不上或loss为NaN现象数据准备阶段跑得好好的训练开始后报“AssertionError: class number mismatch”或者训练到中途loss突然变成nan程序直接中断。原因XML里存在之前没扫描到的额外类别名。比如标注员在某个XML里把鸟写成了bird但你的yaml里只配置了5个类别YOLO读取时发现超出索引范围轻则报错重则把错误类别的梯度传导到整个loss上产生NaN。解决在转换脚本最后加一行全量扫描代码把所有xml里出现过的name集合打出来和你yaml里的names逐一对上。这一步应该在训练启动前完成而不是等loss炸了再去排查。我在接二手数据集时哪怕是别人说“标好了”的也一定会跑一遍统一校验脚本。4.4 标注框超出图像边界导致训练指标异常现象训练过程不报错但val/box_loss始终降不下去验证集可视化里出现大量宽高异常的预测框。原因部分标注框的xmax、ymax超过了图像的宽度和高度归一化后宽度或高度大于1模型学到了一堆不合理的回归目标定位头始终无法收敛。解决转换脚本里对xmin、xmax、ymin、ymax做clamp操作把所有坐标限制在图像尺寸范围内。如果是负坐标直接过滤掉这个框。还要检查是不是标注工具导出的坐标本来就有偏移比如xmin和xmax写反了这种错误在VOC转YOLO的过程中不会报错但训练结果会非常抽象。4.5 模型在新航线数据上性能骤降现象训练集和验证集都是同一条线路拍的mAP50能到0.8以上换了一条新线路的巡检视频去测漏检率直接翻倍。原因不同线路的铁塔结构、绝缘子串型、拍摄高度和相机焦距都不同无人机新航线和训练数据存在域偏移。本质是训练集的场景多样性不够丰富。解决把训练策略改成跨线路混合抽样新线路数据占一部分老线路数据保留一部分让模型学到的是“构件本身的样子”而不是“这条线路的特有纹理”。另一个做法是推理时打开TTA对同一张图做多尺度变换后再合并结果可以明显拉高在新场景下的召回率但推理延迟会增加不少。5. 推理与部署把检测结果接进巡检业务流程5.1 用best.pt做单张图像推理训练完的best.pt可以直接加载做推理yolov8的预测API很简洁但参数调整有讲究不能无脑默认。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict(inspection_img.jpg, conf0.35, iou0.5, imgsz1280, device0, saveTrue) for r in results: boxes r.boxes for box in boxes: cls_id int(box.cls[0].item()) conf box.conf[0].item() xyxy box.xyxy[0].tolist() print(f类别: {model.names[cls_id]}, 置信度: {conf:.2f}, 坐标: {[round(v, 1) for v in xyxy]})这里conf0.35比默认的0.25要高输电线路巡检场景漏检比误检更严重宁愿多框几个背景让人工筛也不能漏掉损坏的绝缘子。imgsz1280和训练时保持一致推理分辨率低于训练分辨率会直接掉点。device0指定用GPU没有GPU就改成cpu但速度会慢很多。saveTrue让yolov8自动保存可视化结果图方便快速抽查。5.2 批量巡检图出检测报告实际巡检任务一次可能几百上千张图单张看显示输出太慢需要有批量导出结构化结果的能力。import csv from ultralytics import YOLO model YOLO(best.pt) image_paths [frame_001.jpg, frame_002.jpg, frame_003.jpg] report_rows [] for img_path in image_paths: results model.predict(img_path, conf0.35, iou0.5, imgsz1280, verboseFalse) for r in results: for box in r.boxes: cls_id int(box.cls[0].item()) conf round(box.conf[0].item(), 3) xyxy [round(v, 1) for v in box.xyxy[0].tolist()] report_rows.append([img_path, model.names[cls_id], conf] xyxy) with open(detection_report.csv, w, newline) as f: writer csv.writer(f) writer.writerow([image, class, confidence, xmin, ymin, xmax, ymax]) writer.writerows(report_rows)这段脚本循环遍历巡检图像把每个检测框拉平成一行写入CSV字段包含图像名、类别、置信度和边界框坐标。这个CSV可以直接导入到巡检管理平台里做缺陷归档。巡检场景建议再额外输出一列判断结果比如类别是insulator且置信度低于某个阈值时标记为“需人工复核”这样技术人员只需要看有问题的行而不用翻完整张表。5.3 部署到边缘设备时的参数调整策略无人机机载或杆塔摄像头这类边缘设备算力有限直接把best.pt传上去跑python推理太慢一般会导出成TensorRT的engine格式再部署。关键命令是导出时的精度控制。yolo export modelbest.pt formatengine device0 imgsz640 halfTrue dynamicTrue这个导出命令把模型转为TensorRT引擎。halfTrue表示FP16半精度推理推理速度能提升接近一倍显存占用下降一半精度损失极小工业场景可接受。dynamicTrue开启动态输入尺寸避免部署后因为图像尺寸不一致反复重新绑定的问题。imgsz640是导出尺寸如果训练用的1280这里必须改成1280否则和训练分辨率不一致精度掉得厉害。要是设备更紧张还可以进一步做INT8量化但那需要在真实数据上校准流程更复杂我先不展开。注意用TensorRT导出前要先确认设备上的CUDA版本和TensorRT版本匹配版本不一致会报plugin not found之类的错误。这一步属于环境踩坑Python脚本本身反而不会出大问题。6. 进阶技巧用预标注把数据集的利用效率翻一倍拿到3334张带标签数据后如果自己还有一批没标注的巡检图可以用这个数据集训出来的模型做预标注大幅减少人工标注时间。做法是先跑一遍推理把置信度高的检测框直接转成VOC格式的XML初稿然后用labelImg打开人工修正。from ultralytics import YOLO import xml.etree.ElementTree as ET model YOLO(best.pt) results model.predict(new_unlabeled_004.jpg, conf0.6, imgsz1280) root ET.Element(annotation) size_el ET.SubElement(root, size) size_el.append(ET.Element(width)) size_el.append(ET.Element(height)) for r in results: for box in r.boxes: cls_id int(box.cls[0].item()) conf box.conf[0].item() if conf 0.6: continue obj ET.SubElement(root, object) name ET.SubElement(obj, name) name.text model.names[cls_id] bndbox ET.SubElement(obj, bndbox) xmin, ymin, xmax, ymax box.xyxy[0].tolist() ET.SubElement(bndbox, xmin).text str(int(xmin)) ET.SubElement(bndbox, ymin).text str(int(ymin)) ET.SubElement(bndbox, xmax).text str(int(xmax)) ET.SubElement(bndbox, ymax).text str(int(ymax))这段脚本的核心逻辑是conf0.6预标注时置信度阈值要设得比正常推理高宁可丢掉一些难目标让模型漏标也不能把错误框写进去因为人工修正漏标比删错框简单得多。阈值设低了人工要在labelImg里删大量误检框反而更耗时。预标注脚本产出的XML初稿结构上只写了目标框和类别名尺寸信息没有填全需要导入labelImg后手动确认图像尺寸。我实际操作时的流程是先用脚本批量生成xml再在labelImg里打开原图检查一遍修正漏检和错检最后整体导出一遍新XML替换旧文件。这套流程跑下来从零标注一张图平均要五分钟预标注后修正一张图基本一分钟内能搞定。预标注里最容易踩的坑在于置信度阈值和类别选择。置信度阈值太低会把背景误框阈值太高会漏掉难样本0.6到0.7是经验值区间可以先抽几张图试跑看看效果再定。如果是绝缘子串这类细长旋转目标水平框预标注的精度会比较勉强那种场景更适合mmrotate那类旋转框检测方案但这份数据集本身是水平框格式我只能说在这个数据格式下预标注方式是最省力的扩数方法。从那以后我每次接新的巡检数据集都会先训一个快速版本再用快速版本跑预标注去扩第二批新图这套“快速模型加人工修正”的循环比直接标注省一半时间以上。希望帮到你。本文还有配套的精品资源点击获取