Apply current workspace changes
This commit is contained in:
+275
@@ -0,0 +1,275 @@
|
||||
#! /usr/bin/env python
|
||||
#################################################################
|
||||
### This program is part of PyINT v2.1 ###
|
||||
### Copy Right (c): 2017-2019, Yunmeng Cao ###
|
||||
### Author: Yunmeng Cao ###
|
||||
### Modified: 2026, Z. Zou - HyP3 UTM GeoTIFF output ###
|
||||
### Contact : ymcmrs@gmail.com ###
|
||||
#################################################################
|
||||
|
||||
import numpy as np
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from pyint import _utils as ut
|
||||
|
||||
|
||||
INTRODUCTION = '''
|
||||
-------------------------------------------------------------------
|
||||
将 geocode_gamma.py 已地理编码的 GAMMA 二进制产品转换为
|
||||
ASF HyP3 兼容的 UTM GeoTIFF 格式, 用于 MintPy 时间序列分析。
|
||||
|
||||
本脚本 **不做任何地理编码或计算**, 仅执行:
|
||||
1. data2geotiff : GAMMA 二进制 (EQA) → GeoTIFF (EQA)
|
||||
2. gdalwarp : GeoTIFF (EQA) → GeoTIFF (UTM)
|
||||
3. rasterio : 生成水体掩膜
|
||||
|
||||
所有地理编码产品由 geocode_gamma.py 提供:
|
||||
amp, corr, dem, unw_phase, wrapped_phase,
|
||||
los_disp, vert_disp, lv_theta, lv_phi
|
||||
'''
|
||||
|
||||
EXAMPLE = '''
|
||||
Usage:
|
||||
hyp3format_gamma.py projectName ifgPair
|
||||
hyp3format_gamma.py shanghaiT171F128S1A 20241105-20241117
|
||||
hyp3format_gamma.py shanghaiT171F128S1A 20241105-20241117 --output-dir /path/to/output
|
||||
-------------------------------------------------------------------
|
||||
'''
|
||||
|
||||
|
||||
def cmdLineParse():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Convert geocoded GAMMA binaries to HyP3 UTM GeoTIFF.',
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
epilog=INTRODUCTION + '\n' + EXAMPLE)
|
||||
parser.add_argument('projectName', help='项目名称')
|
||||
parser.add_argument('ifgPair', help='干涉图对 (如 20241105-20241117)')
|
||||
parser.add_argument('--output-dir', dest='output_dir', default=None,
|
||||
help='输出目录. 默认: projectDir/Hyp3Products/')
|
||||
inps = parser.parse_args()
|
||||
return inps
|
||||
|
||||
|
||||
def get_utm_epsg(lon, lat):
|
||||
"""根据中心经纬度自动计算 UTM 投影的 EPSG 代码"""
|
||||
zone = int((lon + 180) / 6) + 1
|
||||
return 32600 + zone if lat >= 0 else 32700 + zone
|
||||
|
||||
|
||||
def run_cmd(cmd, desc=''):
|
||||
"""执行 shell 命令并检查返回值"""
|
||||
if desc:
|
||||
print(f" [{desc}] {cmd}")
|
||||
else:
|
||||
print(f" {cmd}")
|
||||
ret = os.system(cmd)
|
||||
if ret != 0:
|
||||
print(f" WARNING: 返回非零退出码 {ret}")
|
||||
return ret
|
||||
|
||||
|
||||
def main(argv):
|
||||
|
||||
start_time = time.time()
|
||||
inps = cmdLineParse()
|
||||
projectName = inps.projectName
|
||||
ifgPair = inps.ifgPair
|
||||
|
||||
Mdate = ifgPair.split('-')[0]
|
||||
Sdate = ifgPair.split('-')[1]
|
||||
|
||||
# 验证日期并计算时间基线
|
||||
d1 = datetime.strptime(Mdate, '%Y%m%d')
|
||||
d2 = datetime.strptime(Sdate, '%Y%m%d')
|
||||
interval = abs((d2 - d1).days)
|
||||
|
||||
# 读取模板参数
|
||||
scratchDir = os.getenv('SCRATCHDIR')
|
||||
templateDir = os.getenv('TEMPLATEDIR')
|
||||
templateFile = templateDir + '/' + projectName + '.template'
|
||||
templateDict = ut.update_template(templateFile)
|
||||
|
||||
rlks = templateDict['range_looks']
|
||||
azlks = templateDict['azimuth_looks']
|
||||
masterDate = templateDict['masterDate']
|
||||
|
||||
# 项目目录
|
||||
projectDir = scratchDir + '/' + projectName
|
||||
ifgDir = projectDir + '/ifgrams'
|
||||
demDir = projectDir + '/DEM'
|
||||
|
||||
workDir = ifgDir + '/' + ifgPair
|
||||
if not os.path.isdir(workDir):
|
||||
print(f"ERROR: 干涉图目录不存在: {workDir}")
|
||||
sys.exit(1)
|
||||
|
||||
# 输出目录
|
||||
outputDir = inps.output_dir or (projectDir + '/Hyp3Products')
|
||||
productDir = os.path.join(outputDir, ifgPair)
|
||||
os.makedirs(productDir, exist_ok=True)
|
||||
|
||||
# ============================================================
|
||||
# DEM 参数 (直接引用, 不复制不删除)
|
||||
# ============================================================
|
||||
DEMpar = demDir + '/' + masterDate + '_' + rlks + 'rlks.utm.dem.par'
|
||||
|
||||
nWidthDEM = ut.read_gamma_par(DEMpar, 'read', 'width')
|
||||
nLineDEM = ut.read_gamma_par(DEMpar, 'read', 'nlines')
|
||||
|
||||
# 自动检测 UTM 投影
|
||||
corner_lat = float(ut.read_gamma_par(DEMpar, 'read', 'corner_lat').split()[0])
|
||||
corner_lon = float(ut.read_gamma_par(DEMpar, 'read', 'corner_lon').split()[0])
|
||||
post_lat = float(ut.read_gamma_par(DEMpar, 'read', 'post_lat').split()[0])
|
||||
post_lon = float(ut.read_gamma_par(DEMpar, 'read', 'post_lon').split()[0])
|
||||
center_lat = corner_lat + float(nLineDEM) / 2 * post_lat
|
||||
center_lon = corner_lon + float(nWidthDEM) / 2 * post_lon
|
||||
utm_epsg = get_utm_epsg(center_lon, center_lat)
|
||||
|
||||
# HyP3 文件名前缀 (含 YYYYMMDDTHHMMSS, 兼容 MintPy 日期解析)
|
||||
hyp3_prefix = f"{projectName}_{Mdate}T000000_{Sdate}T000000"
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print(f"HyP3 格式转换: {projectName} / {ifgPair}")
|
||||
print(f"时间基线: {interval} 天, DEM: {nWidthDEM}×{nLineDEM}")
|
||||
print(f"中心: {center_lat:.4f}°N, {center_lon:.4f}°E → EPSG:{utm_epsg}")
|
||||
print(f"输出: {productDir}")
|
||||
print("=" * 70)
|
||||
|
||||
# ============================================================
|
||||
# 已地理编码 (EQA) GAMMA 二进制文件 (由 geocode_gamma.py 生成)
|
||||
# ============================================================
|
||||
geo_unw = workDir + '/geo_' + ifgPair + '_' + rlks + 'rlks.diff_filt.unw'
|
||||
geo_wrapped_pha = workDir + '/geo_' + ifgPair + '_' + rlks + 'rlks.diff_filt.pha'
|
||||
geo_los_disp = workDir + '/geo_' + ifgPair + '_' + rlks + 'rlks.los_disp'
|
||||
geo_vert_disp = workDir + '/geo_' + ifgPair + '_' + rlks + 'rlks.vert_disp'
|
||||
geo_amp = workDir + '/geo_' + masterDate + '_' + rlks + 'rlks.amp'
|
||||
geo_hgt = workDir + '/geo_' + masterDate + '_' + rlks + 'rlks.hgt'
|
||||
lv_theta = workDir + '/lv_theta'
|
||||
lv_phi = workDir + '/lv_phi'
|
||||
|
||||
# 相干性可能用 Pair 或 masterDate 命名
|
||||
geo_cor = workDir + '/geo_' + ifgPair + '_' + rlks + 'rlks.diff_filt.cor'
|
||||
if not os.path.exists(geo_cor):
|
||||
geo_cor = workDir + '/geo_' + masterDate + '_' + rlks + 'rlks.diff_filt.cor'
|
||||
|
||||
# ============================================================
|
||||
# data2geotiff (EQA binary → EQA GeoTIFF) → gdalwarp (→ UTM)
|
||||
# ============================================================
|
||||
print("\n--- GAMMA 二进制 → EQA GeoTIFF → UTM GeoTIFF ---")
|
||||
|
||||
product_map = [
|
||||
('amp', geo_amp, 'bilinear'),
|
||||
('corr', geo_cor, 'bilinear'),
|
||||
('dem', geo_hgt, 'bilinear'),
|
||||
('unw_phase', geo_unw, 'bilinear'),
|
||||
('wrapped_phase', geo_wrapped_pha, 'bilinear'),
|
||||
('los_disp', geo_los_disp, 'bilinear'),
|
||||
('vert_disp', geo_vert_disp, 'bilinear'),
|
||||
('lv_theta', lv_theta, 'bilinear'),
|
||||
('lv_phi', lv_phi, 'bilinear'),
|
||||
]
|
||||
|
||||
generated = {}
|
||||
|
||||
for name, geo_bin, interp in product_map:
|
||||
utm_tif = os.path.join(productDir, f'{hyp3_prefix}_{name}.tif')
|
||||
|
||||
# 跳过已存在且非空的输出
|
||||
if os.path.exists(utm_tif) and os.path.getsize(utm_tif) > 0:
|
||||
print(f" {name}: 已存在,跳过")
|
||||
generated[name] = utm_tif
|
||||
continue
|
||||
|
||||
if not os.path.exists(geo_bin):
|
||||
print(f" {name}: 源文件不存在 ({os.path.basename(geo_bin)}),跳过")
|
||||
continue
|
||||
|
||||
eqa_tif = workDir + '/' + name + '_hyp3_eqa.tif'
|
||||
|
||||
# GAMMA 二进制 → EQA GeoTIFF
|
||||
run_cmd(f'data2geotiff {DEMpar} {geo_bin} 2 {eqa_tif}', f'{name} → EQA')
|
||||
|
||||
if not os.path.exists(eqa_tif):
|
||||
print(f" WARNING: {name} EQA GeoTIFF 生成失败")
|
||||
continue
|
||||
|
||||
# EQA → UTM (gdalwarp)
|
||||
run_cmd(f'gdalwarp -t_srs EPSG:{utm_epsg} -r {interp} '
|
||||
f'-co COMPRESS=LZW -overwrite {eqa_tif} {utm_tif}',
|
||||
f'{name} → UTM')
|
||||
|
||||
# 清理 EQA 中间文件
|
||||
if os.path.exists(eqa_tif):
|
||||
os.remove(eqa_tif)
|
||||
|
||||
if os.path.exists(utm_tif) and os.path.getsize(utm_tif) > 0:
|
||||
generated[name] = utm_tif
|
||||
|
||||
# ============================================================
|
||||
# 生成水体掩膜 (相干性阈值)
|
||||
# ============================================================
|
||||
print("\n--- 水体掩膜 ---")
|
||||
water_mask_tif = os.path.join(productDir, f'{hyp3_prefix}_water_mask.tif')
|
||||
corr_tif = generated.get('corr')
|
||||
|
||||
if corr_tif and os.path.exists(corr_tif) and not os.path.exists(water_mask_tif):
|
||||
try:
|
||||
import rasterio
|
||||
with rasterio.open(corr_tif) as src:
|
||||
corr_data = src.read(1)
|
||||
mask = np.ones_like(corr_data, dtype=np.uint8)
|
||||
mask[corr_data < 0.05] = 0
|
||||
mask[np.isnan(corr_data)] = 0
|
||||
|
||||
profile = src.profile.copy()
|
||||
profile.update(dtype=rasterio.uint8, count=1, compress='lzw', nodata=None)
|
||||
with rasterio.open(water_mask_tif, 'w', **profile) as dst:
|
||||
dst.write(mask, 1)
|
||||
generated['water_mask'] = water_mask_tif
|
||||
print(f" 水体掩膜已生成")
|
||||
except Exception as e:
|
||||
print(f" WARNING: 水体掩膜生成失败: {e}")
|
||||
elif os.path.exists(water_mask_tif):
|
||||
generated['water_mask'] = water_mask_tif
|
||||
print(f" 水体掩膜已存在,跳过")
|
||||
|
||||
# ============================================================
|
||||
# 生成入射角图 (inc_map / inc_map_ell, 复制自 lv_theta)
|
||||
# ============================================================
|
||||
print("\n--- 入射角图 ---")
|
||||
inc_map_tif = os.path.join(productDir, f'{hyp3_prefix}_inc_map.tif')
|
||||
inc_map_ell_tif = os.path.join(productDir, f'{hyp3_prefix}_inc_map_ell.tif')
|
||||
lv_theta_tif = generated.get('lv_theta')
|
||||
|
||||
if lv_theta_tif and os.path.exists(lv_theta_tif):
|
||||
if not os.path.exists(inc_map_tif):
|
||||
os.system(f'cp {lv_theta_tif} {inc_map_tif}')
|
||||
generated['inc_map'] = inc_map_tif
|
||||
print(f" inc_map 已生成 (= lv_theta)")
|
||||
if not os.path.exists(inc_map_ell_tif):
|
||||
os.system(f'cp {lv_theta_tif} {inc_map_ell_tif}')
|
||||
generated['inc_map_ell'] = inc_map_ell_tif
|
||||
print(f" inc_map_ell 已生成 (近似 lv_theta)")
|
||||
|
||||
# ============================================================
|
||||
# 输出摘要
|
||||
# ============================================================
|
||||
print("\n" + "=" * 70)
|
||||
print(f"HyP3 格式转换完成: {ifgPair}")
|
||||
print(f"共 {len(generated)} 个产品:")
|
||||
for name, path in sorted(generated.items()):
|
||||
if os.path.exists(path):
|
||||
size_mb = os.path.getsize(path) / 1024 / 1024
|
||||
print(f" {name:20s} ({size_mb:.1f} MB)")
|
||||
print("=" * 70)
|
||||
|
||||
ut.print_process_time(start_time, time.time())
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[:])
|
||||
Reference in New Issue
Block a user