#!/usr/bin/env python3 """ 将 HDF5 文件的坐标系统从 UTM 转换为 WGS84 地理坐标 同时保持与 MintPy tsview.py 的兼容性 """ import h5py import numpy as np import copy import argparse import os def utm_to_wgs84(easting, northing, zone, northern=True): """ 将 UTM 坐标转换为 WGS84 大地坐标 """ # UTM 参数 a = 6378137.0 # WGS84 长半轴 e = 0.081819190842622 # WGS84 第一偏心率 k0 = 0.9996 # 比例因子 # 中央经线 lon0 = (zone - 1) * 6 - 180 + 3 # 调整东伪偏移 x = easting - 500000.0 # 如果是南半球,调整北伪偏移 if not northern: y = northing - 10000000.0 else: y = northing # M = y / k0 mu = y / (a * (1 - e**2 / 4 - 3 * e**4 / 64 - 5 * e**6 / 256) * k0) e1 = (1 - np.sqrt(1 - e**2)) / (1 + np.sqrt(1 - e**2)) # 纬度计算 N1 = a / np.sqrt(1 - e**2 * np.sin(mu)**2) T1 = np.tan(mu)**2 C1 = e1**2 * np.cos(mu)**2 R1 = a * (1 - e**2) / (1 - e**2 * np.sin(mu)**2)**(3/2) D = x / (N1 * k0) lat = mu - N1 * np.tan(mu) / R1 * (D**2 / 2 + (5 + 3 * T1 + 10 * C1 - 4 * C1**2 - 9 * e1**2) * D**4 / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1**2 - 252 * e1**2 - 3 * C1**2) * D**6 / 720) # 经度计算 lon = lon0 * np.pi / 180 + D * (1 + (1 + 3 * e1**2 + 2 * e1**4) * D**2 / 6 + (2 - e1**2) * D**4 / 120) / np.cos(mu) # 转换为角度 lat_deg = np.degrees(lat) lon_deg = np.degrees(lon) return lon_deg, lat_deg def main(): parser = argparse.ArgumentParser( description='将 HDF5 文件转换为 WGS84 地理坐标(与 MintPy 兼容)', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=''' 示例: python convert_to_wgs84.py input.h5 -o output.h5 说明: 脚本会将文件完全转换为 WGS84 地理坐标系统, 同时设置正确的属性以保持与 MintPy 的兼容性。 ''' ) parser.add_argument('input', help='输入 HDF5 文件路径') parser.add_argument('-o', '--output', help='输出 HDF5 文件路径(默认:输入文件名_WGS84.h5)') args = parser.parse_args() # 输入和输出文件 input_file = args.input if args.output: output_file = args.output else: # 自动生成输出文件名 base, ext = os.path.splitext(input_file) output_file = f"{base}_WGS84{ext}" print(f"正在读取文件: {input_file}") f_in = h5py.File(input_file, 'r') # 读取所有数据集 datasets = {} for key in f_in.keys(): datasets[key] = f_in[key][:] print(f" 读取数据集: {key}, 形状: {datasets[key].shape}") # 读取所有属性 attrs = dict(f_in.attrs) print(f"\n共有 {len(attrs)} 个属性") # 解析 UTM 坐标信息 x_first = float(attrs['X_FIRST']) y_first = float(attrs['Y_FIRST']) x_step = float(attrs['X_STEP']) y_step = float(attrs['Y_STEP']) width = int(attrs['WIDTH']) length = int(attrs['LENGTH']) utm_zone = attrs['UTM_ZONE'] # 获取参考点位置(像素坐标) ref_x = int(attrs.get('REF_X', 0)) ref_y = int(attrs.get('REF_Y', 0)) # 转换 UTM Zone zone_num = int(''.join(filter(str.isdigit, utm_zone))) is_northern = 'N' in utm_zone.upper() print(f"\n原始坐标系统:") print(f" UTM Zone: {utm_zone} (EPSG: {attrs['EPSG']})") print(f" 左上角 UTM: ({x_first}, {y_first})") print(f" 步长: X={x_step}m, Y={y_step}m") print(f" 参考点像素: ({ref_x}, {ref_y})") # 生成网格坐标 x_coords = x_first + np.arange(width) * x_step y_coords = y_first + np.arange(length) * y_step # 转换为 WGS84 print(f"\n正在转换为 WGS84...") lon_grid, lat_grid = np.meshgrid(x_coords, y_coords) wgs84_lon, wgs84_lat = utm_to_wgs84(lon_grid, lat_grid, zone_num, is_northern) # 计算新的坐标参数(注意:lon 是经度,lat 是纬度) # X 对应经度,Y 对应纬度 lon_first = wgs84_lon[0, 0] lat_first = wgs84_lat[0, 0] lon_step = abs(wgs84_lon[0, 1] - wgs84_lon[0, 0]) if width > 1 else 0 lat_step = abs(wgs84_lat[1, 0] - wgs84_lat[0, 0]) if length > 1 else 0 # 计算参考点的经纬度 # REF_X 对应 X 轴(经度),REF_Y 对应 Y 轴(纬度) ref_lon = wgs84_lon[ref_y, ref_x] # 经度 ref_lat = wgs84_lat[ref_y, ref_x] # 纬度 # 更新属性 - 完全转换为 WGS84 attrs_new = copy.deepcopy(attrs) # 更新坐标系统相关属性 attrs_new['EPSG'] = 4326 # WGS84 attrs_new['X_FIRST'] = lon_first # 经度 attrs_new['Y_FIRST'] = lat_first # 纬度 attrs_new['X_STEP'] = lon_step attrs_new['Y_STEP'] = -lat_step # 保持Y方向向下为负 attrs_new['X_UNIT'] = 'degrees' attrs_new['Y_UNIT'] = 'degrees' # 更新参考坐标 - 现在是真正的经纬度 attrs_new['REF_LON'] = ref_lon attrs_new['REF_LAT'] = ref_lat # 保留原始 UTM 信息作为备份(带 _ORIG 后缀) attrs_new['UTM_ZONE_ORIG'] = attrs_new.get('UTM_ZONE', '') attrs_new['EPSG_ORIG'] = attrs_new.get('EPSG', '') # 关键:移除或清空 UTM_ZONE 属性,让 MintPy 识别为地理坐标系统 if 'UTM_ZONE' in attrs_new: del attrs_new['UTM_ZONE'] # 更新角点坐标 attrs_new['LAT_REF1'] = lat_first attrs_new['LAT_REF2'] = wgs84_lat[0, -1] attrs_new['LAT_REF3'] = wgs84_lat[-1, 0] attrs_new['LAT_REF4'] = wgs84_lat[-1, -1] attrs_new['LON_REF1'] = lon_first attrs_new['LON_REF2'] = wgs84_lon[0, -1] attrs_new['LON_REF3'] = wgs84_lon[-1, 0] attrs_new['LON_REF4'] = wgs84_lon[-1, -1] # 设置其他相关属性 attrs_new['COORD_SYSTEM'] = 'GEO' # 地理坐标系统 print(f"\n新坐标系统 (WGS84):") print(f" EPSG: {attrs_new['EPSG']}") print(f" 左上角: ({attrs_new['X_FIRST']:.6f}, {attrs_new['Y_FIRST']:.6f})") print(f" 步长: X={attrs_new['X_STEP']:.6f}°, Y={attrs_new['Y_STEP']:.6f}°") print(f" 参考点经纬度: ({attrs_new['REF_LON']:.6f}, {attrs_new['REF_LAT']:.6f})") print(f" 参考点像素: ({ref_x}, {ref_y})") # 创建新的 HDF5 文件 print(f"\n正在写入文件: {output_file}") f_out = h5py.File(output_file, 'w') # 写入所有数据集 for key, data in datasets.items(): f_out.create_dataset(key, data=data) print(f" 写入数据集: {key}") # 写入所有属性 for key, value in attrs_new.items(): f_out.attrs[key] = value f_in.close() f_out.close() print(f"\n完成!转换后的文件已保存为: {output_file}") print("\n说明:") print(" - 文件已完全转换为 WGS84 地理坐标系统") print(" - 所有坐标属性已更新为经纬度") print(" - 原始 UTM 信息已保存为 _ORIG 后缀的属性") print(" - 应该与 MintPy tsview.py 兼容") if __name__ == '__main__': main()