在遥感图像分析和地理信息系统(GIS)中,将图像数据与其地理位置关联起来是一项关键技术。本教程将展示如何使用Python将DOTA数据集中的标注坐标转换为地理坐标。
 

数据准备

dota数据格式的标注文件以及标注文件所对应的jpg格式的图像和xml格式的地理信息文件。

1. dota格式的数据标注

标注文件名称示例:large_image_11_21_2010.txt,标注文件内容示例如下:

9200.6 9013.3 9211.4 9017.7 9191.4 9066.7 9180.6 9062.3 dam 0
4665.6 10331.5 4671.7 10325.7 4704.1 10360.3 4698.0 10366.0 dam 0
9904.5 11347.8 9916.5 11348.2 9915.5 11380.2 9903.5 11379.8 dam 0
11025.0 373.9 11040.0 381.1 10988.0 489.1 10973.0 481.9 dam 0
9431.8 10677.2 9447.3 10677.3 9447.0 10728.0 9431.5 10727.9 dam 0

2. jpg格式的图像

图像文件名称示例:large_image_11_21_2010.jpg
 

3. xml格式的地理信息

地理信息文件名称示例:large_image_11_21_2010.jpg.aux.xml,地理信息文件内容示例如下:

<PAMDataset>
    <SRS dataAxisToSRSAxisMapping="2,1">GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]</SRS>
    <GeoTransform>  28.14697265625, 2.1457672119140625e-05, 0, -25.5322265625, 0, -2.1457672119140625e-05</GeoTransform>
        </PAMDataset>

代码输出

dota的四个点的像素坐标转化为地理坐标

28.344396114349365 -25.72563099861145 28.344627857208252 -25.725725412368774 28.34419870376587 -25.726776838302612 28.343966960906982 -25.726682424545288 dam 0
28.247085571289062 -25.7539165019989 28.24721646308899 -25.75379204750061 28.24791169166565 -25.754534482955933 28.247780799865723 -25.75465679168701 dam 0
28.35950016975403 -25.775723934173584 28.359757661819458 -25.77573251724243 28.35973620414734 -25.776419162750244 28.35947871208191 -25.776410579681396 dam 0
28.383543491363525 -25.540249586105347 28.383865356445312 -25.540404081344604 28.382749557495117 -25.54272150993347 28.38242769241333 -25.542567014694214 dam 0
28.34935712814331 -25.76133441925049 28.349689722061157 -25.7613365650177 28.34968328475952 -25.76242446899414 28.349350690841675 -25.76242232322693 dam 0

代码

import os
import cv2
import numpy as np
from xml.etree import ElementTree

def draw_boxes_on_image(image_path, boxes, color=(0, 255, 0), thickness=4):
    """在图像上绘制旋转矩形边框。
    
    Args:
        image_path (str): 图像文件路径。
        boxes (list): 边框列表,每个边框由四个点坐标组成。
        color (tuple): 绘制边框的颜色,默认为绿色。
        thickness (int): 边框的厚度。
    """
    # 从文件中读取图像并解码
    image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), cv2.IMREAD_COLOR)
    # 遍历所有边框并在图像上绘制
    for box in boxes:
        points = np.array(box, np.int32)
        points = points.reshape((-1, 1, 2))
        cv2.polylines(image, [points], True, color, thickness)
        print("Drawing box:", box)

    # 指定输出文件夹和文件名
    output_folder = os.path.dirname(image_path) 
    output_file_name = os.path.splitext(os.path.basename(image_path))[0] + '_boxed.jpg'
    output_path = os.path.join(output_folder, output_file_name)
    print(output_path)
    # 将绘制好的图像保存到文件
    cv2.imwrite(output_path, image)

def parse_xml_for_geotransform(xml_path):
    """从XML文件解析地理变换参数。
    
    Args:
        xml_path (str): XML文件的路径。
        
    Returns:
        list: 包含地理变换参数的列表。
    """
    tree = ElementTree.parse(xml_path)
    root = tree.getroot()
    geotransform = []
    # 解析XML以获取地理变换参数
    for element in root.findall('.//GeoTransform'):
        geotransform = list(map(float, element.text.split(',')))
    return geotransform

def pixel_to_geo(geotransform, x_pixel, y_pixel):
    """将像素坐标转换为地理坐标。
    
    Args:
        geotransform (list): 地理变换参数。
        x_pixel (float): x方向的像素坐标。
        y_pixel (float): y方向的像素坐标。
    
    Returns:
        tuple: 包含经度和纬度的元组。
    """
    lon = geotransform[0] + x_pixel * geotransform[1] + y_pixel * geotransform[2]
    lat = geotransform[3] + x_pixel * geotransform[4] + y_pixel * geotransform[5]
    return lon, lat

def img_pre_processing(image_path, xml_path):
    """图像预处理和解析XML以获取地理变换参数。
    
    Args:
        image_path (str): 图像文件的路径。
        xml_path (str): XML文件的路径。
        
    Returns:
        list: 地理变换参数。
    """
    # 从文件读取并解码图像
    image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), cv2.IMREAD_COLOR)
    if image is None:
        raise FileNotFoundError(f"Image {image_path} not found.")
    # 解析XML文件以获取地理变换参数
    geotransform = parse_xml_for_geotransform(xml_path)
    return geotransform

def process_dotas(image_path, xml_path, type_folder, output_folder):
    """处理DOTA标注并转换为地理坐标标注。
    
    Args:
        image_path (str): 图像文件路径。
        xml_path (str): XML文件路径。
        type_folder (str): 包含DOTA标注的文件夹路径。
        output_folder (str): 输出地理坐标标注的文件夹路径。
    """
    geotransform_input = img_pre_processing(image_path, xml_path)
    boxes = []
    image_path_basename = os.path.splitext(os.path.basename(image_path))[0]
    type_txt = image_path_basename + '.txt'
    output_geo_txt_path = os.path.join(output_folder, image_path_basename + '_geo.txt')

    # 读取DOTA标注文件并转换坐标
    with open(os.path.join(type_folder, type_txt), 'r', encoding="utf-8") as t, open(output_geo_txt_path, 'w') as f:
        for line in t:
            parts = line.split()
            dota_nodes = parts[:8]
            dota_type = parts[8]
            geo_coords = []

            dota_coords = [(float(dota_nodes[i]), float(dota_nodes[i + 1])) for i in range(0, len(dota_nodes), 2)]
            boxes.append(dota_coords)
            for i in range(0, len(dota_nodes), 2):
                x_pixel_input = float(dota_nodes[i])
                y_pixel_input = float(dota_nodes[i + 1])
                lon, lat = pixel_to_geo(geotransform_input, x_pixel_input, y_pixel_input)
                geo_coords.append((lon, lat))

            flat_coords = [coord for point in geo_coords for coord in point]
            difficulty = 0
            dota_line = ' '.join(map(str, flat_coords)) + f" {dota_type} {difficulty}\n"
            print(dota_line)
            f.write(dota_line)
            draw_boxes_on_image(image_path, boxes)



if __name__ == '__main__':
    jpg_xml_folder = r'D:\修复数据\研究生\project\代码\train_v4\data_v2\test\images' 
    # 包含jpg图像和xml类型的地理信息文件的文件夹
    output_geo_folder = r'D:\修复数据\研究生\project\代码\train_v4\data_v2\test\geographic' 
    # 输出的地理信息文件的文件夹
    type_folder = r'D:\修复数据\研究生\project\代码\train_v4\data_v2\test\labels'
    # dota格式的标注好的数据文件夹


    if not os.path.exists(output_geo_folder):
        os.makedirs(output_geo_folder)
    for image_filename in os.listdir(jpg_xml_folder):
        if image_filename.endswith('.jpg'):
            base_name = os.path.splitext(image_filename)[0]
            image_path = os.path.join(jpg_xml_folder, image_filename)
            xml_path = os.path.join(jpg_xml_folder, base_name + '.jpg.aux.xml')
            print(image_filename)
            process_dotas(image_path, xml_path, type_folder, output_geo_folder)



Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐