尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

遥感电力塔目标检测:YOLO数据集格式转换与训练避坑指南

发布时间:2026/9/26 5:40:41

资讯中心
01
ARTICLE

遥感电力塔目标检测:YOLO数据集格式转换与训练避坑指南

遥感电力塔目标检测:YOLO数据集格式转换与训练避坑指南
简介一份面向YOLO系列目标检测学习与实战的遥感电力塔数据集包含10000张真实场景图像标注框质量高覆盖多种环境。压缩包内按VOC、COCO、YOLO三种格式分别存放标签可直接接入主流目标检测框架训练。资源共2000个文件以xml标签文件为主对应VOC格式另含txt格式标签、html格式环境搭建与训练教程、py格式数据集划分脚本整体约764.62MB。随附YOLO环境搭建Windows/Linux、训练案例教程以及训练/验证/测试集划分脚本可按需拆分数据并迁移到自有数据集。目前已有655人学习下载适合需要高质量遥感目标检测数据集并希望快速上手YOLO训练流程的开发者。1. 遥感电力塔目标检测拿到这份rar先别急着解压训练做遥感目标检测的人十有八九都会卡在同一个环节数据。YOLO遥感电力塔目标检测数据集带10000张图片三种标注格式齐全还有划分脚本和训练教程这类资源是所有做电力巡检、电网资产识别、遥感智能解译的人都想找的。但我要先说句泼冷水的话数据集到手只是开始真正耗时间的不是训练而是把格式理顺、把划分做对、把小目标调出来。这一套流程对电力塔这种长条状、高纵横比、背景复杂的小目标来说踩坑概率比普通目标检测高得多。这篇笔记面向的是那些准备用YOLO训练自己的遥感数据集、但不想在格式转换和数据划分上翻车的工程师。我会按照从解压到训练的路径把三种标注格式怎么互转、划分脚本怎么写才科学、训练参数怎么调、以及最容易让你白跑一晚上的坑全部捋一遍。适合想一步到位跑通训练教程的从业者也适合那些已经在训练但mAP死活上不去的熟手对照排查。2. 三种标注格式的底账VOC、COCO、YOLO的差异与互转脚本2.1 先盘底账再动手图片与标注文件的对齐方式解压拿到手之后我第一步永远是盘目录结构而不是直接开训练。YOLO遥感电力塔目标检测数据集的常规组织方式是 JPEGImages或 images存放原图labels 分别按 voc、coco、yolo 三级后缀拆分。VOC 格式是每个图片对应一个同名的 XML 文件坐标是 xmin、ymin、xmax、ymax 的绝对像素值COCO 格式是把所有标注汇总到一个 JSON 文件里用 image_id annotation_id 关联YOLO 格式是每个图片对应一个同名 txt 文件每行五列class_id、center_x、center_y、width、height全部归一化到 0~1。这三种格式不是简单换个后缀就能通用的很多人翻车就翻在把坐标搞错。我拿到数据后会先写一个检查脚本确认三件事图片文件数与标注文件数一致、文件名一一对应、坐标范围没有越界。别小看这一步10000张图的数据集里偶尔几张损坏或漏标的情况太常见了。import os from pathlib import Path def audit_dataset(img_dir, ann_dir, ext.txt): img_dir, ann_dir Path(img_dir), Path(ann_dir) imgs {p.stem for p in img_dir.iterdir() if p.suffix.lower() in (.jpg, .jpeg, .png)} anns {p.stem for p in ann_dir.iterdir() if p.suffix.lower() ext} missing_ann imgs - anns missing_img anns - imgs print(f图片总数: {len(imgs)}, 标注总数: {len(anns)}) if missing_ann: print(f缺标注的图片: {len(missing_ann)}, 示例: {list(missing_ann)[:5]}) if missing_img: print(f缺图片的标注: {len(missing_img)}, 示例: {list(missing_img)[:5]}) return missing_ann, missing_img missing_ann, missing_img audit_dataset(JPEGImages, labels/yolo, .txt)这段脚本的逻辑很简单用 stem不带后缀的文件名求两个集合的差集把所有对不上的文件都揪出来。参数说明里最关键的是ext参数你检查 YOLO 标签时用.txt检查 VOC 标注时把ext改成.xml就能复用。跑完后如果 missing_ann 不为空先补标注再谈训练。如果你是准备用 yolo 训练自己的数据集这一条普适。2.2 VOC 到 COCOXML 解析成 JSON 的落地脚本很多公开遥感数据集的原始标注只有 VOC 格式COCO 和 YOLO 格式是后转换出来的。VOC 的 XML 结构很直白object节点里包裹name和bndbox而 COCO JSON 需要把全量标注聚合起来并要求每个 annotation 都有独立的 id、category_id、bbox 和 area。从 0 写这个转换脚本对新手来说最容易漏掉的是 segmentation 字段其实 COCO 检测任务里 segmentation 可以为空但 bbox 必须严格是 [x, y, width, height]这个 bbox 是左上角坐标加宽高不是中心点和 YOLO 正好相反多数人第一次转格式就是死在这。import json import xml.etree.ElementTree as ET from pathlib import Path def voc_to_coco(xml_dir, output_json): xml_dir Path(xml_dir) images, annotations [], [] cat_map, ann_id {}, 1 for idx, xml_file in enumerate(sorted(xml_dir.glob(*.xml))): root ET.parse(xml_file).getroot() img_path root.find(path).text if root.find(path) is not None else img_name xml_file.stem .jpg width int(root.find(size/width).text) height int(root.find(size/height).text) images.append({ id: idx, file_name: img_name, width: width, height: height }) for obj in root.iter(object): name obj.find(name).text if name not in cat_map: cat_map[name] len(cat_map) 1 xmin float(obj.find(bndbox/xmin).text) ymin float(obj.find(bndbox/ymin).text) xmax float(obj.find(bndbox/xmax).text) ymax float(obj.find(bndbox/ymax).text) w, h xmax - xmin, ymax - ymin annotations.append({ id: ann_id, image_id: idx, category_id: cat_map[name], bbox: [xmin, ymin, w, h], area: w * h, iscrowd: 0 }) ann_id 1 dataset { images: images, annotations: annotations, categories: [{id: v, name: k} for k, v in cat_map.items()] } with open(output_json, w) as f: json.dump(dataset, f, indent2) print(f转换完成: {len(images)} 张图, {len(annotations)} 个标注对象) voc_to_coco(Annotations, annotations_coco.json)这段脚本的核心逻辑是遍历所有 XML每张图生成一个 image 条目每个目标生成一个 annotation 条目并用 cat_map 动态注册类别。转换后建议先不急着训练用 COCO 官方的可视化脚本或自定义一个简单的画框函数抽三张图检查 bbox 是否贴合电力塔轮廓。参数说明里要注意root.find(path)在某些数据集中不存在脚本里用了兜底逻辑兼容性更好。2.3 COCO 到 YOLO从 JSON 到 txt 的最短路径COCO 转 YOLO 相对简单因为 COCO 里已经有的 bbox 是绝对坐标的 [x, y, width, height]YOLO 需要的是归一化后的中心点坐标和宽高。转换公式是固定的center_x (x w/2) / image_widthcenter_y (y h/2) / image_heightw_norm w / image_widthh_norm h / image_height。这里唯一的坑是浮点数精度电力塔是长条形小目标归一化之后 width 可能只有 0.01~0.03如果只用 round(number, 6) 会损失精度导致训练时目标框抖动或退化我一般保留小数点后 8 位。import json from pathlib import Path def coco_to_yolo(json_path, output_dir, img_dir): with open(json_path) as f: data json.load(f) img_map {img[id]: img for img in data[images]} output_dir Path(output_dir) output_dir.mkdir(parentsTrue, exist_okTrue) for ann in data[annotations]: img img_map[ann[image_id]] img_w, img_h img[width], img[height] x, y, w, h ann[bbox] cx, cy (x w / 2) / img_w, (y h / 2) / img_h wn, hn w / img_w, h / img_h line f{ann[category_id] - 1} {cx:.8f} {cy:.8f} {wn:.8f} {hn:.8f}\n txt_path output_dir / (Path(img[file_name]).stem .txt) with open(txt_path, a) as f: f.write(line) coco_to_yolo(annotations_coco.json, labels/yolo, JPEGImages)参数说明里有个细节代码里用ann[category_id] - 1做了类别索引归零因为 COCO 的类别 id 通常从 1 开始而 YOLO 的 class_id 从 0 开始漏掉这一步会导致类别全部错位。如果这个数据集里有多类别的目标比如电力塔、绝缘子、树木建议在这里加一个类别映射表而不是直接减一否则你无法处理类别 id 不是连续从 1 开始的情况。3. 划分脚本别让验证集和训练集“沾亲带故”3.1 数据集划分的三个原则按塔基单元、按采样时段、不按文件很多人写的划分脚本就是random.sample一下然后把文件复制到两个目录这种做法对遥感电力塔检测任务来说几乎是灾难。因为遥感影像通常来自同一条航线或同一个采样时段同一座电力塔会有多张不同角度的重叠成像。如果按文件随机划分同一座塔的影像会同时出现在训练集和验证集里模型在验证时看到的其实不是没见过的新目标而是训练过的塔换个角度而已mAP 虚高得离谱。我采用的划分原则有三个。第一层按塔基单元划分电力塔在遥感影像里通常以单个塔基为独立目标需要把属于同一塔基的所有裁剪图归到同一集合第二层按采样时段划分避免同一条航线同一时刻的数据跨集合第三层才是在前两层约束之下做随机均衡保证训练集和验证集的场景多样性接近。好的做法是给数据集维护一个 tower_id 索引这个索引通常在数据采集时就已经写入图片文件名里。3.2 一个实用的划分脚本同步移动图片与三种标签下面这个脚本按文件列表划分支持传入一个划分比例或者一个预定义的 txt 列表。核心逻辑是先读全部图片文件名按比例 shuffle 后切成 train 和 val然后对每组文件名同时操作 JPEGImages、Annotations、labels/yolo 三个目录保证任何一组文件在三个目录里都是同步移动的。这个脚本对 yolo 训练自己的数据集的场景可以直接复用只需要改改路径。import random from pathlib import Path import shutil def split_dataset(img_dir, voc_dir, yolo_dir, val_ratio0.2, seed42): img_dir, voc_dir, yolo_dir Path(img_dir), Path(voc_dir), Path(yolo_dir) imgs [p for p in img_dir.iterdir() if p.suffix.lower() in (.jpg, .jpeg, .png)] random.seed(seed) random.shuffle(imgs) val_count int(len(imgs) * val_ratio) val_imgs, train_imgs imgs[:val_count], imgs[val_count:] for split, img_list in [(train, train_imgs), (val, val_imgs)]: for img in img_list: stem img.stem for src_dir in [img_dir, voc_dir, yolo_dir]: src_file None for suffix in [.jpg, .jpeg, .png, .xml, .txt]: candidate src_dir / (stem suffix) if candidate.exists(): src_file candidate break if src_file is not None: dst_dir src_dir.parent / split / src_dir.name dst_dir.mkdir(parentsTrue, exist_okTrue) shutil.copy2(src_file, dst_dir / src_file.name) print(ftrain: {len(train_imgs)}, val: {len(val_imgs)}) split_dataset(JPEGImages, Annotations, labels/yolo, val_ratio0.2)这段脚本我强调几个参数。第一val_ratio0.2是默认值对于目标类别单一、样本量大的电力塔检测验证集 15%~20% 是合理区间如果后续要做模型调参和早停验证集过大反而会拖慢训练节奏。第二seed42必须固定否则每次划分结果不一致你没法对比两次训练的效果差异。第三脚本用的是copy2而不是move避免在实验阶段频繁重新划分覆盖原始数据等确认划分方案没问题再把copy2改成move省磁盘空间。3.3 划分完必须做的三类自检划分脚本跑完后我建议做三类自检每类都可能成为后面训练失败的原因。第一类是数量对齐自检train 目录下的图片数是否等于 annotations 下的 XML 数、是否等于 labels/yolo 下的 txt 数任何一边不齐都说明划分逻辑有分叉。第二类是类别分布自检验证集里的类别比例是否和训练集接近如果电力塔类别下有几个变体角钢塔、钢管塔、输电塔要确认这些变体没有全部落进验证集。第三类是内容泄漏自检抽查验证集里 20 张图片确认它们对应的塔基没有在训练集里出现过。# 统计 train 和 val 各目录下的文件数快速对齐检查 for split in train val; do echo [$split] JPEGImages: $(ls $split/JPEGImages | wc -l) echo [$split] Annotations: $(ls $split/Annotations | wc -l) echo [$split] labels/yolo: $(ls $split/labels/yolo | wc -l) done # 统计 yolo 格式的类别分布单类别时只关心总数 for split in train val; do echo [$split] class counts: cat $split/labels/yolo/*.txt | awk {print $1} | sort | uniq -c done这两条命令背后是检查脚本的核心思路一是验证划分完整性二是验证类别分布。如果 yolo 格式的类别 id 不止 0说明数据集里混了其他目标类别需要回到 2.3 节的类别映射表去查看看是不是转换时 id 没有归零。划分脚本是数据集建设的最后一道关卡这道关卡没守住后面的训练全部白跑。4. 用 YOLOv8 在 Anaconda 里跑通训练最小配置到训练参数4.1 环境配置Anaconda 虚拟环境与依赖安装的版本要点yolo v8 anaconda环境配置要求是很多人在刚开始就卡住的地方本质是 torch 和 CUDA 的版本配对问题。遥感电力塔景象一般用 GPU 训练所以先确认nvidia-smi里的 CUDA 版本然后安装对应版本的 PyTorch。我建议用 Anaconda 建独立环境而不是直接装在 base 里因为 Python 版本冲突和包依赖污染会让你排查到怀疑人生。conda create -n yolo python3.9 -y conda activate yolo pip install ultralytics8.2.0 # 如果已有 NVIDIA GPU务必安装 CUDA 版 PyTorch而不是 CPU 版 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121参数说明里要留意两处。第一Python 3.9 是目前 ultralytics 兼容性最稳的版本3.10 以上在某些老版本 numpy 下会出现诡异报错。第二--index-url指定了 cu121 意味着你需要 CUDA 12.1 及以上的驱动如果你的驱动只支持 CUDA 11.8把cu121换成cu118即可。装完之后验证一下import torch; torch.cuda.is_available()返回 True再继续往下做。4.2 dataset.yaml 的写法单类别数据集的路径与类名配置ultralytics 的 YOLOv8 训练需要一份 dataset.yaml 文件来描述数据集位置和类别。很多人直接复制官方示例的 coco128.yaml 来改结果漏改了 paths 导致训练时报错 “Dataset not found”。对单类别电力塔检测yaml 文件最简只需要下面几行。# datasets/electrical_tower.yaml path: D:/datasets/electrical_tower # 数据集根目录推荐绝对路径 train: images/train val: images/val names: 0: electrical_tower注意一个关键点这里的train和val是相对path的路径。很多划分脚本会把图片目录命名成JPEGImages而 yaml 里默认找的是images/train所以要么把划分逻辑改为输出到images/train要么在这里显式写train: JPEGImages/train。我一般直接让划分脚本按 yaml 的约定输出目录省得训练时再对路径。4.3 训练命令与四个关键参数imgsz、batch、epochs、patience训练命令本身不长但参数组合直接影响遥感电力塔这种小目标任务的收敛效果和显存占用。下面这组参数是多次跑下来的经验值适合图像尺寸接近 1024×1024 的遥感影像。yolo detect train \ modelyolov8n.pt \ datadatasets/electrical_tower.yaml \ imgsz1024 \ batch8 \ epochs100 \ patience15 \ device0参数说明是这份训练教程的核心逐条讲清楚。imgsz1024是关键电力塔在遥感影像里的像素尺寸往往只有 20×60 左右如果按默认的 640 去训练下采样后塔基只有十几个像素特征几乎丢失。batch8是显存上限决定的1024 分辨率下 8 张图大约需要 16G 显存如果你的卡只有 12G降到 4。epochs100是初始值配合patience15做早停如果 15 个 epoch 验证集 mAP 没有提升就自动停止防止在无效训练上烧时间。device0指定第一张 GPU如果你的机器有多卡可以改成device0,1,2,3做分布式训练。训练过程中要注意看两个指标。一个是 loss 曲线正常情况 box_loss 和 cls_loss 应该在 30 个 epoch 内持续下降如果 loss 在某个点突然升到 NaN基本是学习率太高或数据里有坏标注。另一个是验证集 mAP50电力塔这种大目标占比不平衡的数据集mAP50 达到 0.85 以上才算初步可用低于 0.7 说明数据或标注有问题调参救不回来。5. 遥感电力塔目标检测训练避坑清单5 条血泪经验5.1 小目标标签归一化精度丢失目标直接消失现象训练正常启动但 loss 下降缓慢验证时模型几乎不召回电力塔预测框时有时无。查 labels 目录发现部分 txt 里的宽高值小到离谱比如0.00123456这种。原因COCO 转 YOLO 时用了 round 6 位小数长条形小目标的 height 值在 1024 分辨率下只有 20 像素归一化后是 0.0195保留 6 位没问题但某些标注的 bbox 本来就只有 8 像素宽归一化后是 0.0078如果标注文件用的是 float16 保存直接变成 0.0078 的近似误差小目标框退化。解决统一用 round 8 位保存 YOLO 标签并在划分后抽检 txt 里的坐标值最小宽高低于 0.005 的标签要退回去查原标注。5.2 整图塞进 YOLO 训练显存爆掉现象batch 设了 16imgsz 设 1024开始训练不到一分钟显存欧拉进程被杀。原因遥感影像通常分辨率很高直接把大图作为训练输入显存消耗呈指数增长。解决要么把 imgsz 降到 640 接受精度损失要么对影像做切 patch 预处理把 4000×4000 的原图切成 1024×1024 的滑窗块再按块训练。我一般用后者切 patch 时设置重叠率 20%~30%避免塔基被切在 patch 边缘而截断。5.3 划分脚本同步不到位训练时图片与标签对不上现象训练日志报大量 warningsfound no labels in ...但打开 labels 目录看文件明明存在。原因划分时只移动了图片和 yolo 标签忽略了 VOC 的 XML或者反过来导致三个目录的文件数不齐。训练脚本在加载时找不到对应标签文件自动跳过这些图片等于白训。解决跑完划分脚本后必须做 2.1 节的审计检查把三个目录的文件求差集确保一一对应后再训练。这一条是我的血泪经验建议把它写成一个 shell 函数每次划分后自动执行。5.4 验证集 mAP 虚高换一组数据就翻车现象训练时验证集 mAP50 到 0.92自认为模型很好了换一批新的遥感图测试检测率直接掉到 0.5 以下。原因划分时没有按塔基单元切分同一座塔的多个视角同时出现在训练和验证集模型记住了塔的位置和角度而不是泛化出塔形特征。解决回到 3.1 节的原则按 tower_id 或地理坐标分桶再划分验证集必须保证与训练集完全没有空间重叠。这条问题通常在项目验收阶段爆发返工成本最高建议第一个划分版本就按单元切。5.5 Anaconda 环境里 torch 与 CUDA 版本错配训练速度返祖现象训练能启动但 GPU 利用率只有 10%每轮 epoch 要跑半小时以上CPU 占用却拉满。原因pip install ultralytics默认装的是 CPU 版 torch或者 torch 版本与本地 CUDA 驱动不匹配导致模型全部在 CPU 上跑。解决装完环境后先跑python -c import torch; print(torch.cuda.is_available())返回 True 再看nvidia-smi里的利用率如果返回 False重装 cu121 或 cu118 对应的 torch不要用pip install torch默认版本那大概率是 CPU 版。6. 落地验收与进阶技巧mAP 之外还要看这四件事6.1 验证集可视化把预测框画回原图看漏检训练结束后mAP 只是一个数字落到真实场景里还要看置信度门限怎么调、哪个场景漏检。用一行命令在验证集上做推理然后把结果保存成带框的图片这是最直接的验收方法。yolo detect predict \ modelruns/detect/train/weights/best.pt \ sourcedatasets/electrical_tower/images/val \ conf0.25 \ saveTrue \ save_txtTrue \ imgsz1024参数说明里两个值要重点调。conf0.25是置信度门限对电力塔这种目标特征相对明显的类别0.25 会输出大量候选框用于排查漏检很好用如果做工程化部署建议调高到 0.45~0.55 来压低误检。save_txtTrue会把预测框存成 YOLO 格式的 txt方便后续做几何后处理。我通常会把假阴性的图片单独捞出来看九成的漏检集中在两类场景一是塔基被植被、阴影部分遮挡二是塔身与背景纹理高度融合。如果你也遇到类似情况针对性地给训练集补充这两类困难样本比盲目堆 epoch 有效得多。6.2 置信度门限与 NMS 参数的实用调整调门限时不少人直接螺验证集上的 mAP 曲线但电力塔场景更实用的是把 Precision-Recall 曲线拉出来看。你要找到 Precision 和 Recall 的相对平衡点比如要求 90% 精确率时 Recall 还能保多少。方法是在验证阶段用conf0.001跑一次全量推理然后按分数排序统计出不同门限下的 P/R 值再按业务需求选门限。对电力巡检场景我一般选 Recall 不低于 0.9 的最低门限因为漏检一座塔可能意味着整条线路的巡检报告要返工而多框几个候选框后期还有人工确认环节兜底。6.3 滑窗推理大图上的电力塔检测落地方法训练时用了 1024 的 patch推理时直接拿整张遥感图进去预测会遇到两个问题显存不够、小目标被下采样抹掉。常见做法是滑窗推理先用 numpy 把大图切成 1024×1024 且带重叠率的窗口逐窗口预测后再把框坐标映射回原图最后基于 IoU 做跨窗口的去重合并。import torch import numpy as np from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) def infer_large_image(img, window_size1024, overlap0.25, conf0.3): h, w img.shape[:2] stride int(window_size * (1 - overlap)) detections [] for y in range(0, h - window_size 1, stride): for x in range(0, w - window_size 1, stride): patch img[y:y window_size, x:x window_size] results model.predict(patch, confconf, verboseFalse)[0] for box in results.boxes.xyxy.cpu().numpy(): detections.append([x box[0], y box[1], x box[2], y box[3], float(box[4]), float(box[5])]) return np.array(detections)这段代码用双层循环遍历整张大图每个窗口预测出的框坐标都加上窗口在原图中的偏移量重新映射回全图坐标系。参数说明里overlap0.25是经验值太小会把跨窗口的同一座塔截成两半增加后处理去重的难度太大的重叠率让推理时间接近翻倍。最后要对重合度超过 0.5 的跨窗口框做一次 NMS 合并这个可以用torchvision.ops.nms一行实现否则同一座塔会被输出两次。这一套滑窗推理逻辑在整个模型落地阶段都用得上效果稳定也容易调试。做检测项目这几年我最大的教训是数据集本身的质量决定了精度的天花板模型结构只是锦上添花。拿到这份含三种格式标注和划分脚本的电力塔数据集先花半天把格式、划分、环境验证走完再动手训练你会在后面的调试里省出一个周末的时间。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。