新闻详情

新闻详情

首页 / 资讯中心 / 详情

遥感卫星图飞机目标检测:XML标注转YOLO训练实战与避坑指南

发布时间:2026/9/28 16:37:21来源:尧图网络
遥感卫星图飞机目标检测:XML标注转YOLO训练实战与避坑指南
简介这是一套聚焦遥感场景的飞机目标检测数据集适合目标检测初学者、算法研究者以及遥感图像分析人员使用帮助解决在复杂卫星背景下识别并定位飞机的任务。包体包含1000张1024×1024高分辨率彩色卫星图像、1000份配套XML标注文件和1份info.txt元数据说明共2000个文件压缩包大小约291.76MB图像与标注一一对应可直接用于YOLO、Faster R-CNN等检测模型的训练与评估。目前已有633人学习下载。数据集类别单一仅标注飞机目标既便于上手单类别检测又包含阴影、反射、遮挡等卫星影像特有挑战适合进行数据增强、训练集/验证集划分等实验。通过这套资源可以完整经历数据准备、标签解析、模型训练与遥感场景评测流程为无人驾驶、智能监控、遥感图像分析等实际应用打下基础。1. 卫星图飞机目标检测这份 1000 张 1024×1024 的遥感数据集值得先看做目标检测的人都知道通用数据集COCO、VOC里飞机是侧视角的而卫星图像里的飞机是典型的俯视小目标外观差异极大。如果你正在做遥感图像分析、机场监控或者大作业选题这份“人工智能目标检测数据集飞机卫星图3”就是为单类别飞机检测准备的1000 张 1024×1024 彩图每张图配一个 XML 标注文件类别只有飞机一类不掺杂其他目标。对新手来说单类数据能让你专注跑通训练流程而不被类别平衡问题干扰对熟手来说这套数据天然带有小目标、阴影、遮挡、反射等遥感场景难点用来验证检测模型在俯视视角下的表现很合适。2. 数据集结构与 XML 标注格式先搞懂 1000 张图怎么组织、坐标怎么读2.1 拿到数据集先做三件事数文件、查对应关系、看标注分布数据集的图片文件命名是 airplane-003-0595.jpg 这种格式从 airplane-003-0584.jpg 到 airplane-003-0704.jpg 这一批里选出 1000 张。annotations 文件夹放的是同名 XMLinfo.txt 通常是数据集说明。我第一次拿到这类数据时踩过坑直接进入训练流程结果训练到一半发现 XML 和图片数量对不上。所以拿到数据第一件事是写个脚本做完整性检查。# 统计图片和 XML 数量 ls *.jpg | wc -l ls annotations/*.xml | wc -l # 找出没有对应 XML 的图片 for f in *.jpg; do base${f%.jpg} if [ ! -f annotations/${base}.xml ]; then echo 缺失标注: ${f} fi done这段脚本的逻辑是先把图片和 XML 的数量对齐再逐张检查同名 XML 是否存在。对 1000 张图的数据集来说这两条命令几秒钟就能跑完能避免后续训练时因为文件缺失报 FileNotFoundError。我这里用的 bash 文件名提取方式依赖固定的命名规则如果你的数据格式不同可以用 Python 里的 pathlib 替代。检查完数量我会再用一段 Python 统计所有 XML 里的目标数分布确认没有大面积漏标或者每个图都只有一两个目标导致的训练信号不足import glob import xml.etree.ElementTree as ET xml_files glob.glob(annotations/*.xml) total_objs 0 empty_files [] for xml_file in xml_files: tree ET.parse(xml_file) root tree.getroot() objs root.findall(object) total_objs len(objs) if len(objs) 0: empty_files.append(xml_file) print(fXML 文件总数: {len(xml_files)}) print(f目标总数: {total_objs}) print(f平均每张图目标数: {total_objs / len(xml_files):.2f}) print(f空标注文件数: {len(empty_files)})这段代码用 xml.etree.ElementTree 解析每个 XML统计 object 节点数量。空标注文件必须记录下来单独处理要么删除对应图片要么保留作为负样本但负样本在 YOLO 训练里需要特殊配置我建议初期先把空标注文件筛掉避免影响 loss 计算。2.2 解读 VOC 风格的 XML边界框坐标是绝对像素值这个数据集用的 XML 是 Pascal VOC 风格和 ImageNet 检测任务的标注格式一致。核心结构是每个 object 节点下面有一个 bndbox 子节点里面存放 xmin、ymin、xmax、ymax 四个值表示目标矩形框的左上角和右下角坐标单位是像素。由于图像是 1024×1024所以这四个值取值范围通常是 0 到 1024。import xml.etree.ElementTree as ET def parse_voc_xml(xml_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_width int(size.find(width).text) img_height int(size.find(height).text) boxes [] for obj in root.findall(object): name obj.find(name).text 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) boxes.append({ name: name, bbox: [xmin, ymin, xmax, ymax] }) return img_width, img_height, boxes # 使用示例 w, h, boxes parse_voc_xml(annotations/airplane-003-0595.xml) print(f图像尺寸: {w}x{h}, 目标数: {len(boxes)}) for box in boxes: print(box)这里我保留了 name 字段是为了打印出来确认类别值到底是什么。摘要里说数据集是单类别飞机但实际标注文件里 name 可能写的是 airplane也可能写的是 aircraft甚至可能混入其他标签。我在真实项目中遇到过 XML 的 name 字段写着 play 这种拼写错误的情况所以打印出来看一眼成本最低。坐标用 float 读取而不是 int是因为后面做归一化时浮点精度不丢失。2.3 划分训练集、验证集、测试集按图片划分而不是按标注划分目标检测训练前必须划分数据。很多初学者直接在全局文件列表里随机 shuffle 后按比例切分这在单场景数据集上问题不大但如果同一架飞机出现在多张连续拍摄的帧里纯随机划分会造成数据泄漏。稳妥做法是先按文件名前缀做去重再划分最后把图片和 XML 同步移动。import os import random import shutil from pathlib import Path random.seed(42) image_dir Path(images) xml_dir Path(annotations) train_dir Path(dataset/train) val_dir Path(dataset/val) test_dir Path(dataset/test) for d in [train_dir, val_dir, test_dir]: (d / images).mkdir(parentsTrue, exist_okTrue) (d / labels).mkdir(parentsTrue, exist_okTrue) images sorted(image_dir.glob(*.jpg)) random.shuffle(images) train_ratio 0.8 val_ratio 0.1 n_train int(len(images) * train_ratio) n_val int(len(images) * val_ratio) train_files images[:n_train] val_files images[n_train:n_train n_val] test_files images[n_train n_val:] for split, file_list in [(train, train_files), (val, val_files), (test, test_files)]: for img_path in file_list: xml_path xml_dir / (img_path.stem .xml) dest Path(dataset) / split shutil.copy(img_path, dest / images / img_path.name) shutil.copy(xml_path, dest / labels / xml_path.name) print(f训练集: {len(train_files)}, 验证集: {len(val_files)}, 测试集: {len(test_files)})这段脚本用 random.seed(42) 固定随机种子保证每次运行结果一致。8:1:1 的比例是目标检测里比较常见的经验值数据量小的时候可以把测试集比例降到 0.05把更多样本留给训练。我这里用 copy 而不是 move是因为原始数据还要留着做标注修正等确认转换脚本没问题再改成 move 省磁盘空间。3. 把 XML 转成 YOLO 训练格式转换脚本、参数设置与训练配置3.1 为什么不用 XML 直接训练要转成 YOLO 的 txt 格式YOLO 系列训练时读取的标签格式是纯文本每行一个目标格式为 class x_center y_center width height其中中心点和宽高都是相对图像宽度和高度的归一化值0 到 1 之间。XML 本身也是有效标注格式但训练框架的 DataLoader 设计上就没有针对 XML 做优化每次迭代都要解析 XML 树1000 张图训一轮就要解析 1000 次效率很低。更重要的是YOLO 在推理阶段只认 txt 标签验证集评估时要加载的是 txt。所以不管用 YOLOv5、YOLOv8 还是其他 YOLO 变体第一步都是把 XML 转成同名 txt。转换的核心要点是归一化公式x_center (xmin xmax) / 2 / img_widthy_center (ymin ymax) / 2 / img_heightwidth (xmax - xmin) / img_widthheight (ymax - ymin) / img_height。这个公式不难但很多人在写的时候把 xmax 和 width 搞混导致训练时边框偏移。3.2 转换脚本一次跑完输出可直接用于 YOLOv8 的标签我一般会把转换、划分、生成 dataset.yaml 合并到一个脚本里一次运行就得到完整的 YOLO 工程目录。下面是核心转换部分import cv2 import os import glob import xml.etree.ElementTree as ET CLASS_MAPPING {airplane: 0, plane: 0, aircraft: 0} def convert_xml_to_yolo(xml_path, output_dir, img_dir): tree ET.parse(xml_path) root tree.getroot() img_name os.path.splitext(os.path.basename(xml_path))[0] .jpg img_path os.path.join(img_dir, img_name) img cv2.imread(img_path) if img is None: print(f图片读取失败: {img_path}) return False h, w img.shape[:2] label_path os.path.join(output_dir, os.path.splitext(os.path.basename(xml_path))[0] .txt) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASS_MAPPING: print(f跳过未映射类别: {name} 文件: {xml_path}) continue class_id CLASS_MAPPING[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) xmin max(0, min(xmin, w - 1)) ymin max(0, min(ymin, h - 1)) xmax max(0, min(xmax, w)) ymax max(0, min(ymax, h)) if xmax xmin or ymax ymin: print(f无效框已跳过: {xml_path}) continue x_center (xmin xmax) / 2 / w y_center (ymin ymax) / 2 / h box_w (xmax - xmin) / w box_h (ymax - ymin) / h lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) with open(label_path, w) as f: f.write(\n.join(lines)) return True xml_files glob.glob(annotations/*.xml) os.makedirs(yolo_labels, exist_okTrue) for xml_file in xml_files: convert_xml_to_yolo(xml_file, yolo_labels, images)这段脚本里我用 CLASS_MAPPING 把不同写法的类别名统一映射到 0这样即使 XML 里混入 plane 或 aircraft 也能正确转换。坐标裁剪部分很关键正常标注不会越界但数据标注工具偶尔会产生 xmax1024 或者 xmin1 这类边界值如果不裁剪直接归一化可能出现中心点超出 0~1 范围。写 txt 时用:.6f保留 6 位小数这是 YOLO 官方标签的默认精度足够表达亚像素级的位置信息。3.3 dataset.yaml 与训练超参数换模型、改分辨率、调 batchYOLOv8 用 yaml 文件指定数据集路径和类别信息。单类别数据集配置很简单path: ./dataset train: images/train val: images/val test: images/test nc: 1 names: [airplane]这里的 path 是相对项目根目录的路径train 和 val 指向的是图片目录而不是标签目录。YOLO 会从图片路径自动推导标签路径如果图片在images/train标签就在labels/train。这一点踩坑的人很多——把标签路径写进 yaml 后报错找不到文件。训练命令和关键参数yolo detect train \ datadataset.yaml \ modelyolov8n.pt \ imgsz1024 \ epochs100 \ batch16 \ workers4 \ device0参数选择逻辑imgsz 我建议直接设成 1024和原始图像分辨率一致。卫星图里的飞机通常只有 20×20 到 60×60 像素的规模如果用 640 输入相当于把目标压缩到十几像素小目标检测头也很难救回来。模型权重选择 yolov8n.pt 这类 nano 版本是因为显存有限时可以跑更大的 batch如果你有 24G 显存可以换 yolov8m.pt精度会更好。epochs100 对 1000 张单类数据来说够了再多会过拟合。batch16 在 1024 分辨率下大约占用 12~16G 显存显存不够时先降 batch 而不是降分辨率分辨率是这张数据集的命门。4. 避坑记录卫星图飞机检测最常踩的四个坑4.1 小目标漏检AP 一直上不去这是一个很典型的物理现象模型在 640×640 输入下训练loss 曲线降得很快但验证集的 AP50 卡在 0.5 上不去。排查后发现飞机在图像里占比太小一个 40×40 的飞机下采样 32 倍后只剩 1~2 个特征点检测头基本感知不到。我试过几种解法最直接的是把 imgsz 提到 1024。YOLO 默认的检测头有 P3、P4、P5 三个尺度对应 8 倍、16 倍、32 倍下采样1024 输入能让 32 倍下采样后的特征图保留 32×32 的分辨率小飞机的特征不再消失。如果你的显存撑不住 1024 输入可以启用 YOLOv8 的 P2 检测头或者用 SAHI 切片推理但显存允许的情况下优先提分辨率这个改动成本最低。4.2 XML 坐标越界训练 loss 变成 nan有位同学跑这个数据时loss 在前 20 个 epoch 正常第 30 个 epoch 直接变 nan。查了半天不是学习率问题而是标注文件里出现了 xmax0 的异常框归一化后变成负数导致损失函数里 log 运算出错。解决方式就是转换脚本里那两行坐标裁剪先把坐标 clip 到图像尺寸范围内再做归一化归一化之后再 clip 一次到 [0, 1]。不要嫌这两步麻烦真实标注数据里边界值问题比你想的常见。另外我建议在转换后写一段校验代码扫描所有 txt 标签检查是否存在小于 0 或大于 1 的数值出错就打印文件名这样避免训练中途才炸出来。4.3 类别名和编号没对齐评估结果一塌糊涂单类别数据也会翻车。XML 里类别名可能不统一有的写 airplane 有的写 plane如果你转换脚本里只判断 name airplane那部分 plane 目标会被丢掉。更隐蔽的是如果你后续增加了类别比如把直升机也标为 class 1但忘了改 CLASS_MAPPING训练和验证的类别编号就会错位表现就是 mAP 曲线诡异波动。我的习惯是转换前先跑一段脚本统计所有 XML 里的 name 集合打印set(obj.find(name).text for obj in root.findall(object) for root in ...)看到实际值再写映射表。这个数据集我处理时只发现 airplane 一种但稳妥起见 CLASS_MAPPING 里应该把常见的近义写法都映射到 0。4.4 随机划分造成同帧数据泄漏训练集和验证集都是从同一个数据源随机划分卫星视频序列里往往连续几帧都有同一架飞机飞机的位置和角度略有变化。如果这些帧同时出现在训练集和验证集模型相当于提前见过答案验证集 mAP 虚高部署到真实场景后精度断崖下跌。修正方法是划分前按文件名的前缀分组。这组数据的文件名是 airplane-003-XXXX.jpg中间的 003 是片段编号XXXXX 是帧号。正确做法是以 airplane-003 为组单位划分保证同一组的图片全进 train或者全进 val。如果你拿到的是其他命名规则的数据就找文件名里代表视频序列或拍摄批次的那段字符串来分组。5. 单类别模型优化小目标增强策略与训练结果验证5.1 针对卫星图的数据增强选择旋转、HSV 与保留小目标卫星图像没有固定的“正方向”飞机可以朝任意角度停放所以数据增强里随机旋转对模型帮助很大让模型不依赖飞机的朝向。YOLOv8 默认增强可能没有开启大角度旋转你需要显式配置yolo detect train \ datadataset.yaml \ modelyolov8n.pt \ imgsz1024 \ epochs100 \ batch16 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ degrees180 \ fliplr0.5 \ flipud0.5参数说明degrees180 允许任意角度旋转符合卫星图飞机朝向随机的现实hsv_h、hsv_s、hsv_v 是 HSV 通道色增强幅度遥感图往往偏灰偏暗适度增强色彩能提升模型对光照差异的鲁棒性fliplr 和 flipud 是水平垂直翻转概率各开 0.5 即可。注意 degrees 开大后模型训练变慢因为马赛克增强里旋转操作比较耗时对 1000 张图的数据量影响仍在可接受范围。还有一个小技巧Mosaic 增强默认开启但卫星图上的小目标在 Mosaic 拼接后可能变得更小。如果你的数据内存够大可以适当降低 Mosaic 概率比如设置mosaic0.5保住更多原始尺度的小目标样本参与训练。5.2 训练后怎么验证mAP 之外还要看 PR 曲线和误检形态训练结束后不要只看训练日志打印的 mAP50。对一个单类目标检测任务我通常跑一遍验证集预测然后分析三类错误漏检、虚检、定位偏差。yolo detect val \ modelruns/detect/train/weights/best.pt \ datadataset.yaml \ imgsz1024 \ conf0.25 \ iou0.5重点关注 val 输出里的 mAP50 和 mAP50-95 差距。如果 mAP50 有 0.85 但 mAP50-95 只有 0.5说明模型框的位置不够准飞机这种形状不规则的刚性目标定位偏差会显著拉低两个指标这时可以回看损失函数里的 box_loss 是否还有下降空间或者尝试更大模型。另外把一张包含密集停机坪的测试图放大看预测结果通常能发现两类问题小飞机被漏掉或者把建筑物顶部错认为飞机。看到哪种错误就能回头调整增强策略或者加入背景负样本微调。我自己跑这批数据时第一次训练也是直接拿默认 640 分辨率开跑结果 AP50 卡在 0.4 左右反复震荡完全没有发挥出 1024×1024 原始分辨率的优势。后来把 imgsz 提到 1024 并做完类别名核查AP50 直接跳到 0.82轻量级模型才有实际可用的表现。从那以后我每次拿到遥感目标检测数据集都会强制先跑一遍“文件完整性检查、类别名统计、坐标边界校验”这三板斧确认数据质量没问题再开始训练省下来的调试时间远比检查脚本花掉的时间多。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

从Vibecoding到持久化Web AI编码工作区:会话恢复与项目隔离实战 2026/9/28 17:24:03

从Vibecoding到持久化Web AI编码工作区:会话恢复与项目隔离实战

先聊聊“Vibecoding”这件事。最近这个词在开发者圈子里热度非常高,说白了就是“跟着感觉写代码”:你把需求往 Claude Code 或 Codex 里一丢,AI 自动生成大段代码,你负责读、改、验收,全程像开着车听音乐一样顺畅。但真…

阅读更多 →
工业烟雾检测实战:21578张带标签图像YOLO训练全流程与避坑指南 2026/9/28 17:24:03

工业烟雾检测实战:21578张带标签图像YOLO训练全流程与避坑指南

简介:本资源为面向YOLO目标检测学习者的烟雾识别数据集,适用于安防监控、工业消防、森林防火等场景下的烟雾检测模型训练与算法验证,适合具备一定深度学习基础、正在做目标检测课程设计或科研实验的开发者使用。压缩包共收录2000个文件&#…

阅读更多 →
CSV时序数据分类实战:从数据预处理到LSTM模型 2026/9/28 17:24:03

CSV时序数据分类实战:从数据预处理到LSTM模型

简介:面向CSV时序数据分类任务,该资源提供基于双向LSTM(Bidirectional LSTM)的完整训练与预测实现,适合已有Python/深度学习基础、需要快速搭建序列分类模型的学习者、课程设计或论文基线研究者。压缩包共30个文件&…

阅读更多 →
钢琴键工艺全屋定制实拍 成都本地工厂安装团队 环保板材高柜门 2026/9/28 17:24:03

钢琴键工艺全屋定制实拍 成都本地工厂安装团队 环保板材高柜门

随着国内家装消费观念升级,越来越多业主不再只满足于标准化成品家具,更追求贴合户型、适配生活习惯,同时兼具设计感与环保性的定制家居。全屋定制行业近年来保持稳定增长,消费者对品牌透明度、工艺细节、环保等级的要求越来越高&a…

阅读更多 →
持久化Web AI编码工作区:用Docker+ttyd+tmux打造随时接续的Claude Code/Codex环境 2026/9/28 17:24:03

持久化Web AI编码工作区:用Docker+ttyd+tmux打造随时接续的Claude Code/Codex环境

如果你最近在折腾 Claude Code 或者 Codex,应该对 vibecoding 这个词不陌生。简单说,就是把自己从"每一行代码都要亲自想清楚"的状态里解放出来,把意图丢给 AI,让它快速生成初稿,你再负责验收、纠偏和收尾。…

阅读更多 →
DW_apb_uart初始化与调试实战:从寄存器配置到稳定收发 2026/9/28 17:23:56

DW_apb_uart初始化与调试实战:从寄存器配置到稳定收发

1. 从一颗“哑巴”串口说起:DW_apb_uart到底卡在哪如果你手上正在调一颗SoC,串口打印死活出不来,或者能出字符但一收长包就丢数据,那你大概率正在跟DW_apb_uart打交道。这颗IP在国产SoC、FPGA软核、工业控制板卡里出现频率极高&am…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉