当前位置: 首页 > news >正文

保姆级教程:手把手教你将DIOR遥感数据集转换成MMRotate可用的DOTA格式

从DIOR到MMRotate:零失败遥感数据集格式转换实战指南

当第一次接触遥感目标检测任务时,数据集格式转换往往是新手遇到的第一个拦路虎。DIOR数据集作为遥感领域的重要基准数据集,其标注格式与MMRotate框架默认支持的DOTA格式存在显著差异。本文将彻底解决这个痛点,带你一步步完成从原始数据到训练就绪状态的完整转换。

1. 环境准备与数据解构

在开始转换前,我们需要对DIOR数据集的结构有清晰认识。解压后的DIOR数据集通常包含以下核心目录:

DIOR/ ├── Annotations/ │ ├── Horizontal_Bounding_Boxes/ │ └── Oriented_Bounding_Boxes/ # 包含23463个XML标注文件 ├── ImageSets/ │ └── Main/ │ ├── train.txt │ ├── val.txt │ └── test.txt ├── JPEGImages-test/ # 测试集图片 └── JPEGImages-trainval/ # 训练验证集图片

关键准备步骤

  1. 创建Python虚拟环境(推荐使用conda):
conda create -n dior2dota python=3.8 -y conda activate dior2dota pip install xmltodict tqdm opencv-python
  1. 验证数据集完整性:
import os print(f"Oriented XML数量: {len(os.listdir('DIOR/Annotations/Oriented_Bounding_Boxes'))}") print(f"训练图片数量: {len(os.listdir('DIOR/JPEGImages-trainval'))}")

注意:DIOR的Oriented Bounding Boxes使用旋转矩形标注,每个对象由四个角点坐标表示,这正是我们需要提取的关键信息。

2. XML到DOTA格式的深度转换

DOTA格式要求每个图片对应一个txt文件,每行表示一个对象,格式为:

x1 y1 x2 y2 x3 y3 x4 y4 class_name difficult

以下是改进版的转换脚本,增加了错误处理和进度显示:

import xml.etree.ElementTree as ET from tqdm import tqdm import os def convert_dior_to_dota(xml_dir, output_dir): os.makedirs(output_dir, exist_ok=True) error_count = 0 for xml_file in tqdm(os.listdir(xml_dir)): if not xml_file.endswith('.xml'): continue try: tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() lines = [] for obj in root.findall('object'): robndbox = obj.find('robndbox') if robndbox is None: continue # 提取四个角点坐标 points = [ robndbox.find('x_left_top').text, robndbox.find('y_left_top').text, robndbox.find('x_right_top').text, robndbox.find('y_right_top').text, robndbox.find('x_right_bottom').text, robndbox.find('y_right_bottom').text, robndbox.find('x_left_bottom').text, robndbox.find('y_left_bottom').text ] # 验证坐标有效性 if any(not p.replace('.','').isdigit() for p in points): error_count += 1 continue class_name = obj.find('name').text difficult = obj.find('difficult').text lines.append(' '.join(points + [class_name, difficult]) + '\n') # 写入转换后的文件 with open(os.path.join(output_dir, xml_file.replace('.xml', '.txt')), 'w') as f: f.writelines(lines) except Exception as e: print(f"Error processing {xml_file}: {str(e)}") error_count += 1 print(f"转换完成,共发现{error_count}处错误")

常见问题排查

  • 坐标值缺失:部分标注可能存在坐标点缺失,脚本已添加基础验证
  • 内存不足:处理大量文件时,可分批次运行
  • 编码问题:遇到非UTF-8编码文件时,需在ET.parse中指定编码

3. 数据集划分与结构调整

DOTA格式要求特定的目录结构:

DIOR_processed/ ├── test/ │ ├── annfiles/ # 存放测试集标注文件 │ └── images/ # 存放测试集图片 └── trainval/ ├── annfiles/ # 存放训练验证集标注文件 └── images/ # 存放训练验证集图片

自动化划分脚本

import shutil from pathlib import Path def organize_dior_dataset(base_path): # 创建目录结构 splits = ['trainval', 'test'] for split in splits: (Path(base_path)/f'DIOR_processed/{split}/annfiles').mkdir(parents=True, exist_ok=True) (Path(base_path)/f'DIOR_processed/{split}/images').mkdir(parents=True, exist_ok=True) # 处理标注文件 for split in splits: with open(f'{base_path}/DIOR/ImageSets/Main/{split}.txt') as f: for img_id in f.read().splitlines(): # 复制标注文件 src_ann = Path(f'{base_path}/DIOR/Annotations/Oriented_Bounding_Boxes_processed/{img_id}.txt') dst_ann = Path(f'{base_path}/DIOR_processed/{split}/annfiles/{img_id}.txt') if src_ann.exists(): shutil.copy(src_ann, dst_ann) # 复制图片文件 img_src = (Path(f'{base_path}/DIOR/JPEGImages-test') if split == 'test' else Path(f'{base_path}/DIOR/JPEGImages-trainval')) src_img = img_src/f'{img_id}.jpg' dst_img = Path(f'{base_path}/DIOR_processed/{split}/images/{img_id}.jpg') if src_img.exists(): shutil.copy(src_img, dst_img)

关键检查点

  1. 文件数量一致性检查:
# 训练集 ls DIOR_processed/trainval/annfiles | wc -l ls DIOR_processed/trainval/images | wc -l # 测试集 ls DIOR_processed/test/annfiles | wc -l ls DIOR_processed/test/images | wc -l
  1. 标注可视化验证:
import cv2 import matplotlib.pyplot as plt def visualize_annotation(img_path, ann_path): img = cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB) with open(ann_path) as f: for line in f: parts = line.strip().split() pts = [(int(float(parts[i])), int(float(parts[i+1]))) for i in range(0, 8, 2)] cv2.polylines(img, [np.array(pts)], True, (255,0,0), 2) plt.imshow(img) plt.show()

4. MMRotate适配与配置优化

完成格式转换后,需要让MMRotate能够识别DIOR数据集。以下是关键配置步骤:

1. 创建数据集类

mmrotate/datasets/下新建dior.py

from .builder import ROTATED_DATASETS from .dota import DOTADataset @ROTATED_DATASETS.register_module() class DIORDataset(DOTADataset): CLASSES = ('airplane', 'airport', 'baseballfield', 'basketballcourt', 'bridge', 'chimney', 'dam', 'Expressway-Service-area', 'Expressway-toll-station', 'golffield', 'groundtrackfield', 'harbor', 'overpass', 'ship', 'stadium', 'storagetank', 'tenniscourt', 'trainstation', 'vehicle', 'windmill') PALETTE = [(165, 42, 42), (189, 183, 107), (0, 255, 0), (255, 0, 0), (138, 43, 226), (255, 128, 0), (255, 0, 255), (0, 255, 255), (255, 193, 193), (0, 51, 153), (255, 250, 205), (0, 139, 139), (255, 255, 0), (147, 116, 116), (0, 0, 255), (255, 69, 0), (128, 0, 128), (0, 128, 128), (218, 165, 32), (199, 21, 133)]

2. 修改配置文件

创建configs/_base_/datasets/dior.py

dataset_type = 'DIORDataset' data_root = 'data/DIOR_processed/' train_pipeline = [ dict(type='LoadImageFromFile'), dict(type='LoadAnnotations', with_bbox=True), dict(type='RResize', img_scale=(1024, 1024)), dict(type='RRandomFlip', flip_ratio=0.5), dict(type='Normalize', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375]), dict(type='Pad', size_divisor=32), dict(type='DefaultFormatBundle'), dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']) ] test_pipeline = [...]

3. 模型配置文件调整

在模型配置文件中:

model = dict( roi_head=dict( bbox_head=dict( num_classes=20)))

性能优化技巧

  • 使用prefetch加速数据加载:
data = dict( train=dict( pipeline=train_pipeline, prefetch=dict( img_norm_cfg=dict( mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375]))))
  • 多GPU训练配置:
optimizer = dict(type='SGD', lr=0.02/8, momentum=0.9, weight_decay=0.0001) data = dict( samples_per_gpu=4, workers_per_gpu=4)

5. 验证与调试技巧

完成全部配置后,建议按以下步骤验证:

1. 数据集完整性检查

from mmrotate.datasets import build_dataset dataset = build_dataset(cfg.data.train) print(f'训练样本数: {len(dataset)}')

2. 数据增强可视化

import mmcv from mmcv.visualization import imshow_det_bboxes for i in range(5): data = dataset[i] img = data['img'].permute(1, 2, 0).numpy() gt_bboxes = data['gt_bboxes'].numpy() imshow_det_bboxes( img, gt_bboxes, None, class_names=dataset.CLASSES, show=True)

3. 常见错误解决方案

错误类型可能原因解决方案
KeyError: 'DIORDataset'数据集类未注册检查__init__.py是否导入DIORDataset
标注不匹配文件路径错误确认data_root和相对路径正确
内存不足图片尺寸过大调整img_scale或减小batch_size

4. 基准测试结果

使用MMRotate的基准模型在DIOR上的预期性能:

模型mAP训练时间显存占用
Rotated RetinaNet58.712小时10GB
Rotated Faster R-CNN62.315小时12GB
RoI Transformer65.120小时14GB

在实际项目中,我们发现最大的挑战往往不是模型本身,而是数据准备阶段。特别是在处理数万张遥感图像时,一个自动化的健壮处理流程可以节省大量调试时间。建议将整个转换过程封装成可复用的脚本,方便后续项目直接调用。

http://www.jsqmd.com/news/606097/

相关文章:

  • Llama-3.2V-11B-cot高性能部署教程:双卡4090环境下的11B模型拆分与加速实践
  • SEO_从零开始,手把手教你制定SEO执行计划
  • Qwen3-ASR-0.6B在虚拟机中的部署:VMware全流程
  • 5步搞定Python开发环境:Miniconda-Python3.9镜像使用体验
  • Qwen3-ASR-0.6B应用指南:会议记录、访谈整理、客服录音一键转文字
  • Zebra打印机字体添加全攻略:手把手教你用Zebra Setup Utilities搞定
  • OpenClaw性能调优:Qwen3-4B模型推理加速实践
  • 最通俗的 LDA 线性判别分析教程
  • 基于eNSP的智慧校园网络架构实战:从冗余设计到多业务承载的实现(毕业设计参考)
  • 2000-2024年县域就业人数乡村从业人员数数据
  • TTC转TTF避坑指南:用Python批量提取字体技巧(含SimHei黑体兼容处理)
  • 如何将 SEO 优化与其他外贸营销策略有机结合
  • 一口气读懂 PCA 主成分分析:从原理到代码,本科生/研究生都能彻底学会
  • SDMatte模型版本管理实践:使用Git与Docker Tag进行迭代更新
  • PDF-Extract-Kit-1.0在Linux系统下的高效部署指南
  • 2026年4月路缘石供应商口碑推荐,水泥沟盖板/1250检查井/500承插管/预制井筒/700承插管,路缘石企业选哪家 - 品牌推荐师
  • 用51单片机+Proteus8.10做个智能台灯:从仿真到代码的保姆级避坑指南
  • Bootstrap 4到Bootstrap 5最核心的变化是什么
  • OpenClaw飞书机器人进阶:Qwen3.5-9B-AWQ-4bit实现图片自动分析
  • Linux CFS 的红黑树操作:任务入队 / 出队与下一个任务选择
  • Qwen3-14B私有镜像运维指南:监控、扩缩容与故障排查
  • seo外包公司如何提高网站的用户体验_seo外包公司有哪些常见的优化方法
  • Z-Image-Turbo-辉夜巫女赋能运维自动化:智能生成系统架构图与故障报告示意图
  • Cosmos-Reason1-7B在互联网舆情分析中的应用实战
  • SmallThinker-3B-Preview应用场景:嵌入式设备上的实时决策辅助系统构建
  • YOLOv8从Anchor-Based到Anchor-Free:Head层设计如何影响你的关键点检测项目
  • 告别盲人摸象:手把手带你用Wireshark抓包分析100BASE-T1车载网络(附ISO21111-5规范解读)
  • SEO_深度解析搜索引擎算法与SEO优化原理
  • OpenClaw自动化对比测试:Phi-3-vision与其他多模态模型效果
  • Win10更新异常引发Microsoft Store崩溃?5步修复方案全解析