wgs84影像直接转换为cgcs2000影像

最近写遥感的东西比较少,今天写一写如何将wgs84影像直接转换为cgcs2000影像,我们直接上代码就好了。

说白了这东西没什么技术含量,都是调用gdal写好的接口,以后我们再讨论一下wgs84的tif和cgcs2000的tif本质上有什么区别,这块我后面再好好研究一下。

至于wgs84影像直接转换为cgcs2000影像的代码,我直接放后面。此外,我还想再唠上一唠。

诸如遥感数据处理的东西,其实是没有技术含量的,本质上都是调用gdal的东西,你把gdal的各个接口弄明白了就掌握这个数据处理的技能,唯手熟尔。真正有难度的是算法、加速处理速度。我其实很久不做数据数据处理的东西了,因为我有足够的代码积累,我建立了一个代码库,需要哪个模块,我直接搜索。

当然,这些代码库,随着这两年的公众号的文章更新,早已被我耗尽。不然我去年不可能做到高强度的更新。

我自认为部分的技术文章还是写的有一点水平的,哈哈我这种黄婆卖瓜自卖自夸行为真不要脸。

#!/usr/bin/env python
# -*- coding: utf-8 -*- 
# @Time : 2025/10/26 21:30 
# @File : python tif_wgs84_to_cgcs2000.py 
'''
TIF影像坐标系转换工具
支持从WGS84转换到CGCS2000等坐标系
'''

from osgeo import gdal, osr
import os


def get_image_info(input_tif):
    """
    获取影像的基本信息和坐标系信息
    
    参数:
    input_tif: 输入TIF文件路径
    
    返回:
    dict: 包含影像信息的字典
    """
    dataset = gdal.Open(input_tif)
    if dataset is None:
        raise Exception(f"无法打开输入影像文件:{input_tif}")
    
    # 获取投影信息
    projection = dataset.GetProjection()
    geotransform = dataset.GetGeoTransform()
    
    # 获取影像尺寸
    cols = dataset.RasterXSize
    rows = dataset.RasterYSize
    bands = dataset.RasterCount
    
    # 获取数据类型
    datatype = dataset.GetRasterBand(1).DataType
    
    # 解析坐标系
    srs = osr.SpatialReference()
    srs.ImportFromWkt(projection)
    
    info = {
        'width': cols,
        'height': rows,
        'bands': bands,
        'datatype': datatype,
        'projection': projection,
        'geotransform': geotransform,
        'epsg': srs.GetAttrValue('AUTHORITY', 1) if srs.GetAttrValue('AUTHORITY', 1) else 'Unknown',
        'proj_name': srs.GetAttrValue('PROJCS') if srs.GetAttrValue('PROJCS') else srs.GetAttrValue('GEOGCS')
    }
    
    dataset = None
    return info


def reproject_tif_simple(input_tif, output_tif, target_epsg, resample_method='bilinear'):
    """
    使用GDAL Warp进行坐标转换(推荐方法)
    
    参数:
    input_tif: 输入TIF文件路径
    output_tif: 输出TIF文件路径  
    target_epsg: 目标坐标系的EPSG代码
    resample_method: 重采样方法 ('nearest', 'bilinear', 'cubic', 'cubicspline', 'lanczos')
    """
    # 检查输入文件
    if not os.path.exists(input_tif):
        raise Exception(f"输入文件不存在:{input_tif}")
    
    # 获取输入影像信息
    print("正在获取输入影像信息...")
    info = get_image_info(input_tif)
    print(f"输入影像信息:")
    print(f"  尺寸: {info['width']} x {info['height']}")
    print(f"  波段数: {info['bands']}")
    print(f"  当前坐标系: {info['proj_name']} (EPSG:{info['epsg']})")
    
    # 设置重采样方法映射
    resample_dict = {
        'nearest': gdal.GRA_NearestNeighbour,
        'bilinear': gdal.GRA_Bilinear,
        'cubic': gdal.GRA_Cubic,
        'cubicspline': gdal.GRA_CubicSpline,
        'lanczos': gdal.GRA_Lanczos
    }
    
    resample_alg = resample_dict.get(resample_method.lower(), gdal.GRA_Bilinear)
    
    # 创建目标坐标系
    target_srs = osr.SpatialReference()
    target_srs.ImportFromEPSG(target_epsg)
    
    print(f"目标坐标系: {target_srs.GetAttrValue('PROJCS') or target_srs.GetAttrValue('GEOGCS')} (EPSG:{target_epsg})")
    print("正在执行坐标转换...")
    
    # 使用GDAL Warp进行重投影
    warp_options = gdal.WarpOptions(
        dstSRS=f'EPSG:{target_epsg}',
        resampleAlg=resample_alg,
        format='GTiff',
        creationOptions=['COMPRESS=LZW', 'TILED=YES']  # 添加压缩和分块选项
    )
    
    # 执行重投影
    result = gdal.Warp(output_tif, input_tif, options=warp_options)
    
    if result is None:
        raise Exception("坐标转换失败!")
    
    result = None
    print(f"坐标转换完成!输出文件:{output_tif}")
    
    # 验证输出文件
    output_info = get_image_info(output_tif)
    print(f"输出影像信息:")
    print(f"  尺寸: {output_info['width']} x {output_info['height']}")
    print(f"  坐标系: {output_info['proj_name']} (EPSG:{output_info['epsg']})")


def reproject_tif_advanced(input_tif, output_tif, target_epsg, pixel_size=None, extent=None):
    """
    高级坐标转换方法,支持自定义像素大小和范围
    
    参数:
    input_tif: 输入TIF文件路径
    output_tif: 输出TIF文件路径
    target_epsg: 目标坐标系的EPSG代码
    pixel_size: 输出像素大小 (xres, yres),如果为None则自动计算
    extent: 输出范围 (minx, miny, maxx, maxy),如果为None则自动计算
    """
    # 检查输入文件
    if not os.path.exists(input_tif):
        raise Exception(f"输入文件不存在:{input_tif}")
    
    print("正在执行高级坐标转换...")
    
    # 构建warp选项
    warp_options_dict = {
        'dstSRS': f'EPSG:{target_epsg}',
        'resampleAlg': gdal.GRA_Bilinear,
        'format': 'GTiff',
        'creationOptions': ['COMPRESS=LZW', 'TILED=YES']
    }
    
    # 设置像素大小
    if pixel_size:
        warp_options_dict['xRes'] = pixel_size[0]
        warp_options_dict['yRes'] = pixel_size[1]
    
    # 设置输出范围
    if extent:
        warp_options_dict['outputBounds'] = extent
    
    warp_options = gdal.WarpOptions(**warp_options_dict)
    
    # 执行重投影
    result = gdal.Warp(output_tif, input_tif, options=warp_options)
    
    if result is None:
        raise Exception("高级坐标转换失败!")
    
    result = None
    print(f"高级坐标转换完成!输出文件:{output_tif}")


def get_suitable_cgcs2000_epsg(lon, lat):
    """
    根据经纬度获取合适的CGCS2000投影坐标系EPSG代码
    
    参数:
    lon: 经度
    lat: 纬度
    
    返回:
    int: 合适的EPSG代码
    """
    # CGCS2000 3度分带投影坐标系
    # 中央经线从75°开始,每3度一个分带
    zone = int((lon + 1.5) / 3) + 25
    
    if zone < 25 or zone > 45:
        # 如果超出范围,使用6度分带
        zone_6 = int((lon + 6) / 6) + 13
        epsg = 4490 + zone_6  # CGCS2000 6度分带
        print(f"使用CGCS2000 6度分带,带号:{zone_6},EPSG:{epsg}")
    else:
        epsg = 4513 + zone - 25  # CGCS2000 3度分带
        print(f"使用CGCS2000 3度分带,带号:{zone},EPSG:{epsg}")
    
    return epsg


def auto_reproject_to_cgcs2000(input_tif, output_tif=None):
    """
    自动选择合适的CGCS2000坐标系进行转换
    
    参数:
    input_tif: 输入TIF文件路径
    output_tif: 输出TIF文件路径,如果为None则自动生成
    """
    if output_tif is None:
        base_name = os.path.splitext(input_tif)[0]
        output_tif = f"{base_name}_cgcs2000.tif"
    
    # 获取影像中心点坐标
    dataset = gdal.Open(input_tif)
    if dataset is None:
        raise Exception(f"无法打开输入影像文件:{input_tif}")
    
    geotransform = dataset.GetGeoTransform()
    width = dataset.RasterXSize
    height = dataset.RasterYSize
    
    # 计算影像中心点
    center_x = geotransform[0] + width * geotransform[1] / 2
    center_y = geotransform[3] + height * geotransform[5] / 2
    
    dataset = None
    
    print(f"影像中心点坐标:({center_x:.6f}, {center_y:.6f})")
    
    # 获取合适的CGCS2000 EPSG代码
    target_epsg = get_suitable_cgcs2000_epsg(center_x, center_y)
    
    # 执行转换
    reproject_tif_simple(input_tif, output_tif, target_epsg)
    
    return output_tif


if __name__ == "__main__":
    # 使用示例
    input_tif = r"D:\temp\rgb_uint8.tif"  # 输入TIF文件路径
    
    # 方法1:自动选择合适的CGCS2000坐标系(推荐)
    print("=== 方法1:自动转换到CGCS2000 ===")
    try:
        output_file = auto_reproject_to_cgcs2000(input_tif)
        print(f"自动转换完成!输出文件:{output_file}")
    except Exception as e:
        print(f"自动转换失败:{e}")
    
    # 方法2:手动指定目标坐标系
    print("\n=== 方法2:手动指定坐标系 ===")
    output_tif = r"D:\temp\rgb_uint8_cgcs2000_manual.tif"
    target_epsg = 4526  # CGCS2000 3度分带 120°E中央经线
    
    try:
        reproject_tif_simple(input_tif, output_tif, target_epsg)
        print(f"手动转换完成!输出文件:{output_tif}")
    except Exception as e:
        print(f"手动转换失败:{e}")
    
    # 方法3:高级转换(自定义参数)
    print("\n=== 方法3:高级转换 ===")
    output_tif_advanced = r"D:\temp\rgb_uint8_cgcs2000_advanced.tif"
    
    try:
        # 自定义像素大小为2米
        reproject_tif_advanced(input_tif, output_tif_advanced, target_epsg, pixel_size=(2.0, 2.0))
        print(f"高级转换完成!输出文件:{output_tif_advanced}")
    except Exception as e:
        print(f"高级转换失败:{e}")
    
    print("\n=== 转换完成 ===")
    print("注意事项:")
    print("1. 确保输入文件路径正确")
    print("2. CGCS2000坐标系会根据影像位置自动选择合适的分带")
    print("3. 输出文件会自动压缩以节省空间")
    print("4. 如果转换失败,请检查GDAL是否正确安装")