
简介面向遥感目标检测任务RSOD遥感数据集已标注版本可直接用于YOLO模型训练包含飞机、油箱、运动场和立交桥四类目标所有标注均遵循PASCAL VOC规范对应xml文件与图像一一匹配省去自行标注的繁琐步骤。整理者具备多年算法工程经验数据集配套代码采用参数化编程注释清晰、便于调整契合计算机、电子信息工程、数学等专业学生在课程设计、期末大作业和毕业设计中的使用需求。资源包共一千九百一十二个文件以九百七十六张遥感图像和九百三十六份xml标注文件为主压缩包体积为三百零八点六三兆字节解压后目录结构规整可快速定位到需要的图像与标注。目前已有五百七十八人学习下载对于希望节省标注时间、专注算法验证的遥感目标检测学习者这是一套现成且规范的入门数据资源。1. 遥感检测的标注成本才是真正的门槛做过目标检测的人都知道模型结构可以抄训练流程可以照搬唯独数据集得自己攒。而遥感影像目标检测又是一个比通用目标检测更麻烦的领域飞机、油箱、运动场、立交桥这些目标尺度差异极大小目标占比高背景纹理杂乱。RSOD 数据集恰恰是这一领域里少有的、已经用 PASCAL VOC 格式标注好的公开资源1000 张 JPEG 原图对应 1000 个 XML 标注文件下载解压后直接丢进 YOLO 训练流程就能跑。对正在做课程设计、毕业设计或者想快速验证 YOLO 系列模型在遥感场景下效果的人来说省掉的不是一两天时间而是从图像采集、目标标注到格式校验的一整条流水线。这篇博客就围绕这套数据集的真实结构把 YOLO 读取 VOC 格式标注、转换、配置和训练的完整链路拆开讲一遍。2. RSOD 数据集结构与 PASCAL VOC 标注格式2.1 这个数据集里到底有什么解压后你会看到两类核心文件JPEGImages目录下的 1000 张.jpg图片以及Annotations目录下与图片同名的.xml标注文件。图片文件名形如playground_71.jpg、playground_131.jpg从文件名前缀可以推断图像采集自不同场景比如playground_*对应运动场区域但实际类别信息不看文件名前缀完全由 XML 文件里的object节点决定这一点和 ImageNet 那种目录即标签的组织方式完全不同。RSOD/ ├── JPEGImages/ │ ├── playground_71.jpg │ ├── playground_131.jpg │ └── ... ├── Annotations/ │ ├── playground_71.xml │ ├── playground_131.xml │ └── ...该数据集定义的目标类别比较特殊不是日常的 person、car而是四类明显具有遥感图像特征的物体aircraft飞机、oiltank油箱、playground运动场、overpass立交桥。其中飞机数量最多通常超过 4000 个实例油箱其次运动场和立交桥因为图像中天然只出现一次或两次实例数相对较少。这意味着训练时类别不平衡会比较明显后文会说怎么处理。2.2 XML 标注文件的字段含义打开任意一个 XML 文件结构基本长这样annotation folderJPEGImages/folder filenameplayground_71.jpg/filename source databaseRSOD/database /source size width935/width height639/height depth3/depth /size segmented0/segmented object nameplayground/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin156/xmin ymin217/ymin xmax708/xmax ymax474/ymax /bndbox /object /annotationsize子节点里的width、height十分关键YOLO 在转换标签时需要重新计算归一化坐标依赖的就是这两个值。需要注意不少网上下载的数据集会存在 XML 标注的图片尺寸与 JPEG 实际尺寸不一致的情况RSOD 整体质量较高但训练前我仍然建议写脚本对所有 XML 做一次完整性校验防止个别文件缺失object节点导致 YOLO 训练时读取到空标签。object节点中的bndbox是实际的目标框xmin、ymin、xmax、ymax是最小外接矩形的左上角和右下角坐标。坐标单位是像素且基于原始图片分辨率计算不是基于任何缩放后的尺寸。truncated和difficult两个标志位在该数据集中通常都为 0但 YOLO 的训练脚本默认会忽略difficult1的样本这一点在后续数据划分和精度评估时需要留意。2.3 为什么 YOLO 官方推荐 YOLO 格式而不直接用 XMLYOLO 系列的训练管线普遍希望标签是一个纯文本文件每行对应一个目标框格式为class_id x_center y_center width height其中坐标值全部归一化到 0~1 区间。这样做的好处是代码读取时不需要解析 XML 树结构用numpy.loadtxt()即可完成载入IO 效率高也便于 GPU 增强管线中直接在浮点坐标上做仿射变换。PASCAL VOC 的 XML 格式信息完整但冗余字段太多而且坐标是绝对像素值缩放图片时还得重新换算所以 YOLO 的官方仓库和第三方实现都会提供voc_label.py这类转换脚本。但这并不意味着 XML 格式没有价值。相反XML 看起来更接近人对目标位置的理解可读性好便于人工检查和修改因此在数据标注阶段普遍先输出成 VOC 格式送入训练前再统一转成 YOLO 格式。如果你打算用 LabelImg 补充标注漏检目标新标注文件默认输出也是 XML恰好能与 RSOD 的既有格式无缝衔接。3. 从 RSOD 的 XML 到 YOLO 训练标签的转换实现3.1 类别映射与坐标归一化的原理PASCAL VOC 格式下类别是字符串而 YOLO 要求类别是整数索引因此必须建立一张字符串到整数的映射表。以 RSOD 四类目标为例类别名称类别索引IDaircraft0oiltank1playground2overpass3映射顺序本身是随意的但一旦训练完成后续推理和数据评估都必须沿用同一张表。很多用户在训练结束后写检测脚本时才发现类别名对不上问题就出在这张映射表没有持久化保存。归一化计算的核心也很简单假设一张图片宽为W、高为HXML 中的xmin、ymin、xmax、ymax分别表示左上角和右下角的像素坐标那么归一化的中心坐标和宽高按以下公式计算x_center ((xmin xmax) / 2) / W y_center ((ymin ymax) / 2) / H box_width (xmax - xmin) / W box_height (ymax - ymin) / H这里的关键点是中心点坐标必须落在一个小的浮点值区间内而宽高也必须缩放到 0~1。YOLOv5 及后续版本内部在增强阶段会对越界框做裁剪但源标签如果已经是错误坐标训练时 mAP 会异常偏低。3.2 完整转换脚本示例下面是一个我常用的转换脚本能够遍历整个Annotations目录逐个解析 XML 并生成对应的 YOLO 格式.txt文件。这里选用xml.etree.ElementTree作为解析器不需要安装额外依赖。import xml.etree.ElementTree as ET import os from pathlib import Path CLASS_MAPPING { aircraft: 0, oiltank: 1, playground: 2, overpass: 3 } def convert_xml_to_yolo(xml_path, output_dir): 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) # 读取图片文件名用于生成同名 txt filename root.find(filename).text txt_name Path(filename).stem .txt lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in CLASS_MAPPING: print(f警告: 未知类别 {cls_name} 出现在 {xml_path}) continue cls_id CLASS_MAPPING[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 坐标归一化 x_center ((xmin xmax) / 2) / img_width y_center ((ymin ymax) / 2) / img_height box_width (xmax - xmin) / img_width box_height (ymax - ymin) / img_height # 越界裁剪 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) box_width min(box_width, 1.0) box_height min(box_height, 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_width:.6f} {box_height:.6f}) output_path os.path.join(output_dir, txt_name) with open(output_path, w) as f: f.write(\n.join(lines)) annotations_dir Annotations labels_dir labels os.makedirs(labels_dir, exist_okTrue) for xml_file in Path(annotations_dir).glob(*.xml): convert_xml_to_yolo(str(xml_file), labels_dir) print(转换完成)这段脚本做了三件事解析 XML 尺寸字段、提取所有object节点、生成与图片同名的文本标签。脚本里加了越界裁剪防止标注框因为人工标注误差导致中心点越界。参数说明xml_path是单个 XML 文件的绝对路径output_dir是存放转换后文本标签的目录。实际运行时如果打印出未知类别警告建议不要简单跳过先打开对应的 XML 文件确认类别是否确实不在四类之内如果存在第五类目标需要重新审视数据集是否被改动过。3.3 数据划分与目录组织建议标签转换完成后还需要将图片和标签按比例划分成训练集、验证集和测试集。RSOD 官方没有提供预设划分文件通常按照 8:1:1 或 7:2:1 的比例随机划分。划分时务必保证同一个图片的.jpg和.txt同时进入同一个子集不能出现训练集有图片但验证集有对应标签的情况。dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── rsod.yamlYOLOv5 和 YOLOv8 都要求图片和标签分别放在images和labels目录下且两个目录内部的train、val子集名称必须保持一致。如果图片在images/train/playground_71.jpg那么标签文件必须位于labels/train/playground_71.txt否则训练脚本无法建立图片与标签的对应关系。这一步的目录结构错误是 YOLO 训练时报错No labels found的第一大原因。3.4 用可视化脚本验证转换是否正确光看文本文件难以确认坐标转换是否出错最直接的方法是写一个小脚本把标注框画到原图上进行人工抽样检查。import cv2 import numpy as np from pathlib import Path CLASS_NAMES [aircraft, oiltank, playground, overpass] def draw_yolo_boxes(image_path, label_path): img cv2.imread(str(image_path)) h, w img.shape[:2] with open(label_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() cls_id int(parts[0]) x_center float(parts[1]) * w y_center float(parts[2]) * h box_w float(parts[3]) * w box_h float(parts[4]) * h x1 int(x_center - box_w / 2) y1 int(y_center - box_h / 2) x2 int(x_center box_w / 2) y2 int(y_center box_h / 2) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, CLASS_NAMES[cls_id], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imshow(check, img) cv2.waitKey(0) cv2.destroyAllWindows() draw_yolo_boxes(playground_71.jpg, labels/playground_71.txt)绘制时注意一个容易犯错的地方YOLO 格式中x_center和y_center是归一化后的比例值要乘以图像的原始宽高才能还原成像素坐标。画框时如果发现框的位置与目标物体位置有系统性偏移通常是归一化时除以了错误的尺寸需要回去检查 XML 的width、height字段。4. YOLO 模型配置文件与 RSOD 数据集的适配4.1 数据配置文件编写要点以 YOLOv8 为例数据配置文件的 YAML 内容大致如下path: ./RSOD train: images/train val: images/val test: images/test nc: 4 names: [aircraft, oiltank, playground, overpass]path是数据集的根路径后面train、val的路径都相对于这个根路径来写。nc是类别总数必须与names列表的长度严格一致。一个常见的坑是写过nc: 4但names列表只填了三个名字训练脚本会直接崩溃或静默出错。4.2 模型主配置文件的关键参数YOLO 系列模型的主配置参数非常多但在 RSOD 这个场景里最值得关注的是这几个参数名推荐值说明imgsz640 或 1280遥感图像分辨率高640 训练快1280 小目标召回率明显提升但显存占用翻倍batch8/16取决于显卡显存8GB 以下显存建议 416GB 可用 16epochs150~300RSOD 只有 1000 张图训练 200 轮能基本收敛继续增大轮数容易过拟合patience30~50早停耐心值验证集 mAP 不再提升时自动终止训练optimizerSGD 或 AdamWSGD 配合 cos LR 是最稳妥的组合mosaic1.0 训练后期可降为 0.5Mosaic 增强可以大幅提升模型对遮挡目标的鲁棒性但也可能让小目标学习不稳定4.3 数据集类别不平衡怎么办RSOD 数据集中飞机实例数远超其他三类运动场和立交桥的样本量很少这在训练时会导致模型整体偏向飞机类别。常见做法有几种其一是在dataset.yaml或训练脚本中启用类别权重YOLOv5 中可直接计算每个类的权重热力图YOLOv8 则可以在损失函数层面调整其二是对样本量少的类别所属图像做离线过采样也就是复制几份对应图片放入训练集其三是使用cls损失项的权重参数调整但这与模型版本相关。实际训练时更实用的做法是先不做复杂的类别加权用默认配置跑 100 轮观察验证集上每个类别的 AP。如果playground和overpass的 AP 明显低于aircraft再针对性地复制小类图片或修改损失权重比这样可解释性更强。4.4 数据增强配置对遥感目标的影响遥感目标检测里存在大量小目标例如 1000 像素宽图片中的飞机可能只有 30×30 像素。训练时如果使用默认的 mosaic 增强多个目标被拼接在一起每个目标实际分到的像素更少小目标特征会被进一步稀释。这是很多人在遥感数据集上训练 YOLO 感觉效果差的一个核心原因。推荐配置是在训练第 1 代到第 150 代启用较强的 mosaic后期关闭或降频。可以用 YOLO 训练参数中的mosaic0.5控制概率或者设置close_mosaic20让最后 20 轮关闭 mosaic 增强这样模型能够在最后阶段适应真实的单图分布。5. 训练启动、损失曲线判读与结果的工程化输出5.1 完整训练命令与日志判读将上述配置保存后执行训练命令yolo detect train datarsod.yaml modelyolov8s.pt epochs200 imgsz640 batch16 patience40 projectrsod_yolov8 nameexp1训练过程中重点关注两列指标box_loss和cls_loss。box_loss衡量预测框和真实框的位置误差cls_loss衡量类别分类误差。两者在前 50 轮内快速下降是正常现象之后进入平台期。如果box_loss持续下降但验证集 mAP 不再上升说明模型已经过拟合或增强策略需要调整。推理阶段模型按矩阵乘法计算锚框的类别预测因此 GPU 显存占用与类别数呈线性关系。RSOD 只有 4 个类别输出通道数较少推理速度会比 COCO 80 类场景快约 20%~30%。5.2 迁移学习视角下的预训练权重选择常规做法是在 ImageNet 预训练权重基础上微调而不是从随机权重开始训练。对于 RSOD 这种数据量较小的任务直接使用 YOLOv8n 的 COCO 预训练权重yolov8n.pt是最合理的起点。COCO 数据集中本身包含飞机类别模型已经具备一定的飞机目标纹理特征提取能力对油箱和运动场的通用形状特征也有基础认知因此收敛速度明显快于从零训练。5.3 验证集 mAP 的解读边界遥感数据集的验证结果需要结合图像分辨率、目标尺寸和检测难度来综合解读。RSOD 图像中的飞机目标通常较小且背景包含大量干扰特征验证 mAP 在 0.85~0.95 之间都是健康范围。若 mAP 低于 0.8优先检查标签转换脚本是否正确处理了所有 XML 文件例如是否遗漏了部分多目标文件或是否错误地将xmax与xmin的顺序颠倒。5.4 部署到端侧时的模型导出训练完成后将模型导出为 ONNX 或 TensorRT 格式以便端侧推理yolo export modelruns/detect/exp1/weights/best.pt formatonnx opset12导出 ONNX 时建议设置opset12兼容性最好。若端侧设备是 NVIDIA Jetson 系列可继续将 ONNX 转为 TensorRT engine推理速度提升两到三倍。需要注意 RSOD 的图像尺寸不一导出时应固定输入尺寸为 640×640推理时在预处理阶段对图片做 letterbox 填充避免目标框坐标在缩放后产生偏移。5.5 直接检测标注遗漏的辅助脚本如果怀疑数据集自身标注有遗漏可以利用训练好的模型做推理将置信度高于 0.5 但没有与任何真实标注框重叠的预测视为漏标候选import cv2 from ultralytics import YOLO model YOLO(runs/detect/exp1/weights/best.pt) imgs [playground_71.jpg, playground_131.jpg, playground_8.jpg] for img_path in imgs: results model.predict(img_path, conf0.5, iou0.45) boxes results[0].boxes.xyxy.cpu().numpy() classes results[0].boxes.cls.cpu().numpy() print(f{img_path} 检测到 {len(boxes)} 个目标) for box, cls in zip(boxes, classes): cls_name model.names[int(cls)] print(f 类别: {cls_name}, 置信度: {results[0].boxes.conf.cpu().numpy()[0]:.3f}, 坐标: {box.astype(int)})将打印结果与人工核对可以快速发现标注漏检的位置和数量。这个方法比直接打开 XML 查漏快得多尤其在 1000 张大图上逐张检查时效率差距巨大。本文还有配套的精品资源点击获取