增加坡度计算

This commit is contained in:
2026-04-22 09:27:59 +08:00
parent 4fd1b0a203
commit d563a56358
20 changed files with 4891 additions and 344 deletions

103
slope/caijian.py Normal file
View File

@ -0,0 +1,103 @@
import rasterio
from rasterio.warp import reproject, Resampling
import numpy as np
def merge_angles_with_slope_aspect(angle_file, slope_aspect_file, output_file,
resampling=Resampling.bilinear):
"""
将坡度坡向波段添加到角度文件波段之后输出合并的ENVI DAT文件。
输出文件的空间范围、分辨率、投影与角度文件完全一致。
掩膜基于角度文件的忽略值生成:只有所有角度波段均为忽略值(0.0)的像素才被设为忽略值。
输出文件的忽略值统一设为0.0。
Parameters
----------
angle_file : str
包含角度信息的ENVI DAT文件如传感器角度、太阳角度等至少1个波段
该文件定义了输出的目标空间参数和掩膜基准。
slope_aspect_file : str
包含坡度坡向的ENVI DAT文件通常2个波段
output_file : str
输出合并后的ENVI DAT文件路径将自动生成.hdr头文件
resampling : rasterio.warp.Resampling, optional
重采样方法,默认为双线性(适用于连续参数)。
"""
# 1. 从角度文件获取目标空间参数、数据、掩膜
with rasterio.open(angle_file) as src_angle:
# 目标空间参数
dst_transform = src_angle.transform
dst_width = src_angle.width
dst_height = src_angle.height
dst_crs = src_angle.crs
# 读取角度文件所有波段
angle_data = src_angle.read() # shape: (bands, rows, cols)
angle_count = src_angle.count
# 获取角度文件的忽略值如果未定义默认为0.0,但应给出警告)
angle_nodata = src_angle.nodata
if angle_nodata is None:
print("警告角度文件未定义忽略值将使用0.0作为默认忽略值。")
angle_nodata = 0.0
# 构建掩膜:所有波段均不等于忽略值视为有效
mask = np.all(angle_data != angle_nodata, axis=0)
# 2. 处理坡度坡向文件:重采样到目标空间
with rasterio.open(slope_aspect_file) as src_sa:
src_sa_data = src_sa.read() # shape: (bands, src_sa_height, src_sa_width)
src_sa_count = src_sa.count
src_sa_crs = src_sa.crs
src_sa_transform = src_sa.transform
sa_resampled = np.empty((src_sa_count, dst_height, dst_width),
dtype=src_sa_data.dtype)
reproject(
source=src_sa_data,
destination=sa_resampled,
src_transform=src_sa_transform,
src_crs=src_sa_crs,
dst_transform=dst_transform,
dst_crs=dst_crs,
resampling=resampling
)
# 3. 合并波段:角度在前,坡度坡向在后
merged_data = np.concatenate([angle_data, sa_resampled], axis=0)
merged_count = merged_data.shape[0]
# 4. 准备输出元数据基于角度文件的profile
with rasterio.open(angle_file) as src_angle:
out_profile = src_angle.profile.copy()
output_nodata = 0.0 # 强制输出忽略值为0.0(用户要求)
out_profile.update({
'driver': 'ENVI',
'height': dst_height,
'width': dst_width,
'transform': dst_transform,
'crs': dst_crs,
'count': merged_count,
'dtype': merged_data.dtype,
'nodata': output_nodata
})
# 5. 应用掩膜将无效区域的像素设为忽略值0.0
for b in range(merged_count):
merged_data[b, ~mask] = output_nodata
# 6. 写入输出文件
with rasterio.open(output_file, 'w', **out_profile) as dst:
dst.write(merged_data)
print(f"处理完成!合并后的文件已保存至:{output_file}")
print(f"总波段数:{merged_count}(角度 {angle_count} 波段 + 坡度坡向 {src_sa_count} 波段)")
print(f"有效像素区域基于角度文件所有波段判断,忽略值统一设为 0.0。")
# 示例用法
if __name__ == "__main__":
angle_file = r"E:\is2\yaopu\output\angel.dat" # 角度DAT文件
slope_aspect_file = r"E:\is2\yaopu\DEM\slope_aspect_cosine.dat" # 原始坡度坡向DAT
out_file = r"E:\is2\yaopu\DEM\angles_with_slope_aspect.dat" # 合并输出
merge_angles_with_slope_aspect(angle_file, slope_aspect_file, out_file)

197
slope/readme.txt Normal file
View File

@ -0,0 +1,197 @@
================================================================================
地形校正模块 - 已知问题与改进方向
================================================================================
【问题描述】
-----------
当前版本的 slope_aspectV2.py 在处理推扫式无人机高光谱图像时,存在一个关键假设:
整幅图像使用单一的太阳天顶角和方位角来计算 cosine_i入射角余弦
然而,实际数据采集情况是:
- 高光谱图像由3个架次的无人机飞行拼接而成
- 每个架次的飞行时间不同(通常间隔数分钟至数十分钟)
- 因此,不同扫描线(或不同图像区域)对应的太阳角度是不同的
- 但目前代码仅基于DEM中心点坐标计算一组太阳角度并应用于整幅图像
【技术影响】
-----------
这个简化会导致以下问题:
1. 时间跨度误差
- 假设3个架次间隔30分钟太阳方位角可能变化7-8度取决于纬度
- 在日出/日落时段太阳高度角变化可达10-15度
- 这会导致不同架次交界处的 cosine_i 出现系统性偏差
2. 地形校正不准确
- 东向坡面:过早架次会低估照明,过晚架次会高估照明
- 西向坡面:与东向坡面相反
- 交界区域会出现明显的"拼接缝"现象
3. BRDF校正累积误差
- cosine_i 是许多BRDF模型的关键输入参数
- 角度误差会传播到后续的BRDF地形校正结果
【当前代码实现】
---------------
文件: slope/slope_aspectV2.py
当前流程:
1. 读取DEM -> 2. 计算坡度/坡向 -> 3. 获取DEM中心点坐标(lat, lon)
4. 根据单一时间计算一组太阳角度(solar_zn, solar_az)
5. 将这组角度应用于整幅图像的所有像素
关键代码段约110-130行
```python
# 获取DEM中心点坐标
latitude, longitude = get_dem_center_coords(dem) # 仅一个中心点!
# 计算太阳角度(仅一组)
solar_zn_deg, solar_az_deg = calc_solar_angles(latitude, longitude, observation_time)
# 应用于整幅图像
cosine_i = calc_cosine_i(solar_zn_rad, solar_az_rad, aspect_rad, slope_rad)
```
【需要的改进方向】
-----------------
接手人员需要进行以下修改:
方案A: 分架次处理(推荐)
----------------------------
如果已知3个架次的地理分界线或时间范围
1. 输入格式修改
- 接收3组时间参数或从飞行日志自动提取
- 例如: -t1 "2024-06-15 08:30:00" -t2 "2024-06-15 09:00:00" -t3 "2024-06-15 09:30:00"
2. 空间分区处理
- 根据每架次的覆盖范围可从高光谱图像的GLT或地理坐标确定
- 将DEM分割为3个区域
- 每个区域使用对应架次的时间计算太阳角度
3. 修改后的伪代码示例:
```python
# 定义3个架次的时间和地理范围
flight_segments = [
{'time': '2024-06-15 08:30:00', 'row_range': (0, 1200)}, # 架次1: 行0-1199
{'time': '2024-06-15 09:00:00', 'row_range': (1200, 2800)}, # 架次2: 行1200-2799
{'time': '2024-06-15 09:30:00', 'row_range': (2800, 4000)}, # 架次3: 行2800-3999
]
# 初始化cosine_i数组
cosine_i = np.zeros_like(slope_data)
# 分段计算
for segment in flight_segments:
dt = parse_datetime(segment['time'])
solar_zn, solar_az = calc_solar_angles(lat, lon, dt)
y1, y2 = segment['row_range']
cosine_i[y1:y2, :] = calc_cosine_i(
np.deg2rad(solar_zn), np.deg2rad(solar_az),
aspect_rad[y1:y2, :], slope_rad[y1:y2, :]
)
```
方案B: 逐行/逐像素太阳角度(更精确)
-------------------------------------
如果需要更高精度(考虑太阳角度在单架次内的缓慢变化):
1. 输入要求
- 高光谱图像的每一行对应的时间戳可从IMU/GPS数据提取
- 或者每个像素的精确UTC时间
2. 逐行计算
```python
# 假设times是一个与图像行数相同长度的一维数组
# times[i] = 第i行的观测时间datetime对象
for row in range(n_rows):
dt = observation_times[row] # 该行的具体时间
solar_zn, solar_az = calc_solar_angles(lat, lon, dt)
cosine_i[row, :] = calc_cosine_i(
np.deg2rad(solar_zn), np.deg2rad(solar_az),
aspect_rad[row, :], slope_rad[row, :]
)
```
3. 性能优化
- 由于pvlib计算较慢可对时间相近的行批量计算
- 例如每10行计算一次太阳角度中间行插值
方案C: 从飞行日志自动提取(最自动化)
--------------------------------------
如果飞行平台记录了GPS/IMU数据
1. 输入数据
- 读取POS数据位置、姿态、时间
- 或从高光谱图像的GLT地理位置查找表提取
2. 建立时间-位置映射
- 根据无人机位置和时间建立每行图像的观测时间
3. 分区域计算cosine_i
【数据结构参考】
---------------
典型的推扫式高光谱数据结构:
高光谱图像 (lines, samples, bands)
- lines: 扫描线数(飞行方向的像素数)
- samples: 每行的像素数(垂直飞行方向)
- 第i行对应无人机的第i个位置
关键信息来源:
1. 图像头文件 (.hdr) - 通常包含起始时间和积分时间
2. GLT文件 (Geographic Lookup Table) - 每个像素的地理坐标
3. 飞行日志/POS数据 - 每行对应的时间戳
4. 帧辅助数据 (Frame Auxiliary Data) - 部分传感器自带每帧时间
【建议的输入接口修改】
----------------------
当前命令行接口:
python slope_aspectV2.py -i dem.tif -o output.dat -t "2024-06-15 10:00:00"
建议扩展为:
# 方式1: 手动指定3个架次的时间和行范围
python slope_aspectV2.py -i dem.tif -o output.dat \
--segments "0,1200,2024-06-15T08:30:00" \
--segments "1200,2800,2024-06-15T09:00:00" \
--segments "2800,4000,2024-06-15T09:30:00"
# 方式2: 从飞行日志文件自动读取
python slope_aspectV2.py -i dem.tif -o output.dat --time-log flight_log.csv
# 方式3: 从高光谱图像头文件提取时间信息
python slope_aspectV2.py -i dem.tif -o output.dat --hyperspectral-ref image.hdr
【验证方法】
-----------
修改后应验证以下指标:
1. 连续性检查
- 目视检查3个架次交界处的cosine_i是否连续
- 统计交界行前后10行的cosine_i差异
2. 物理合理性
- 东向坡的cosine_i应随时间增加而增加上午飞行
- 西向坡的cosine_i应随时间增加而减小上午飞行
3. 与GLT对比
- 如果高光谱有GLT可根据每像素的太阳角度公式验证
【相关文件】
-----------
- slope_aspectV2.py - 当前主程序(需要修改)
- angle_compute.py - 角度计算工具(可能包含相关逻辑)
- 高光谱图像的.hdr文件 - 可能包含时间元数据
- 飞行日志/POS数据 - 外部时间参考
【优先级建议】
--------------
1. 【高】首先实现方案A分架次处理- 工作量适中,效果显著
2. 【中】评估是否需要方案B逐行- 取决于太阳角度变化幅度
3. 【低】长期可考虑方案C全自动- 需要整合飞行数据解析
简单来说在计算的时候需要加入角度文件进行逐像素的cosi计算

83
slope/slope_aspect.py Normal file
View File

@ -0,0 +1,83 @@
import xdem
import rasterio
import numpy as np
def calc_cosine_i(solar_zn, solar_az, aspect, slope):
"""Generate cosine i image. The cosine of the incidence angle (i) is
defined as the angle between the normal to the pixel surface
and the solar zenith direction.
All input geometry units must be in radians.
Args:
solar_az (numpy.ndarray): Solar azimuth angle.
solar_zn (numpy.ndarray): Solar zenith angle.
aspect (numpy.ndarray): Ground aspect.
slope (numpy.ndarray): Ground slope.
Returns:
numpy.ndarray: Cosine i image.
"""
relative_az = aspect - solar_az
cosine_i = (np.cos(solar_zn) * np.cos(slope) +
np.sin(solar_zn) * np.sin(slope) * np.cos(relative_az))
return cosine_i
# ========== 1. 读取 DEM ==========
dem = xdem.DEM("E:/is2/yaopu/DEM/dsm.tif")
# ========== 2. 计算坡度、坡向 ==========
slope = xdem.terrain.slope(dem, method='ZevenbergThorne')
aspect = xdem.terrain.aspect(dem)
# ========== 3. 获取空间参考信息 ==========
transform = dem.transform
crs = dem.crs
# ========== 4. 转换为 numpy 数组 ==========
slope_data = slope.data
aspect_data = aspect.data
# ========== 5. 太阳角度(单位:度,根据实际飞行时间和地理位置设置) ==========
solar_zn_deg = 30.0 # 太阳天顶角(从天顶到太阳的夹角),例如 30°
solar_az_deg = 180.0 # 太阳方位角(从北顺时针),例如 180°正南
# 转换为弧度(因为三角函数需要弧度)
solar_zn_rad = np.deg2rad(solar_zn_deg)
solar_az_rad = np.deg2rad(solar_az_deg)
# 坡度和坡向也转换为弧度
slope_rad = np.deg2rad(slope_data)
aspect_rad = np.deg2rad(aspect_data)
# ========== 6. 计算 cosine_i ==========
cosine_i = calc_cosine_i(solar_zn_rad, solar_az_rad, aspect_rad, slope_rad)
# ========== 7. 处理无效值NaN ==========
# 注意:将 NaN 替换为 0 可能会与真实值为 0 的像元混淆如水平面坡度为0阴影边缘cosine_i=0
# 如需严格区分,建议使用特殊值(如 -9999作为 NoData。
slope_data = np.nan_to_num(slope_data, nan=0.0)
aspect_data = np.nan_to_num(aspect_data, nan=0.0)
cosine_i = np.nan_to_num(cosine_i, nan=0.0)
# ========== 8. 堆叠为多波段数组坡度、坡向、cosine_i ==========
stacked = np.stack([slope_data, aspect_data, cosine_i], axis=0)
# ========== 9. 输出 ENVI 格式文件 ==========
output_path = "E:/is2/yaopu/DEM/slope_aspect_cosine.dat"
with rasterio.open(
output_path,
'w',
driver='ENVI',
height=stacked.shape[1],
width=stacked.shape[2],
count=stacked.shape[0],
dtype=stacked.dtype,
crs=crs,
transform=transform,
nodata=0.0, # 与上面替换的 NaN 值一致
) as dst:
dst.write(stacked)
print(f"已保存多波段 ENVI 文件:{output_path}")
print(f"波段顺序1-坡度(°), 2-坡向(°), 3-cosine_i")

381
slope/slope_aspectV2.py Normal file
View File

@ -0,0 +1,381 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
DEM地形处理工具 - 计算坡度、坡向和太阳入射角余弦
该工具从DEM文件中提取坐标信息根据给定时间计算太阳位置
并生成坡度、坡向和cosine_i的多波段ENVI文件。
作者: BRDF_GUI Team
版本: 2.0.0
"""
import xdem
import rasterio
import numpy as np
import pandas as pd
import argparse
import sys
from datetime import datetime
from pathlib import Path
import pvlib.solarposition as solarposition
from rasterio.crs import CRS
import pyproj
def calc_cosine_i(solar_zn, solar_az, aspect, slope):
"""
计算入射角余弦cosine i
入射角余弦定义为地表法线与太阳天顶方向之间夹角的余弦值。
所有角度输入必须为弧度。
Args:
solar_az (numpy.ndarray): 太阳方位角(弧度)
solar_zn (numpy.ndarray): 太阳天顶角(弧度)
aspect (numpy.ndarray): 地面坡向(弧度)
slope (numpy.ndarray): 地面坡度(弧度)
Returns:
numpy.ndarray: 入射角余弦图像
"""
relative_az = aspect - solar_az
cosine_i = (np.cos(solar_zn) * np.cos(slope) +
np.sin(solar_zn) * np.sin(slope) * np.cos(relative_az))
return cosine_i
def get_dem_center_coords(dem):
"""
获取DEM图像中心点的经纬度坐标。
Args:
dem: xdem.DEM对象
Returns:
tuple: (纬度, 经度) - 单位:度
"""
# 获取DEM的范围边界
bounds = dem.bounds # (left, bottom, right, top)
center_x = (bounds.left + bounds.right) / 2
center_y = (bounds.bottom + bounds.top) / 2
# 如果DEM是投影坐标系需要转换为WGS84经纬度
if dem.crs is not None and not dem.crs.is_geographic:
# 创建从投影坐标系到WGS84的转换
transformer = pyproj.Transformer.from_crs(dem.crs, CRS.from_epsg(4326), always_xy=True)
lon, lat = transformer.transform(center_x, center_y)
else:
# 已经是地理坐标系(经纬度)
lon, lat = center_x, center_y
return lat, lon
def parse_datetime(datetime_str):
"""
解析日期时间字符串。
支持的格式:
- YYYY-MM-DD HH:MM:SS
- YYYY-MM-DDTHH:MM:SS
- YYYYMMDD_HHMMSS
Args:
datetime_str (str): 日期时间字符串
Returns:
datetime: datetime对象UTC时间
"""
formats = [
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%dT%H:%M:%S",
"%Y%m%d_%H%M%S",
"%Y-%m-%d",
]
for fmt in formats:
try:
dt = datetime.strptime(datetime_str, fmt)
# 如果只输入了日期默认时间为正午12:00
if fmt == "%Y-%m-%d":
dt = dt.replace(hour=12, minute=0, second=0)
return dt
except ValueError:
continue
raise ValueError(f"无法解析日期时间: {datetime_str}. 支持的格式: YYYY-MM-DD HH:MM:SS, YYYY-MM-DDTHH:MM:SS, YYYYMMDD_HHMMSS")
def get_user_input_datetime():
"""
交互式获取用户输入的日期和时间。
Returns:
datetime: datetime对象UTC时间
"""
print("请输入观测日期和时间UTC时间")
try:
year = int(input(" 年份 (YYYY): "))
month = int(input(" 月份 (MM): "))
day = int(input(" 日期 (DD): "))
hour = int(input(" 小时 (HH, 24小时制): "))
minute = int(input(" 分钟 (MM): "))
second = int(input(" 秒 (SS): "))
dt = datetime(year, month, day, hour, minute, second)
print(f"\n使用的时间: {dt.strftime('%Y-%m-%d %H:%M:%S')} UTC")
return dt
except ValueError as e:
print(f"输入错误: {e}")
print("将使用默认时间 2024-06-15 10:00:00 UTC")
return datetime(2024, 6, 15, 10, 0, 0)
def calc_solar_angles(lat, lon, dt):
"""
使用pvlib计算太阳天顶角和方位角。
Args:
lat (float): 纬度(度)
lon (float): 经度(度)
dt (datetime): datetime对象UTC时间
Returns:
tuple: (太阳天顶角, 太阳方位角) - 单位:度
天顶角: 0=天顶, 90=地平线
方位角: 从北顺时针0=北90=东180=南270=西
"""
# 创建时间索引
times = pd.DatetimeIndex([dt])
# 使用pvlib计算太阳位置
solpos = solarposition.get_solarposition(times, lat, lon)
solar_zn_deg = solpos['zenith'].values[0] # 天顶角
solar_az_deg = solpos['azimuth'].values[0] # 方位角
return solar_zn_deg, solar_az_deg
def write_envi_output(output_path, data, transform, crs, metadata=None):
"""
将数据写入ENVI格式文件。
Args:
output_path (str): 输出文件路径
data (numpy.ndarray): 数据数组 (bands, rows, cols)
transform: 地理变换参数
crs: 坐标参考系
metadata (dict, optional): 额外的元数据
"""
with rasterio.open(
output_path,
'w',
driver='ENVI',
height=data.shape[1],
width=data.shape[2],
count=data.shape[0],
dtype=data.dtype,
crs=crs,
transform=transform,
nodata=0.0,
) as dst:
dst.write(data)
# 写入ENVI头文件元数据
if metadata:
dst.update_tags(**metadata)
def process_dem(dem_path, output_path, datetime_input=None, interactive=False):
"""
主处理函数读取DEM计算坡度坡向计算太阳角度输出结果。
Args:
dem_path (str): DEM输入文件路径
output_path (str): 输出文件路径
datetime_input (str, optional): 日期时间字符串如果为None则使用交互模式
interactive (bool): 是否使用交互式时间输入
Returns:
dict: 处理结果信息
"""
# ========== 1. 读取 DEM ==========
print(f"读取DEM文件: {dem_path}")
dem = xdem.DEM(dem_path)
# ========== 2. 计算坡度、坡向 ==========
print("计算坡度和坡向...")
slope = xdem.terrain.slope(dem, method='ZevenbergThorne')
aspect = xdem.terrain.aspect(dem)
# ========== 3. 获取空间参考信息 ==========
transform = dem.transform
crs = dem.crs
# ========== 4. 转换为 numpy 数组 ==========
slope_data = slope.data
aspect_data = aspect.data
# ========== 5. 获取DEM中心点坐标并计算太阳角度 ==========
print("\n获取DEM坐标信息...")
latitude, longitude = get_dem_center_coords(dem)
print(f" 中心点纬度: {latitude:.6f}°")
print(f" 中心点经度: {longitude:.6f}°")
print(f" 坐标系: WGS84")
# 获取观测时间
if datetime_input:
observation_time = parse_datetime(datetime_input)
print(f"\n使用命令行提供的时间: {observation_time.strftime('%Y-%m-%d %H:%M:%S')} UTC")
elif interactive or not sys.stdin.isatty():
observation_time = get_user_input_datetime()
else:
# 默认时间(如果非交互式且未提供时间)
observation_time = datetime(2024, 6, 15, 10, 0, 0)
print(f"\n使用默认时间: {observation_time.strftime('%Y-%m-%d %H:%M:%S')} UTC")
# 计算太阳角度
print("\n计算太阳位置...")
solar_zn_deg, solar_az_deg = calc_solar_angles(latitude, longitude, observation_time)
print(f" 太阳天顶角: {solar_zn_deg:.2f}°")
print(f" 太阳高度角: {90 - solar_zn_deg:.2f}°")
print(f" 太阳方位角: {solar_az_deg:.2f}°")
# 转换为弧度
solar_zn_rad = np.deg2rad(solar_zn_deg)
solar_az_rad = np.deg2rad(solar_az_deg)
# 坡度和坡向也转换为弧度
slope_rad = np.deg2rad(slope_data)
aspect_rad = np.deg2rad(aspect_data)
# ========== 6. 计算 cosine_i ==========
print("\n计算入射角余弦 (cosine_i)...")
cosine_i = calc_cosine_i(solar_zn_rad, solar_az_rad, aspect_rad, slope_rad)
# ========== 7. 处理无效值NaN ==========
slope_data = np.nan_to_num(slope_data, nan=0.0)
aspect_data = np.nan_to_num(aspect_data, nan=0.0)
cosine_i = np.nan_to_num(cosine_i, nan=0.0)
# ========== 8. 堆叠为多波段数组 ==========
stacked = np.stack([slope_data, aspect_data, cosine_i], axis=0)
# ========== 9. 准备元数据 ==========
metadata = {
'description': 'Slope, Aspect, and Cosine_i derived from DEM',
'band_names': 'slope(deg),aspect(deg),cosine_i',
'solar_zenith_angle': str(solar_zn_deg),
'solar_azimuth_angle': str(solar_az_deg),
'solar_elevation_angle': str(90 - solar_zn_deg),
'observation_time_utc': observation_time.strftime('%Y-%m-%d %H:%M:%S'),
'dem_center_lat': str(latitude),
'dem_center_lon': str(longitude),
}
# ========== 10. 输出 ENVI 格式文件 ==========
print(f"\n保存结果到: {output_path}")
write_envi_output(output_path, stacked, transform, crs, metadata)
print("\n处理完成!")
print(f" 输出文件: {output_path}")
print(f" 波段顺序: 1-坡度(°), 2-坡向(°), 3-cosine_i")
return {
'output_path': output_path,
'solar_zenith': solar_zn_deg,
'solar_azimuth': solar_az_deg,
'center_lat': latitude,
'center_lon': longitude,
'observation_time': observation_time,
}
def main():
"""主函数 - 命令行入口"""
parser = argparse.ArgumentParser(
description='DEM地形处理工具 - 计算坡度、坡向和太阳入射角余弦',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
使用示例:
# 基本用法(交互式输入时间)
python slope_aspectV2.py -i dem.tif -o output.dat
# 通过命令行指定时间
python slope_aspectV2.py -i dem.tif -o output.dat -t "2024-06-15 10:30:00"
# 仅指定日期默认使用正午12:00
python slope_aspectV2.py -i dem.tif -o output.dat -t "2024-06-15"
# 显示详细处理信息
python slope_aspectV2.py -i dem.tif -o output.dat -t "2024-06-15 10:30:00" -v
支持的日期时间格式:
- "YYYY-MM-DD HH:MM:SS" (推荐)
- "YYYY-MM-DDTHH:MM:SS" (ISO格式)
- "YYYYMMDD_HHMMSS"
- "YYYY-MM-DD" (默认使用12:00:00)
'''
)
parser.add_argument('-i', '--input', required=True,
help='输入DEM文件路径 (支持GeoTIFF等格式)')
parser.add_argument('-o', '--output', required=True,
help='输出ENVI文件路径 (.dat)')
parser.add_argument('-t', '--time',
help='观测日期时间 (UTC),格式: "YYYY-MM-DD HH:MM:SS"'
'如果不提供,将进入交互式输入模式')
parser.add_argument('--interactive', action='store_true',
help='强制使用交互式时间输入模式')
parser.add_argument('-v', '--verbose', action='store_true',
help='显示详细处理信息')
parser.add_argument('--version', action='version', version='%(prog)s 2.0.0')
args = parser.parse_args()
# 验证输入文件存在
if not Path(args.input).exists():
print(f"错误: 输入文件不存在: {args.input}", file=sys.stderr)
sys.exit(1)
# 创建输出目录(如果不存在)
output_dir = Path(args.output).parent
if not output_dir.exists():
output_dir.mkdir(parents=True, exist_ok=True)
print(f"创建输出目录: {output_dir}")
try:
# 执行处理
result = process_dem(
dem_path=args.input,
output_path=args.output,
datetime_input=args.time,
interactive=args.interactive
)
if args.verbose:
print("\n详细结果:")
for key, value in result.items():
print(f" {key}: {value}")
sys.exit(0)
except Exception as e:
print(f"\n处理失败: {e}", file=sys.stderr)
if args.verbose:
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == '__main__':
main()