212 lines
6.8 KiB
Python
212 lines
6.8 KiB
Python
#!/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() |