从Labelme到DOTA:遥感图像旋转框标注与mmdetection实战全流程

在遥感图像分析领域,旋转目标检测(OBB Detection)正逐渐成为处理航拍、卫星影像中密集排列和任意方向物体的关键技术。不同于传统水平框检测,旋转框能更精确地框定飞机、车辆、建筑物等目标,减少背景干扰和重叠区域的误判。本文将完整呈现从Labelme多边形标注到DOTA格式转换,再到mmdetection框架下S2ANet模型训练的全套解决方案。

1. 旋转目标检测基础与工具选型

旋转框检测的核心在于用五参数表示法(中心点坐标x,y、宽高w,h、旋转角度θ)或八参数表示法(四个顶点坐标)来描述倾斜物体。DOTA数据集作为遥感领域标杆,采用八参数OBB(Oriented Bounding Box)格式:

x1 y1 x2 y2 x3 y3 x4 y4 category difficult

工具链对比表

工具 标注类型 输出格式 适用场景 转换复杂度
Labelme 多边形 JSON 通用图像 ★★☆
CVAT 旋转矩形 XML/COCO 工业检测 ★☆☆
DOTA官方工具 OBB TXT 遥感图像 -
RectLabel 旋转框 CSV/PascalVOC macOS环境 ★★☆

对于从Labelme迁移到DOTA格式的项目,需要特别注意:

  • 顶点顺序必须统一为顺时针
  • 坐标归一化处理(原始像素值 vs 相对值)
  • 困难样本(difficult)的判定标准

提示:Labelme的JSON文件中,多边形点集保存在 shapes[i]['points'] 中,而DOTA格式要求四个顶点按特定顺序排列。

2. Labelme到DOTA的格式转换实战

转换过程本质是多边形凸包计算与顶点排序问题。以下是关键代码片段:

import json
import numpy as np
from scipy.spatial import ConvexHull

def labelme_to_dota(labelme_path, dota_path):
    with open(labelme_path) as f:
        data = json.load(f)
    
    with open(dota_path, 'w') as f_out:
        for shape in data['shapes']:
            points = np.array(shape['points'])
            hull = ConvexHull(points)  # 计算凸包确保四边形
            
            # 按顺时针排序顶点(DOTA要求)
            sorted_points = sort_clockwise(points[hull.vertices])
            
            line = ' '.join([f'{x:.1f} {y:.1f}' 
                           for x,y in sorted_points[:4]])  # 取前四个顶点
            line += f' {shape["label"]} 0\n'  # 默认difficult=0
            f_out.write(line)

常见问题及解决方案:

  1. 顶点数量不匹配

    • 多边形点过多时:采用凸包简化
    • 点过少时:插值生成四边形
  2. 方向判定错误

    def sort_clockwise(points):
        center = np.mean(points, axis=0)
        angles = np.arctan2(points[:,1]-center[1], points[:,0]-center[0])
        return points[np.argsort(-angles)]  # 顺时针排序
    
  3. 坐标系统差异

    • Labelme使用左上角原点,DOTA通常用左下角
    • 需进行y轴镜像变换: y_new = image_height - y_old

3. DOTA数据预处理与增强策略

针对大尺寸遥感图像(如4096×4096),必须进行智能裁剪:

裁剪参数对比实验

重叠比例 裁剪数量 mAP提升 训练时间
0% 16 - 1x
25% 36 +3.2% 1.8x
50% 100 +5.7% 4.2x
75% 196 +6.1% 7.5x

推荐采用滑动窗口裁剪代码:

python DOTA_devkit/ImgSplit.py \
    --base_json configs/split_config.json \
    --srcpath origin_images \
    --dstpath cropped_images

其中 split_config.json 示例:

{
    "image_ext": ".png",
    "gap": 200,
    "subsize": 1024,
    "thresh": 0.7,
    "save_ext": ".jpg"
}

多尺度训练策略:

  1. 原始尺寸(1024×1024)
  2. 下采样50%(512×512)
  3. 上采样150%(1536×1536)

注意:裁剪后的标注文件需要同步处理,使用DOTA_devkit中的 SplitOnlyImage_multi_process.py 可自动完成

4. mmdetection旋转检测模型配置详解

以S2ANet为例,关键配置项修改:

# configs/s2anet/s2anet_r50_fpn_1x_dota.py

model = dict(
    bbox_head=dict(
        num_classes=15,  # 对应DOTA的15个类别
        anchor_generator=dict(
            strides=[8, 16, 32, 64, 128],
            ratios=[1.0],
            scales=[1, 2, 4]),
        loss_cls=dict(
            type='FocalLoss',
            use_sigmoid=True,
            gamma=2.0,
            alpha=0.25,
            loss_weight=1.0),
        loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))
)

data = dict(
    samples_per_gpu=4,  # 根据GPU显存调整
    workers_per_gpu=2,
    train=dict(
        type='DOTADataset',
        ann_file='data/dota/train/labelTxt/',
        img_prefix='data/dota/train/images/',
        pipeline=train_pipeline),
    val=dict(
        type='DOTADataset',
        ann_file='data/dota/val/labelTxt/',
        img_prefix='data/dota/val/images/',
        pipeline=test_pipeline)
)

训练启动命令:

CUDA_VISIBLE_DEVICES=0,1 tools/dist_train.sh \
    configs/s2anet/s2anet_r50_fpn_1x_dota.py \
    2 --validate

性能优化技巧

  • 使用 RotatedAugmentation 增强:
    train_pipeline = [
        dict(type='RotatedRandomFlip', flip_ratio=0.5),
        dict(type='RotatedRandomRotate', angle_range=180),
        dict(type='RotatedResize', img_scale=(1024, 1024))
    ]
    
  • 开启FP16训练:
    optimizer_config = dict(type="Fp16OptimizerHook", loss_scale=512.)
    
  • 采用 CheckpointHook 定期保存:
    checkpoint_config = dict(interval=3)
    

5. 模型部署与生产化实践

Docker镜像构建关键点:

FROM nvidia/cuda:11.1-base

# 安装依赖
RUN apt-get update && apt-get install -y \
    libgl1-mesa-glx \
    libsm6 \
    libxext6

# 固定版本防止兼容问题
RUN pip install torch==1.8.1+cu111 torchvision==0.9.1+cu111 -f https://download.pytorch.org/whl/torch_stable.html
RUN pip install mmcv-full==1.3.9 -f https://download.openmmlab.com/mmcv/dist/cu111/torch1.8.0/index.html

# 复制预编译的mmdetection
COPY mmdetection /app/mmdetection
ENV PYTHONPATH=/app/mmdetection:$PYTHONPATH

# 示例推理命令
CMD ["python", "tools/test.py", "config.py", "checkpoint.pth"]

性能监控方案:

  1. 使用 nvtop 实时查看GPU利用率
  2. 通过 mmdet.utils.logger 记录训练指标
  3. 添加Prometheus监控端点:
from prometheus_client import start_http_server, Gauge

train_loss = Gauge('training_loss', 'Current training loss')
val_mAP = Gauge('validation_map', 'Current validation mAP')

def log_metrics(runner):
    train_loss.set(runner.log_buffer.output['loss'])
    val_mAP.set(runner.log_buffer.output['mAP'])
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐