Apply current workspace changes

This commit is contained in:
2026-04-22 01:52:21 +08:00
parent cf34b9a8ed
commit cb518b431f
449 changed files with 92252 additions and 321 deletions
+275
View File
@@ -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[:])