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

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

发布时间:2026/9/24 22:15:38

资讯中心
01
ARTICLE

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

YOLO遥感电力塔目标检测:数据集格式转换与训练全流程指南
简介面向目标检测学习者和遥感应用开发者这份资源提供了真实场景下的电力塔目标检测数据集。数据集中包含一千张高质量图片均已使用LabelImg完成标注并同时提供VOC、COCO和YOLO三种格式标签分别存放可直接接入YOLO系列模型进行训练省去格式转换环节。压缩包共两千个文件以xml和txt标签为主体另含6个html教程文档、3个Python划分脚本和1个yaml配置文件整体约177.44MB。随包附赠YOLO环境搭建与训练案例教程覆盖Linux和Windows版本并提供了训练集、验证集、测试集划分脚本用户可根据实际需求自由切分数据。目前已有265人学习下载适合刚接触YOLO或需要规范化遥感数据集的研究者快速上手也可作为电力设施巡检等项目的预训练数据基础。 拿到一份「YOLO遥感电力塔目标检测数据集」压缩包别急着解压跑训练。先想清楚一个问题你的检测任务是地面视角还是高空俯视这两个场景里同一座电力塔在画面中的尺寸能差出十倍。遥感影像里的电力塔往往只有几十像素宽背景混着植被、建筑和阴影泛化差的模型在这个场景下的置信度会全线跌破0.3。这个资源包恰好补上了整条链路1000张带标注的遥感电力塔图片VOC、COCO、YOLO三种标签格式都能直接喂进常见训练框架附带的划分脚本帮你在训练前把数据切干净训练教程负责从环境配置到出结果这最后一公里。适合正在做电力设施巡检、遥感目标检测以及刚入门想把「数据→训练→评估」完整跑通一遍的CV从业者。2. 三种标签格式为什么都要给VOC、COCO和YOLO的体系差异目标检测常用标注工具labelimg默认存成Pascal VOC的xml手动切成YOLO模式就导出txt很多人以为只是换了后缀。真实的差异比这大得多坐标系基准不同、数值是否归一化不同、类别用字符串还是整数、同一个COCO框架里检测和分割的id管理方式都不一样。三种格式互不直接兼容而训练框架往往只认其中一种。这份数据集的价值点在于同一批框被转成三种独立可用的标签替你省掉了最容易出错的那层转换。要验证这个说法先看清三种格式各自长什么样。2.1 VOC的XML左上角和右下角的两个像素点VOC的xml以图片文件为单位组织一张图对应一个annotation根节点目标信息写进object里坐标落在bndbox。xmin、ymin是框左上角xmax、ymax是右下角单位是像素绝对值不归一化。下面是一张2560×1920影像里单座电力塔的标注annotation folderimages/folder filenameimg_0001.jpg/filename size width2560/width height1920/height depth3/depth /size object namepower_tower/name bndbox xmin342/xmin ymin287/ymin xmax415/xmax ymax402/ymax /bndbox /object /annotation注意VOC的bndbox不直接存宽高框的宽度要靠xmax减去xmin算出来类别是字符串name。解析时最常踩的坑是漏了size节点或者把xmax、ymax错当成宽高直接读。任何训练框架拿到xml之后都要先做这一步换算换算错一次框就整体偏移。2.2 COCO的JSON图片和标注拆成两个大数组COCO格式用images和annotations两个顶层数组组织。images里存图的id、文件名和宽高annotations里每一条目标对应一个整数image_idbbox字段是[x, y, width, height]形式的像素绝对值。categories单独成表把category_id映射到类别名。{ images: [ {id: 1, file_name: img_0001.jpg, width: 2560, height: 1920} ], annotations: [ {id: 1, image_id: 1, category_id: 0, bbox: [342, 287, 73, 115]} ], categories: [ {id: 0, name: power_tower} ] }COCO的坑不在坐标换算而在id体系。第一image_id和category_id都要手工维护对应关系漏一个字段训练时就会报找不到样本。第二测试阶段经常出现category_id从0开始还是从1开始的混乱两种写法在社区代码里都存在使用前先确认目标检测框架的约定。第三纯检测任务里segmentation字段可以省略但很多通用解析器会硬读这个键读到空列表直接抛异常转换时最好带上一个空的分割占位。2.3 YOLO的TXT一行一个目标的归一化坐标YOLO的标签最简洁一张图对应一个同名txt每行描述一个目标类别索引、中心点x、中心点y、宽、高共五个数。全部除以图片宽高归一化到0到1区间类别用整数索引而不是字符串。0 0.14785 0.17943 0.02852 0.05990 0 0.62301 0.41127 0.03516 0.07148这行记录表示类别索引0目标中心点在图像宽度的14.785%、高度的17.943%处框宽占整图宽度2.852%高占5.99%。YOLO格式的常见翻车点有三个一是忘了归一化把像素坐标直接写进去训练loss直接变成nan二是类别写了字符串名解析器按int读就报错三是保留小数过短归一化值只留三位小数对宽框影响不大但遥感里电力塔本身只有几十像素宽误差占比明显建议至少保留六位。2.4 自写转换脚本把VOC转成YOLO时真正要注意的是什么格式坐标含义数值范围类别表示典型训练框架VOC xmlxmin, ymin, xmax, ymax像素绝对值字符串nameSSD、Faster R-CNN系列COCO jsonx, y, width, height像素绝对值整数category_idDetectron2、MMDetectionYOLO txtcx, cy, width, height0~1归一化整数索引YOLO系列转换逻辑本来很简单但遥感的图幅尺寸跨度大加上部分标注框贴近影像边缘转换时很容易产生越界坐标。以VOC转YOLO为例我一般会这么写import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_path, class_map): tree ET.parse(xml_path) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_map: continue box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 越界裁剪边缘目标常因人工标注误差超出图像边界 xmin, xmax max(0, xmin), min(w, xmax) ymin, ymax max(0, ymin), min(h, ymax) cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{class_map[name]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines))class_map要把VOC里的字符串类别名映射成整数索引比如{power_tower: 0}这一步的对应关系必须和训练时的data.yaml完全一致差一位就是灾难。裁剪逻辑放在归一化之前能有效防止浮点误差把边缘框推出0到1区间。程序跑完别急着训练抽样几十张图把txt画回jpg上肉眼检查一遍。别靠看数字判断对错框画出来不对后面所有指标都是黑匣子。提示转换脚本里建议强制检查w和h是否为0。遥感影像偶尔会有EXIF异常导致读不出宽高的图片不拦下来后面全是nan loss。3. 划分脚本先想清楚再跑遥感数据藏着随机切分的坑压缩包里的划分脚本标准做法是按文件随机拆成train、val、test三份。随机本身没问题问题是遥感数据天生带空间相关性——同一张大图切出来的瓦片相邻两块内容重合度极高。如果只按文件名乱序抽取训练集和验证集里很可能躺着同一座塔的邻近视角验证指标虚高换个城市立刻翻车。这一章把划分这件事拆开讲清楚什么情况下能随机切什么情况下必须按来源切以及切完怎么自查。3.1 随机划分的隐性风险空间自相关让数据泄漏于无形数据泄漏这个词在遥感任务里远比在自然图像里严重。自然图像里同一只猫的不同照片差异很大但遥感影像里相邻瓦片的重合度可以超过60%尤其是塔身和杆塔阴影这种纹理特征几乎一模一样。随机划分后模型在训练时见过某座塔的东半部分验证时又看到同一座塔的西半部分mAP分数自然好看。等到部署时撞上一座全新的塔模型表现断崖式下跌。处理办法要看数据来源。如果1000张图是从若干张大图中滑窗切出来的标准做法是把切片的来源图id作为分组依据同一张大图的所有切片进同一个集合避免跨集合泄漏。如果图片本身就是独立的航拍单帧来源信息不可考可以用间隔采样代替纯随机把文件按文件名排序后每隔10张取1张进验证集从空间分布上拉开距离。这个资源包里每个方向的做法我一般都默认走强一点宁可验证集分数调低一点也要先保证评估是干净的。3.2 一个够用的划分脚本固定种子、校验标签、输出清单围绕这个资源包我会把划分脚本写成下面这样。它做四件事筛出有标签的图片、固定随机种子切分、生成训练可用的清单文件、统计每个集合的类别分布。import os import random from collections import Counter ratio (0.8, 0.1, 0.1) seed 42 name power_tower image_dir images label_dir labels img_exts {.jpg, .jpeg, .png, .tif} label_exts {.xml, .json, .txt} items [] for f in sorted(os.listdir(image_dir)): stem, ext os.path.splitext(f) if ext.lower() not in img_exts: continue # 三个格式里至少有一个标签文件才保留 has_label any( os.path.exists(os.path.join(label_dir, stem e)) for e in label_exts ) if has_label: items.append(stem) print(带标签图片数:, len(items)) random.seed(seed) random.shuffle(items) n len(items) sp1 int(n * ratio[0]) sp2 int(n * (ratio[0] ratio[1])) sets { train: items[:sp1], val: items[sp1:sp2], test: items[sp2:], } os.makedirs(split, exist_okTrue) for k, v in sets.items(): with open(fsplit/{name}_{k}.txt, w, encodingutf-8) as f: for stem in v: f.write(stem \n) print(k, len(v)) def count_classes(stems, label_dir): cnt Counter() for stem in stems: p os.path.join(label_dir, stem .txt) if not os.path.exists(p): continue with open(p, encodingutf-8) as f: for line in f: cnt[int(line.split()[0])] 1 return cnt for k, v in sets.items(): print(k, count_classes(v, label_dir))逻辑说明代码先扫描图片目录用文件主名匹配三种标签格式只要存在任意一种就算这条样本有效。随后固定随机种子再做shuffle保证同一份数据每次跑出来的划分结果完全一致。切分比例8:1:1是通用的起点值1000张图训练集有800张对单类检测够用了但对数据增广还不太充裕通过yaml里的增强参数补。类别统计放在最后是为了看一眼三个集合里正样本比例是否接近——如果训练集里70%的塔都被切走了验证集上mAP再高也不可信。参数说明seed的值不一定要42但固定下来后不要频繁改动这直接关系到实验可复现。ratio的元组顺序对应train、val、test乘积之和应等于1。label_exts里要不要带.json取决于你最终训练框架吃哪种格式如果只用YOLO格式训练可以把json排除避免把残缺的多边形标注样本选进来。3.3 划分完先做对齐自检三条命令找出脏数据划分不是终点。切完之后第一件事是核对图片和标签数量是否对齐这一步比训练快得多却能在几分钟内拦住脏数据。ls images | wc -l ls labels | wc -l # 找出没有对应标签文件的图片 for f in images/*.jpg; do n${f%.jpg} if [ ! -f labels/$(basename $n).txt ]; then echo missing label: $f fi done这个检查做完继续检查反方向找出没有图片的孤儿标签。训练框架通常不会为这两类报错而是静默地跳过或当成空标注处理直接表现为loss曲线莫名其妙地抖动。还有一种漏网情况是图片存在但打不开用Python的PIL跑一遍全部读入校验最稳妥from PIL import Image import os for f in os.listdir(images): try: with Image.open(os.path.join(images, f)) as im: im.verify() except Exception as e: print(bad image:, f, e)这块自检脚本可以合并进第2章的格式转换流程里一个函数同时处理VOC转YOLO和损坏图片过滤能把后期排错时间压缩一半。提示验证集里务必保留少量带目标的复杂样本比如阴影遮挡、密集排布的电力塔。一份全是干净单塔的验证集无法暴露真实场景里最普遍的漏检问题。4. 跑通训练的最小链路环境、目录、三组关键参数再高质量的数据集跑不通训练流程就等于零。yolo环境配置是新手第一道坎十次报错里有八次是torch版本和CUDA不匹配。先把环境做成最小可用再谈训练本身。这一章节按「环境 → 目录 → 训练 → 验证」的顺序来每步都给出可直接复制的命令和必须调整的位置。4.1 环境配置conda里建独立环境验证CUDA可用再继续conda create -n yolo python3.10 -y conda activate yolo pip install ultralytics python -c import torch; print(torch.cuda.is_available())逻辑说明独立环境隔离Python版本和依赖避免把系统环境搞乱。ultralytics是YOLO系列训练框架的通用入口安装时会连带torch等核心依赖。最后一行验证CUDA是否可用输出True再继续输出False就去查显卡驱动和CUDA版本。参数说明python用3.10是当前兼容性最稳的选择3.11、3.12在部分torch版本下会报编译错误。如果机器没有NVIDIA显卡或者显存小于4GB建议直接用CPU训练做流程验证把epochs降到5跑通pipeline等有卡再上正式训练。macOS用户装ultralytics默认走MPS写devicemps能跑但性能和踩坑成本都比CUDA高。4.2 目录结构YOLO只认它熟悉的组织方式YOLO训练不识别散落的图片和标签需要把数据按下面结构放好power_tower/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/图片和标签目录保持相同内部结构文件名一一对应。然后用一个yaml描述数据集path: /data/power_tower train: images/train val: images/val test: images/test nc: 1 names: 0: power_tower参数说明path建议写绝对路径避免在训练命令里反复cd。nc是类别数量遥感图像目标检测这种单类场景就是1。names里的类别顺序必须和TXT标签里的整数索引对齐这是整个配置里最容易埋雷的位置——索引错位模型也能训练但检测结果和标签名完全对不上。写完后用一行Python验证yaml解析无异常python -c import yaml; dyaml.safe_load(open(power_tower.yaml)); print(d[nc], d[names])4.3 训练命令与参数从nano模型开始跑通流程以ultralytics框架为例训练命令长这样yolo detect train \ modelyolov8n.pt \ datapower_tower.yaml \ epochs100 \ imgsz640 \ batch16 \ workers4 \ device0参数说明model指定预训练权重yolov8n是nano版本显存占用小、迭代速度快适合先跑通流程等确认loss行为正常再换yolov8s或yolov8m提精度。epochs设100配合早停机制默认patience为50个epoch验证集指标不再提升会自动中断。imgsz640是速度与精度的平衡点遥感里电力塔属于小目标我一般首轮用640跑通第二轮直接拉到1024代价是显存占用翻倍。batch16按显存调8GB显存从16开始OOM就减半。workers4是数据加载进程数别试图拉满Windows下workers超过2经常触发死锁。训练过程中重点盯三行日志box_loss、cls_loss、dfl_loss。yolo损失函数由这三部分加权组成box_loss反映回归质量cls_loss反映分类置信度dfl_loss负责框分布的精细调整。如果box_loss在初始阶段就剧烈震荡不收敛大概率是标签和图片没对齐先回去查数据别浪费时间调参。loss一直降说明训练在正常吃数据epochs不用跑满等验证集指标稳定就手动停。4.4 训练完成后的三个验证动作训练完不要只看终端里那个mAP50。第一件事跑验证并导出JSONyolo detect val \ modelruns/detect/train/weights/best.pt \ datapower_tower.yaml \ splitval \ save_jsonTruesave_jsonTrue会把每张图每个框的得分、类别、坐标导出这是后续做假阳性分析的基础。第二件事打开runs/detect/val下的混淆矩阵图看power_tower被错分成什么。第三件事抽三张验证集图片做预测可视化yolo predict \ modelruns/detect/train/weights/best.pt \ sourcepower_tower/images/val \ saveTrue \ conf0.25人工看一遍框的位置比任何指标都更直接。框整体偏大或偏小、漏了阴影里的塔、把建筑物标成塔这些问题在指标上看不出来但画出来一眼就能定位。提示训练过程中如果意外中断ultralytics会在runs目录保留last.pt。把命令里的model参数指向last.pt resumeTrue可以从断点续训不用重新开始。5. 遥感电力塔训练的五个高频事故排查下面五条不算冷门全是血泪经验。按顺序对照现象排查大概率能救回一个看起来已经废掉的训练。每条按「现象 → 原因 → 解决」的结构来可直接对号入座。5.1 训练集loss稳稳下降验证集曲线平得像条直线现象前几十个epoch里训练loss持续下降但验证集loss纹丝不动mAP50长期趴在0.3以下。原因最常见的是数据划分泄漏导致验证集和训练集过于相近或过于相远。过于相近时验证指标虚高但不降说明模型在背答案过于相远时验证loss不降说明模型学到的特征迁移不过去。第二个常见原因是数据增强开太猛mosaic概率拉满时训练样本被切得面目全非模型学到的纹理和实际目标对不上。解决先关掉mosaic和mixup把增强参数降到接近默认值重跑30个epoch看曲线是否恢复正常。若验证集仍然不降检查第3章的对齐脚本确认训练集和验证集没有来自同一张大图。都不行再考虑学习率问题把lr0从默认0.01降到0.001用验证集loss曲线判断是否在震荡。5.2 mAP50很高画出来的框却整体偏移现象验证集mAP50能到0.85以上但可视化预测时框总偏在塔身一侧或者框整体偏小没包住塔基。原因这类问题80%出在标签转换而非模型。VOC转YOLO时如果忘了把坐标转float整数除法会让xmax减xmin的结果直接截断导致所有框偏小一两个像素。塔身本身只有几十像素时一个像素的偏移在mAP上几乎无感但框画出来就是不对齐。解决回到第2章的转换脚本检查是否有int/int的写法确保所有运算都落在浮点数上。然后随机抽20张图把TXT解析后的框画回原图逐一和原标注对照。画框脚本用OpenCV的rectangle就能做不值得在这步省时间。5.3 远处小目标和阴影遮挡导致漏检率奇高现象近距离清晰塔都能检出来但影像边缘的小塔和埋在阴影里的塔被大量漏掉recall明显偏低。原因遥感影像里电力塔的视觉尺寸本身就小640输入尺寸下一座塔可能只有20×30像素下采样两次后特征几乎消失。模型不是学不会是特征图里根本没留下足够信息。解决首选把imgsz提到1024或1280显存不够就降低batch。次选是切片推理先把大图切成若干小块输入推理后再把框映射回原图坐标合并。训练侧可以降低mosaic概率避免小目标在增强后变得更小到无法学习。这个数据集里小目标占比如果偏高我一般会单独统计一下目标宽高分布低于16像素的目标占比超过两成就优先做切片训练而不是硬调模型结构。5.4 显存OOM和进程被杀现象训练到第二个或第三个epoch时进程突然消失终端报CUDA out of memory或者整机无响应。原因batch和workers设置超出了机器实际能力。显存看着够用但mosaic数据增强会临时创建更大的中间张量峰值显存往往在前几个epoch出现。workers开太多则会让CPU排队内存溢出的进程会被系统杀掉。解决batch直接减半比如16降到8。imgsz从1024退回640。把cacheFalse不预加载全部图片进内存。workers降到2。如果机器是双卡先把device0改成单卡训练排除并行通信问题。这类问题属于配置问题而非模型问题不要为了迁就显存去改模型结构容量不够后面还得改回来。5.5 同数据集指标优秀换一批影像立刻翻车现象自己划分的测试集上mAP50有0.88拿到新区域的航拍影像上检测漏检率突然涨到40%以上。原因训练集覆盖了单一传感器、单一季节、单一高度模型把「这个色调下的塔」当成了「塔」。遥感图像目标检测最常见的泛化陷阱不是类内差异而是成像条件差异。同一个数据集里指标再高跨区域、跨时相的表现也无法保证。解决上线前准备一小批与训练集来源不同的负样本只跑推理不做训练统计误检率。如果翻车把新影像里的少量样本补进训练集做增量训练不要试图用调参来解决数据覆盖问题。这才是遥感数据集的正确迭代方式先确认分布差异再决定补多少数据而不是盲目优化当前验证集。6. 判断模型能不能上线置信度门限、混淆矩阵和切片推理训练完成不等于能交付。部署前的最后一步是用验证集输出物给模型做一次全面体检核心是调整置信度门限和检查假阳性来源。置信度门限直接决定漏检和误报的平衡。电力巡检场景里漏检一座塔的代价远大于误报一次我一般会把推理置信度从默认的0.25压低到0.1以下让模型倾向于多输出候选框再交给人工复核。执行命令时通过conf参数控制yolo detect predict \ modelruns/detect/train/weights/best.pt \ sourcenew_region_imgs \ conf0.10 \ iou0.45conf越低框越多假阳性也会上升。配合confusion_matrix.png来看错检具体集中在哪里。如果大量误报框落在铁塔阴影和建筑物边缘说明模型学到的是高对比度竖直线条而不是塔身结构这时候调门限救不回来需要补负样本。如果误报相对均匀分布门限压低带来的额外人工复核成本才是可接受的。面对大幅遥感影像时直接整图推理的检测效果通常很差。遍历整张图的塔目标我习惯把原图切成若干小块分别推理再按原始坐标拼回去。切块尺寸用640重叠保留50像素推理完成后对重叠区域的框做NMS合并。这个流程不需要改模型纯推理侧处理但召回率提升非常明显。切片数量多后推理时间线性上涨和巡检任务的实际时效约束权衡着来可以先在10张图上验证效果再全量铺开。我自己的习惯是模型在mAP50过0.85之后再跑一轮负样本测试只拿完全没有塔的影像去推理统计假阳性次数。这一步拦下过两版数据分布没对齐、注定要返工的模型。配置、数据、训练、验证全链路能自动化之后这轮体检花不了半小时却决定了模型能不能真正落到生产环境。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

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

03
WHY YAOTU

想打造同款高转化官网?

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

场景化定制

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

营销型架构

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

全周期服务

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

免费获取你的建站方案

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