
简介面向电力巡检智能化与遥感目标检测学习者这份数据集聚焦电杆塔检测场景同时提供Pascal VOC与YOLO两种标注格式便于直接接入YOLO、SSD、Faster R-CNN等主流检测框架。包内含400张jpg遥感图像并配套400个xml与400个txt标注文件标注类别为单一的sdgt共680个矩形框由labelImg工具按画框规则完成标注定位准确、数量均衡。压缩包共1202个文件txt文件为402个除每张图对应的YOLO格式标签外还包含类别说明等辅助内容整体约136.93MB解压后按图像、xml、txt分类存放能快速完成训练集与验证集划分。目前已有605人学习浏览适合初学者理解VOC与YOLO格式差异也适合有基础的开发者直接用于模型训练、迁移学习或算法验证是电力场景目标检测任务的实用数据基础。1. 电力场景遥感杆塔检测数据集400张图能把模型训到什么程度做遥感目标检测的人都会遇到同一个尴尬公开数据集里汽车、船只、飞机一大堆唯独电力杆塔这种小目标、稀疏分布、背景杂乱的对象很难找。你拿着通用模型去推自己的巡检影像要么漏检要么误检归根到底是训练数据里没有这类样本。这份数据集就是冲着这个缺口来的——400张真实电力场景遥感图统一标注成Pascal VOC和YOLO两种格式类别只有sdgt输电杆塔一个总共680个框。对刚入门YOLO或者需要快速验证检测流程的人来说它最大的价值不是大而是干净标注格式齐全、类别单一、目录结构简单拿来就能直接喂给训练脚本。适合四类人正在做遥感目标检测课程设计的学生、需要电力杆塔先验数据做预训练的算法工程师、想搞懂VOC与YOLO格式差异的初学者以及想用少量数据跑通YOLO全流程的开发者。别指望400张图能训出生产级模型但用它跑通流程、验证思路、学会踩坑完全够了。2. 拆开数据集VOC与YOLO两套标注如何对齐先说结论这份数据集里每张jpg图片对应一个xml和一个txt三份文件同名同前缀只是后缀不同。xml是Pascal VOC标准格式txt是YOLO训练需要的归一化坐标格式。很多人第一次拿到双格式数据集会困惑“为什么同一张图要标两遍”其实不是标两遍而是标注工具一次性导出再通过脚本转换出来的。2.1 目录结构与命名规则解压后你会看到典型的检测数据集布局JPEGImages放图片Annotations放xmllabels或yolo_labels放txt。具体到这份数据文件名形如firc_dianli_146.jpg对应firc_dianli_146.xml和firc_dianli_146.txt。图片数量400xml数量400txt数量400一一对应。没有任何分割路径文件也就是说没有train.txt、val.txt这种索引列表需要自己划分。# 解压后建议先做一次完整性校验 cd 数据集目录 echo 图片数量: $(ls *.jpg | wc -l) echo xml数量: $(ls *.xml | wc -l) echo txt数量: $(ls *.txt | wc -l)我一般会先跑这三行确认数字都是400再继续。文件数对不上就是传输丢包或者解压不完整后面训练时会出现“No labels found”的玄学报错先排除这个最省时间。另外注意文件名里的dianli是拼音“电力”不是缩写别因为看着奇怪就擅自改名路径里只要统一就好。2.2 VOC格式的xml里有什么关键信息用任意文本编辑器打开一个xml结构基本是固定的annotation根节点下面有folder、filename、size和object。size里的width、height、depth决定图片尺寸object里是类别名和bndbox四组坐标。这幅数据的宽高可能是几百到上千像素不等遥感图通常不是正方形训练时要留意。annotation folderJPEGImages/folder filenamefirc_dianli_146.jpg/filename size width960/width height540/height depth3/depth /size object namesdgt/name bndbox xmin112/xmin ymin88/ymin xmax156/xmax ymax210/ymax /bndbox /object /annotation注意这里的坐标是像素绝对值xmin/xmax、ymin/ymax分别对应矩形框左、右、上、下边界。对遥感图像来说杆塔通常是小目标框会集中在几十到一两百像素的范围内背景占大头。这个xml文件在训练时不会被YOLO直接读取但它作为原始标注存档很有价值因为像素坐标不会因为归一化产生精度损失。2.3 YOLO格式的txt归一化坐标的换算关系YOLO训练读取的txt是归一化后的结果。每行代表一个目标格式为class_id x_center y_center width height四个数值都是相对于图片宽高的比例范围0到1。以刚才那个xml为例换算逻辑是x_center(112156)/2/960y_center(88210)/2/540width(156-112)/960height(210-88)/540。# firc_dianli_146.txt 内容示例 0 0.139583 0.275926 0.045833 0.225926因为这个数据集只有sdgt一个类别class_id固定为0。如果你后续要合并其他类别记得把txt里的类号改成对应索引否则训练时会按类别名重新映射轻则训练集类别数对不上重则框全部变成背景。我见过有人直接把多个数据集的txt拼在一起没检查类别索引结果模型把所有目标都识别成了第一类排查了半天才发现是txt里的编号和配置文件里的类别顺序不一致。2.4 用脚本校验标注是否成对拿到双格式数据最值得做的一件事就是自动校验xml和txt的框数、坐标是否一致。标注工具导出时偶尔会漏标或重复用脚本扫一遍比肉眼靠谱得多。import xml.etree.ElementTree as ET from pathlib import Path def check_pair(xml_path, txt_path): tree ET.parse(xml_path) objs tree.findall(object) xml_boxes [] for obj in objs: b obj.find(bndbox) xml_boxes.append((float(b.find(xmin).text), float(b.find(ymin).text), float(b.find(xmax).text), float(b.find(ymax).text))) txt_boxes [] with open(txt_path) as f: for line in f: parts line.strip().split() if len(parts) 5: x, y, w, h map(float, parts[1:]) # 反算回像素坐标 txt_boxes.append((x, y, w, h)) return len(xml_boxes), len(txt_boxes), xml_boxes, txt_boxes上面这个函数只统计框数实际使用时还要根据图片宽高把txt里的归一化坐标反算成像素坐标再计算IoU。IoU大于0.9基本可以认为一致。这个脚本不负责修正只负责报警——发现不一致优先信xml因为xml是从labelImg直接导出的txt是后续转换的。这份数据集标注质量整体不错但养成校验习惯后以后用别人的数据集就不会瞎。3. 把数据集跑进YOLO训练目录组织与配置文件实操格式对上了下一步就是把数据组织成YOLO项目能直接吃的结构。这里以YOLOv5和YOLOv8为例因为这两者是目前用得最多的网上所谓的“yolo入门”教程八成也是基于这两套。数据集本身不挑框架关键是目录和配置文件要写对。3.1 标准目录如何摆放YOLOv5和YOLOv8的目录要求略有不同但核心是images和labels两个文件夹平行放置。我们可以把数据集统一整理成如下结构datasets/ └── dianli/ ├── images/ │ ├── train/ │ │ ├── firc_dianli_146.jpg │ │ └── ... │ └── val/ │ ├── firc_dianli_375.jpg │ └── ... └── labels/ ├── train/ │ ├── firc_dianli_146.txt │ └── ... └── val/ ├── firc_dianli_375.txt └── ...注意这里的labels目录放的是YOLO格式的txt不是xml。xml可以作为原始标注保存在另一个地方训练时YOLO不读xml。创建目录和拷贝文件可以用一个简短脚本完成mkdir -p datasets/dianli/images/train datasets/dianli/images/val mkdir -p datasets/dianli/labels/train datasets/dianli/labels/val # 假设原数据集解压在 source/ 下 cp source/*.jpg datasets/dianli/images/train/ cp source/*.txt datasets/dianli/labels/train/上面把所有数据都放到了train然后从train里随机抽一部分给val。常见做法是80/20划分也就是320张训练、80张验证。对于400张的数据集验证集太少会导致评估曲线抖动我一般会取85/15甚至90/10优先保证训练数量。不过这份数据集只有680个框平均每张1.7个目标很多图可能没有目标所以划分时最好按“包含目标的图片”来分层避免验证集全是空图。3.2 data.yaml配置文件怎么写YOLO训练不认数据集里的xml全靠一个yaml文件告诉它图片路径、标签路径和类别名。最典型的写法如下# dianli.yaml path: D:/datasets/dianli # 数据集根目录改成你自己的绝对路径 train: images/train val: images/val nc: 1 names: [sdgt]有几个地方容易翻车。path一定要写绝对路径或者保证执行训练命令时当前目录在path的上一级写相对路径时YOLO会先尝试拼接找不到再报错报错信息里不会提示它试了哪些组合全靠自己猜。names的顺序必须和txt里的class_id一致这里是sdgt对应0如果以后增加类别按顺序追加。nc是类别数写错会导致最后一层输出维度对不上训练能跑但loss不降或者推理时类别错乱。3.3 一行命令启动训练YOLOv5和YOLOv8的训练命令很相似只是入口不同。我用YOLOv8的命令举例因为它的CLI更简洁# YOLOv8 yolo train modelyolov8n.pt datadianli.yaml epochs100 imgsz640 batch16# YOLOv5 (在项目根目录执行) python train.py --data dianli.yaml --weights yolov5s.pt --epochs 100 --img 640 --batch 16参数说明yolov8n.pt是nano版本模型小、速度快适合400张这种小数据量如果你追求精度换yolov8s.pt或yolov5s.pt也行但训练时间会拉长。imgsz640是输入尺寸遥感图如果原图超过640模型会缩放到640小目标容易丢失。我一般会先用640跑通流程再用896或1280做对比实验看看mAP对输入尺寸的敏感度。batch16取决于显存6G显存以下建议8或4否则显存溢出。训练时留意loss曲线YOLOv8的box_loss、cls_loss、dfl_loss应该同步下降如果cls_loss震荡不停先检查类别名是否和目标匹配。3.4 训练输出怎么判断好坏训练结束后结果保存在runs/detect/train或runs/train下重点看三个文件results.csv、val_batch0_pred.jpg和confusion_matrix.png。results.csv里有每个epoch的mAP50和mAP50-95。对于这个类别单一且框数有限的数据集mAP50到0.8以上不算难事关键是看mAP50-95和PR曲线。如果mAP50很高但mAP50-95很低通常意味着框定位不够准也就是和真值重叠度低。此时优先考虑调高imgsz而不是盲目加epoch。# 查看训练指标用Python读取CSV python -c import pandas as pd; dfpd.read_csv(runs/detect/train/results.csv); print(df[[epoch,metrics/mAP50(B),metrics/mAP50-95(B)]].tail())如果训练到第60个epoch后两条曲线还在上升说明模型没收敛可以加到150甚至200个epoch。但如果曲线在第20个epoch就平了加epoch没意义不如调数据增强或换模型。对于400张图我的经验是100个epoch足够看到一个可靠趋势剩下的时间用来做错误分析。4. 常见问题与避坑标注框、路径、格式转换的五个坑数据量小问题反而更隐蔽因为每一个误差都会被放大。下面五条是我在类似遥感小数据集上反复踩过的按频率排序。4.1 labelImg打开图片后xml和txt对不上现象用labelImg重新打开某张图发现框的位置和原始txt坐标不一致甚至框数都不同。原因labelImg默认保存的是VOC xml但如果你在标注过程中切换过YOLO模式它会同时写txt如果你手动改过xml而没有同步单个txt就会出现两边数据不一致。解决以xml为准重新生成txt不要手工改txt。可以写一个小脚本读xml里所有object按归一化公式重新输出txt每次标注完跑一遍。4.2 训练时报“AssertionError: train: No labels in ...”现象启动训练后立刻报错说某个文件夹下找不到标签。原因txt文件不是UTF-8编码或者标签里的类别索引超出nc范围又或者txt文件名和jpg文件名不完全一致比如多了空格。解决先确认labels目录下txt数量等于图片数量再确认txt内容第一列是不是0最后用file命令检查编码。这个数据集里的txt基本都是纯ASCII但如果你合并过其他来源的数据就要小心。# 检查txt内容是否合法 awk { if ($10 || $10) print FILENAME: $0 } labels/train/*.txt这段awk的作用是打印所有类别索引不是0的行因为本数据集只有一类任何非0的索引都是错误。如果输出为空说明类别编号没问题。接下来还要看坐标值是否都在0到1之间越界会导致训练时loss变成NaN。4.3 验证集mAP显示为0训练集正常现象跑完100个epoch训练集mAP很高但验证集mAP是0。原因大概率是数据划分时验证集里全是没有目标的背景图或者验证集图片路径错误YOLO读取的是空标签。对于这种400张图的数据集随机划分很容易把少数包含框的图全分到训练集。解决用分层抽样按“图中是否有目标”进行划分。先解析所有xml统计框数把含框的图和空图分开分别按比例取到train和val。import random from pathlib import Path xml_files list(Path(Annotations).glob(*.xml)) with_box, without_box [], [] for xf in xml_files: tree ET.parse(xf) if len(tree.findall(object)) 0: with_box.append(xf.stem) else: without_box.append(xf.stem) random.shuffle(with_box) val_with with_box[:int(len(with_box)*0.2)] train_with with_box[len(val_with):] # 空图可全放训练集或按比例放用这个逻辑生成的train.txt和val.txt再用YOLO的--data参数加载时需要把txt里的文件名列出来。或者直接在目录组织阶段就把文件移动好。这个坑在遥感数据集里特别常见因为大多数遥感影像只有10%的图有目标。4.4 小目标漏检严重调高imgsz后反而显存溢出现象训练后推理杆塔在远距离图片里完全没检测出来提高输入尺寸到1280后训练直接OOM。原因杆塔在遥感图里可能只有几十个像素640输入下缩到十几像素特征图里几乎不剩信息。而1280对单卡8G显存来说确实带不动batch16。解决先试imgsz960batch降到4如果还溢出用YOLOv5的--multi-scale配合--rect或者直接换nano模型。另外可以在推理时用TTA测试时增强对mAP有提升但速度会掉下来。4.5 7z解压后文件后缀丢失现象Windows下用右键解压得到的文件扩展名全部消失jpg变成无后缀文件。原因某些7z压缩包内文件属性在Windows解压时被错误处理常见于中文路径或特殊字符。解决用7-Zip官方工具解压不要用Windows自带的“压缩文件夹”功能。Linux下用7z x命令确保安装p7zip-full。sudo apt install p7zip-full 7z x 电力场景遥感数电杆塔检测数据集VOCYOLO格式400张1类别.7z解压后马上用file命令检查文件类型file xxx.jpg如果输出“JPEG image data”说明没问题如果输出“data”说明解压异常。这时重新下载或者换个解压工具别在坏文件上继续改后缀改完也可能损坏。5. 进阶数据增强与模型验证让400张图发挥更大价值400张图、680个框说实话不够建模但足够做算法分析和流程验证。想让模型效果往上走与其堆epoch不如从数据增强和验证策略两个方向下手。5.1 针对遥感小目标的增强策略YOLO自带的增强如mosaic、mixup对自然图像效果好但遥感图像有自己的特殊性杆塔通常垂直于地面但角度多变背景是大面积地物纹理复杂。我一般会在基础增强上加两项随机旋转90度倍数和随机裁剪。遥感图不像自然图有明确的“上下”旋转90度不改变语义而且能让模型对杆塔的方向不敏感。# YOLOv8增强参数示例写到yaml里或命令行传参 augment: true mosaic: 1.0 mixup: 0.0 degrees: 90.0 # 随机旋转0~90度遥感图可以放宽 scale: 0.5 hsv_h: 0.015注意degrees不要设成180连续旋转180度对杆塔这类目标没意义而且可能让标注框的方向变得奇怪。mixup建议设0因为小数据集上mixup容易把两个不同场景的杆塔混在一起反而干扰特征学习。mosaic保留它等于把四张图拼成一张相当于变相增加了样本多样性。5.2 用k-fold交叉验证评估真实精度单次80/20划分的mAP波动很大尤其数据这么少。更可靠的评估是5折交叉验证每次用320张训练、80张验证训练5次然后看平均mAP和标准差。这个做法在数据集不平衡时特别有用。# 生成5折划分的脚本片段 from sklearn.model_selection import KFold import pandas as pd files pd.DataFrame({stem: [f.stem for f in Path(images).glob(*.jpg)]}) kf KFold(n_splits5, shuffleTrue, random_state42) for fold, (train_idx, val_idx) in enumerate(kf.split(files), 1): train_files files.iloc[train_idx][stem] val_files files.iloc[val_idx][stem] print(fold, len(train_files), len(val_files))实际使用时要为每个fold生成独立的data.yaml并指定对应的train.txt和val.txt。跑5次训练虽然耗时但能大幅抑制随机性带来的误判。你会发现有些fold的mAP特别低往往是因为那个验证集里包含了几张杆塔特别小或者重叠严重的图这些图才是真正的难点样本。5.3 用置信度阈值和NMS参数微调推理训练完做推理时默认置信度阈值是0.25NMS阈值是0.45。遥感小目标场景下误检和漏检的平衡点跟自然图像不一样。杆塔在低分辨率下特征弱置信度普遍偏低你把阈值降到0.1会找回不少漏检但同时会带回背景误检。更合理的做法是先跑一遍验证集的PR曲线找到召回率较高而精度下降不明显的阈值点。# YOLOv8推理时调整阈值 yolo detect predict modelbest.pt sourcetest_images conf0.1 iou0.5参数说明conf0.1表示只保留置信度高于0.1的框iou0.5表示两个框IoU大于0.5时只保留一个。对于杆塔这种尺寸小、数量稀疏的目标conf0.15、iou0.4通常比默认参数好你可以画几组结果的对比图来确认。注意不要为了刷指标把阈值调到极端毕竟真实巡检场景对误检率有要求。6. 最后的技巧用可视化脚本快速核验标注质量数据集好不好光看mAP不够标注的错漏有时候会被模型“聪明地”忽略掉但一旦你换模型或调增强策略问题就会爆发。我的习惯是训练前先做一次可视化核验把所有标注框画到原图上生成一张拼图快速扫一遍。import cv2 import xml.etree.ElementTree as ET from pathlib import Path def draw_boxes(image_path, xml_path, output_path): img cv2.imread(str(image_path)) tree ET.parse(xml_path) for obj in tree.findall(object): b obj.find(bndbox) xmin int(b.find(xmin).text) ymin int(b.find(ymin).text) xmax int(b.find(xmax).text) ymax int(b.find(ymax).text) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0, 0, 255), 2) cv2.imwrite(str(output_path), img) # 批量处理前50张 for xml_file in sorted(Path(Annotations).glob(*.xml))[:50]: jpg Path(JPEGImages) / (xml_file.stem .jpg) draw_boxes(jpg, xml_file, Path(check_vis) / (xml_file.stem .jpg))这段代码会生成带红色框的图片保存到check_vis目录。之后你只需要挨个翻看重点检查三点框是否贴住杆塔主体而不是只框了塔尖、有没有漏掉图中明显的杆塔、有没有框把两个杆塔并成一个框。这套流程我每次换数据集都强制走一遍最多花十分钟却能省下后面训练完才发现数据问题的后悔药。这份数据集是遥感电力场景背景复杂有些图的杆塔可能淹没在线路走廊里如果发现某些图框明显偏移不要犹豫自己用labelImg修正后再训练。对于400张的规模手动修几十张完全值得。数据质量决定模型上限YOLO只是把标注里的规律学到极致而已。希望帮到你。本文还有配套的精品资源点击获取