Initial commit

This commit is contained in:
2026-04-10 16:46:45 +08:00
commit 4fd1b0a203
165 changed files with 25698 additions and 0 deletions

View File

@ -0,0 +1,814 @@
#!/usr/bin/env python3
"""
高光谱反射率校正工具
功能:
- 读取ENVI ASCII Plot File格式的反射率校正文件
- 读取航带文件夹中的高光谱数据文件 (.bil/.bip/.bsq等ENVI格式)
注意spectral库通过读取对应的.hdr头文件来访问数据
- 根据波长匹配进行反射率校正(航带数据 / 校正值)
- 保存校正后的反射率文件
依赖:
- numpy
- GDAL - 用于读取和保存ENVI格式高光谱数据
- pathlib
使用方法:
python redlence.py <航带文件夹路径> <校正文件路径> [输出文件夹路径]
文件要求:
- 航带文件夹中应包含 .bil/.bip/.bsq 文件及其对应的 .hdr 头文件
- 校正文件为ENVI ASCII Plot File格式包含波长和校正值两列数据
"""
import numpy as np
import os
import sys
from pathlib import Path
from typing import Tuple, List, Dict, Optional
import argparse
# 可选GDAL库用于读取和保存ENVI格式文件
try:
from osgeo import gdal
# GDAL性能优化配置
GDAL_AVAILABLE = True
except ImportError:
GDAL_AVAILABLE = False
print("警告: GDAL不可用请安装GDAL")
def parse_correction_file(correction_file: str) -> Tuple[np.ndarray, np.ndarray]:
"""
解析ENVI ASCII Plot File格式的反射率校正文件优化版本
参数:
-----------
correction_file : str
校正文件路径
返回:
-----------
wavelengths : np.ndarray
波长数组 (nm)
corrections : np.ndarray
校正值数组
"""
try:
# 使用numpy的loadtxt加速读取跳过标题行
# 首先找到数据开始的行号
with open(correction_file, 'r', encoding='utf-8') as f:
lines = f.readlines()
# 找到数据开始的行索引
data_start_idx = 0
for i, line in enumerate(lines):
line = line.strip()
if not line or line.startswith(';'):
continue
if 'ENVI ASCII Plot File' in line or 'Column 1:' in line or 'Column 2:' in line:
continue
# 找到第一个可能是数据行的行
try:
parts = line.split()
if len(parts) >= 2:
float(parts[0]), float(parts[1])
data_start_idx = i
break
except (ValueError, IndexError):
continue
if data_start_idx == 0 and not lines:
raise ValueError("校正文件中未找到有效的数据行")
# 使用numpy loadtxt从数据开始行读取
data = np.loadtxt(correction_file, skiprows=data_start_idx, dtype=float)
if data.ndim == 1:
# 如果只有一行数据
wavelengths = np.array([data[0]])
corrections = np.array([data[1]])
else:
wavelengths = data[:, 0]
corrections = data[:, 1]
print(f"✅ 成功解析校正文件: {correction_file}")
print(f" 数据点数: {len(wavelengths)}")
print(f" 波长范围: {wavelengths.min():.1f} - {wavelengths.max():.1f} nm")
print(f" 校正值范围: {corrections.min():.6f} - {corrections.max():.6f}")
return wavelengths, corrections
except Exception as e:
# 如果numpy loadtxt失败回退到原始方法
print(f"⚠️ numpy加速读取失败回退到逐行读取: {e}")
return parse_correction_file_fallback(correction_file)
def parse_correction_file_fallback(correction_file: str) -> Tuple[np.ndarray, np.ndarray]:
"""
回退方法:使用原始的逐行解析方式
"""
wavelengths = []
corrections = []
try:
with open(correction_file, 'r', encoding='utf-8') as f:
lines = f.readlines()
# 跳过标题行,找到数据开始
for line in lines:
line = line.strip()
# 跳过空行和注释
if not line or line.startswith(';'):
continue
# 跳过标题
if 'ENVI ASCII Plot File' in line or 'Column 1:' in line or 'Column 2:' in line:
continue
# 尝试解析数据行(波长 校正值)
try:
parts = line.split()
if len(parts) >= 2:
wavelength = float(parts[0])
correction = float(parts[1])
wavelengths.append(wavelength)
corrections.append(correction)
except (ValueError, IndexError):
# 如果这一行不是数据,可能是其他格式,跳过
continue
if not wavelengths:
raise ValueError("校正文件中未找到有效的数据行")
wavelengths = np.array(wavelengths, dtype=float)
corrections = np.array(corrections, dtype=float)
return wavelengths, corrections
except Exception as e:
raise RuntimeError(f"解析校正文件失败: {correction_file}, 错误: {e}")
def find_hyperspectral_files(folder_path: str) -> List[str]:
"""
查找文件夹中的高光谱数据文件
支持的格式:.bil, .bip, .bsq等ENVI格式文件
注意GDAL可以直接读取ENVI格式文件会自动查找对应的.hdr头文件
参数:
-----------
folder_path : str
文件夹路径
返回:
-----------
file_list : List[str]
高光谱数据文件路径列表 (.bil/.bip/.bsq文件)
"""
folder = Path(folder_path)
if not folder.exists():
raise FileNotFoundError(f"文件夹不存在: {folder_path}")
# 支持的ENVI格式扩展名
supported_extensions = ['.bil', '.bip', '.bsq','.dat']
hyperspectral_files = []
for ext in supported_extensions:
files = list(folder.glob(f'*{ext}'))
hyperspectral_files.extend([str(f) for f in files])
# 去重(防止同一个文件被多次识别)
hyperspectral_files = list(set(hyperspectral_files))
if not hyperspectral_files:
print(f"警告: 在文件夹 {folder_path} 中未找到高光谱数据文件")
print("支持的格式: .bil, .bip, .bsq")
return sorted(hyperspectral_files)
def load_hyperspectral_data(file_path: str) -> Tuple[np.ndarray, Dict]:
"""
使用GDAL读取高光谱数据文件 - 流式版本
不加载整个立方体,只返回数据集句柄和元数据
参数:
-----------
file_path : str
高光谱数据文件路径 (.bil/.bip/.bsq)
返回:
-----------
dataset : gdal.Dataset
GDAL数据集对象用于流式读取
metadata : dict
元数据信息
"""
if not GDAL_AVAILABLE:
raise RuntimeError("需要GDAL库来读取高光谱文件请安装GDAL")
file_path = Path(file_path)
try:
# 使用GDAL打开ENVI文件
dataset = gdal.Open(str(file_path), gdal.GA_ReadOnly)
if dataset is None:
raise RuntimeError(f"无法打开文件: {file_path}")
# 获取基本信息
lines = dataset.RasterYSize
samples = dataset.RasterXSize
bands = dataset.RasterCount
# 查找对应的HDR文件
hdr_file = None
hdr_candidates = [
file_path.with_suffix('.hdr'), # datafile.hdr
file_path.with_suffix(file_path.suffix + '.hdr'), # datafile.ext.hdr
file_path.parent / f"{file_path.name}.hdr", # datafile.ext.hdr (另一种写法)
]
for candidate in hdr_candidates:
if candidate.exists():
hdr_file = candidate
break
# 尝试从HDR文件中提取波长信息
wavelengths = None
if hdr_file and hdr_file.exists():
try:
# 读取HDR文件内容
with open(str(hdr_file), 'r', encoding='utf-8', errors='ignore') as f:
hdr_content = f.read()
# 提取波长信息
import re
wavelength_match = re.search(r'wavelength\s*=\s*\{([^}]+)\}', hdr_content, re.IGNORECASE)
if wavelength_match:
wavelength_str = wavelength_match.group(1)
# 解析波长值
wavelength_values = []
for val in wavelength_str.split(','):
val = val.strip()
try:
wavelength_values.append(float(val))
except ValueError:
continue
if wavelength_values:
wavelengths = np.array(wavelength_values, dtype=float)
except Exception as e:
print(f"⚠️ 无法从HDR文件读取波长信息: {e}")
# 构建元数据
metadata = {
'file_path': str(file_path), # 原始数据文件路径
'hdr_file': str(hdr_file) if hdr_file else None, # 对应的hdr文件路径
'lines': lines,
'samples': samples,
'bands': bands,
'wavelengths': wavelengths,
'data_type': 'float32', # 流式读取时的数据类型
'interleave': 'unknown' # GDAL不直接提供interleave信息
}
print(f"✅ 成功打开高光谱文件: {Path(file_path).name}")
if hdr_file:
print(f" HDR文件: {Path(hdr_file).name}")
print(f" 数据尺寸: {metadata['lines']} x {metadata['samples']} x {metadata['bands']}")
print(f" 数据类型: {metadata['data_type']} (流式)")
if metadata['wavelengths'] is not None:
print(f" 波长范围: {metadata['wavelengths'][0]:.1f} - {metadata['wavelengths'][-1]:.1f} nm")
return dataset, metadata
except Exception as e:
raise RuntimeError(f"读取高光谱文件失败: {file_path}, 错误: {e}")
def interpolate_corrections(wavelengths_data: np.ndarray, wavelengths_corr: np.ndarray,
corrections: np.ndarray) -> np.ndarray:
"""
将校正值插值到数据波长上
参数:
-----------
wavelengths_data : np.ndarray
数据文件的波长数组
wavelengths_corr : np.ndarray
校正文件的波长数组
corrections : np.ndarray
校正值数组
返回:
-----------
interpolated_corrections : np.ndarray
插值后的校正值数组
"""
if wavelengths_data is None:
raise ValueError("数据文件缺少波长信息,无法进行校正")
try:
# 使用线性插值
from scipy.interpolate import interp1d
interp_func = interp1d(wavelengths_corr, corrections,
kind='linear', bounds_error=False,
fill_value='extrapolate')
interpolated = interp_func(wavelengths_data)
print(f"✅ 成功插值校正值到数据波长")
print(f" 数据波段数: {len(wavelengths_data)}")
print(f" 校正数据点数: {len(wavelengths_corr)}")
print(f" 插值范围: {interpolated.min():.3f} - {interpolated.max():.3f}")
return interpolated
except ImportError:
# 如果没有scipy使用numpy的interp
print("警告: scipy不可用使用numpy进行线性插值")
interpolated = np.interp(wavelengths_data, wavelengths_corr, corrections)
print(f"✅ 使用numpy插值校正值到数据波长")
print(f" 插值范围: {interpolated.min():.3f} - {interpolated.max():.3f}")
return interpolated
def apply_reflectance_correction_streaming(input_dataset, output_dataset, corrections: np.ndarray, block_size: int = 1024):
"""
应用反射率校正 - 流式版本
按块读取→校正→写入,避免加载整个立方体
参数:
-----------
input_dataset : gdal.Dataset
输入数据集
output_dataset : gdal.Dataset
输出数据集
corrections : np.ndarray
校正值数组 (bands,)
block_size : int
块大小(行数)
"""
lines = input_dataset.RasterYSize
samples = input_dataset.RasterXSize
bands = input_dataset.RasterCount
if bands != len(corrections):
raise ValueError(f"数据波段数 ({bands}) 与校正值数量 ({len(corrections)}) 不匹配")
print("🔢 正在应用反射率校正(流式处理,向量化加速)...")
# 用“乘倒数”替代逐元素除法,并在无效校正值(0/NaN/Inf)处直接置零
corrections = np.asarray(corrections, dtype=np.float32)
scale = np.zeros((bands,), dtype=np.float32)
valid = np.isfinite(corrections) & (corrections != 0)
scale[valid] = np.float32(10000.0) / corrections[valid]
scale_3d = scale[:, None, None]
# 提前缓存输出波段对象,避免循环内重复 GetRasterBand
output_bands = [output_dataset.GetRasterBand(i + 1) for i in range(bands)]
total_blocks = (lines + block_size - 1) // block_size
# 按块处理:每个块一次性读全波段并向量化计算
for block_idx, y_start in enumerate(range(0, lines, block_size), start=1):
y_end = min(y_start + block_size, lines)
actual_block_size = y_end - y_start
# 低频打印进度避免大量I/O拖慢处理
if block_idx == 1 or block_idx == total_blocks or block_idx % 10 == 0:
print(f" 处理块 {block_idx}/{total_blocks}: 行 {y_start}-{y_end-1} ({actual_block_size} 行)")
block = input_dataset.ReadAsArray(0, y_start, samples, actual_block_size)
if block is None:
raise RuntimeError(f"读取数据块失败: y_start={y_start}, block_size={actual_block_size}")
# 统一维度为 (bands, block_y, samples)
if block.ndim == 2:
block = block[np.newaxis, :, :]
block_f = block.astype(np.float32, copy=False)
np.multiply(block_f, scale_3d, out=block_f, casting='unsafe')
np.clip(block_f, 0, 65535, out=block_f)
block_u16 = block_f.astype(np.uint16, copy=False)
# GDAL按波段写出
for band_idx in range(bands):
output_bands[band_idx].WriteArray(block_u16[band_idx, :, :], 0, y_start)
print("✅ 成功应用反射率校正(流式处理,向量化加速)")
def save_corrected_data_streaming(input_dataset, corrections: np.ndarray, output_file: str,
wavelengths: Optional[np.ndarray] = None, source_hdr: Optional[str] = None):
"""
保存校正后的反射率数据为ENVI格式 - 流式版本
参数:
-----------
input_dataset : gdal.Dataset
输入数据集
corrections : np.ndarray
校正值数组
output_file : str
输出文件路径(不含扩展名)
wavelengths : np.ndarray, optional
波长信息
source_hdr : str, optional
源HDR文件路径用于复制HDR内容
"""
lines = input_dataset.RasterYSize
samples = input_dataset.RasterXSize
bands = input_dataset.RasterCount
# 确保输出目录存在
output_path = Path(output_file)
output_path.parent.mkdir(parents=True, exist_ok=True)
# 输出文件路径
bil_file = str(output_path.with_suffix('.dat'))
hdr_file = str(output_path.with_suffix('.hdr'))
try:
# 创建输出数据集
driver = gdal.GetDriverByName('ENVI')
output_dataset = driver.Create(bil_file, samples, lines, bands, gdal.GDT_UInt16,
options=['INTERLEAVE=BSQ'])
if output_dataset is None:
raise RuntimeError(f"无法创建ENVI数据集: {bil_file}")
# 设置NoData值
for band_idx in range(bands):
output_band = output_dataset.GetRasterBand(band_idx + 1)
output_band.SetNoDataValue(0)
# 应用流式校正和保存
apply_reflectance_correction_streaming(input_dataset, output_dataset, corrections)
# 关闭输出数据集
output_dataset = None
# 处理HDR文件
if source_hdr and Path(source_hdr).exists():
import shutil
shutil.copy2(source_hdr, hdr_file)
print(f"✅ 已复制源HDR文件: {Path(source_hdr).name}")
else:
# 创建HDR头文件
create_envi_header(hdr_file, lines, samples, bands, wavelengths, None)
print(f"✅ 成功保存校正结果:")
print(f" 数据文件: {bil_file}")
print(f" 头文件: {hdr_file}")
print(f" 数据尺寸: {lines} x {samples} x {bands}")
print(f" 数据类型: uint16 (反射率x10000)")
print(f" 处理方式: 流式处理")
except Exception as e:
raise RuntimeError(f"保存文件失败: {output_file}, 错误: {e}")
def save_with_gdal(data: np.ndarray, bil_file: str, wavelengths: Optional[np.ndarray] = None,
source_file: Optional[str] = None, source_hdr: Optional[str] = None):
"""
使用GDAL保存ENVI格式文件
"""
lines, samples, bands = data.shape
hdr_file = bil_file.replace('.dat', '.hdr')
# 创建GDAL驱动
driver = gdal.GetDriverByName('ENVI')
# 创建数据集 - 使用uint16格式优化性能和文件大小
dataset = driver.Create(bil_file, samples, lines, bands, gdal.GDT_UInt16,
options=['INTERLEAVE=BSQ'])
if dataset is None:
raise RuntimeError(f"无法创建ENVI数据集: {bil_file}")
try:
# 设置元数据
metadata = dataset.GetMetadata()
metadata['DESCRIPTION'] = 'Reflectance corrected hyperspectral data using Python'
metadata['SENSOR_TYPE'] = 'Hyperspectral'
metadata['DATA_UNITS'] = 'Reflectance'
metadata['PROCESSING_ALGORITHM'] = 'Reflectance Correction'
metadata['CREATION_DATE'] = str(np.datetime64('now'))
if source_file:
metadata['SOURCE_FILE'] = Path(source_file).name
# 添加波长信息到元数据
if wavelengths is not None and len(wavelengths) == bands:
metadata['wavelength_units'] = 'nm'
for i, wl in enumerate(wavelengths):
metadata[f'wavelength_{i+1}'] = str(wl)
dataset.SetMetadata(metadata)
# 写入数据 - 优化版本转换为uint16格式
print(f"💾 正在写入 {bands} 个波段的数据...")
# 将反射率转换为uint16乘以10000以保留4位小数精度裁剪到有效范围
data_uint16 = np.clip(data * 10000, 0, 65535).astype(np.uint16, copy=False)
for band_idx in range(bands):
band = dataset.GetRasterBand(band_idx + 1)
band_data = data_uint16[:, :, band_idx]
band.WriteArray(band_data)
band.SetNoDataValue(0) # uint16的NoData值为0
# 简化:只在必要时设置波段描述(可选优化:完全移除以提升速度)
# if wavelengths is not None and band_idx < len(wavelengths):
# band.SetDescription(f'{wavelengths[band_idx]:.1f} nm')
# 每处理100个波段显示一次进度减少打印频率
if bands >= 100 and (band_idx + 1) % 100 == 0:
print(f" 已写入 {band_idx + 1}/{bands} 个波段")
print(f"✅ 数据写入完成 ({bands} 个波段)")
# 创建HDR头文件GDAL会自动创建基本的HDR但我们需要添加更多信息
create_envi_header(hdr_file, lines, samples, bands, wavelengths, source_file)
finally:
# 关闭数据集
dataset = None
def save_with_numpy(data: np.ndarray, bil_file: str, hdr_file: str,
wavelengths: Optional[np.ndarray] = None, source_file: Optional[str] = None, source_hdr: Optional[str] = None):
"""
使用numpy保存ENVI格式文件GDAL不可用时的回退方案优化版本
"""
lines, samples, bands = data.shape
print(f"💾 正在保存 {bands} 个波段的数据...")
# 保存二进制数据 - uint16格式预先转换数据类型
with open(bil_file, 'wb') as f:
# 将反射率转换为uint16乘以10000以保留4位小数精度裁剪到有效范围
data_to_save = np.clip(data * 10000, 0, 65535).astype(np.uint16, copy=False)
data_to_save.tofile(f)
print(f"✅ 数据文件写入完成")
# 如果有源HDR文件直接复制
if source_hdr and Path(source_hdr).exists():
import shutil
shutil.copy2(source_hdr, hdr_file)
print(f"✅ 已复制源HDR文件: {Path(source_hdr).name}")
else:
# 创建HDR头文件
create_envi_header(hdr_file, lines, samples, bands, wavelengths, source_file)
def create_envi_header(hdr_file: str, lines: int, samples: int, bands: int,
wavelengths: Optional[np.ndarray] = None, source_file: Optional[str] = None):
"""
创建ENVI格式的HDR头文件
"""
with open(hdr_file, 'w', encoding='utf-8') as f:
f.write("ENVI\n")
f.write("description = {\n")
f.write(" Reflectance corrected hyperspectral data\n")
f.write(" Processed with Python reflectance correction}\n")
f.write(f"samples = {samples}\n")
f.write(f"lines = {lines}\n")
f.write(f"bands = {bands}\n")
f.write("header offset = 0\n")
f.write("file type = ENVI Standard\n")
f.write("data type = 12\n") # uint16
f.write("interleave = bsq\n")
f.write("sensor type = Hyperspectral\n")
f.write("byte order = 0\n") # little-endian
f.write("reflectance scale factor = 10000\n") # 反射率缩放因子
# 添加波长信息
if wavelengths is not None and len(wavelengths) == bands:
f.write("wavelength units = nm\n")
f.write("wavelength = {\n")
for i, wl in enumerate(wavelengths):
f.write(f" {wl}")
if i < len(wavelengths) - 1:
f.write(",")
if (i + 1) % 10 == 0: # 每10个波长换行
f.write("\n")
f.write("}\n")
# 添加波段名称
f.write("band names = {\n")
for i, wl in enumerate(wavelengths):
f.write(f" {wl:.1f} nm")
if i < len(wavelengths) - 1:
f.write(",")
if (i + 1) % 8 == 0: # 每8个波段名称换行
f.write("\n")
f.write("}\n")
def process_single_file(hyp_file: str, wavelengths_corr: np.ndarray, corrections: np.ndarray,
output_dir: str) -> bool:
"""
处理单个高光谱文件
参数:
-----------
hyp_file : str
高光谱文件路径
wavelengths_corr : np.ndarray
校正文件的波长
corrections : np.ndarray
校正值
output_dir : str
输出目录
返回:
-----------
success : bool
处理是否成功
"""
try:
print(f"\n🔄 处理文件: {Path(hyp_file).name}")
# 读取高光谱数据(流式)
input_dataset, metadata = load_hyperspectral_data(hyp_file)
try:
# 获取数据波长
wavelengths_data = metadata.get('wavelengths')
if wavelengths_data is None:
print(f"⚠️ 跳过文件 {Path(hyp_file).name}: 缺少波长信息")
return False
# 判断数据波长和校正波长是否一致
wavelengths_data = np.array(wavelengths_data)
if len(wavelengths_data) == len(wavelengths_corr) and np.allclose(wavelengths_data, wavelengths_corr, rtol=1e-6):
# 波长完全一致,直接使用校正值
print("✅ 数据波长与校正波长完全一致,无需插值")
interpolated_corrections = corrections
else:
# 波长不一致,需要插值
print("🔄 数据波长与校正波长不一致,进行插值")
interpolated_corrections = interpolate_corrections(
wavelengths_data, wavelengths_corr, corrections
)
# 生成输出文件名
input_name = Path(hyp_file).stem
output_file = Path(output_dir) / f"{input_name}_reflectance"
# 流式保存结果(包含校正)
save_corrected_data_streaming(input_dataset, interpolated_corrections, str(output_file),
wavelengths_data, metadata.get('hdr_file'))
finally:
# 确保关闭输入数据集
input_dataset = None
print(f"✅ 成功处理文件: {Path(hyp_file).name}")
return True
except Exception as e:
print(f"❌ 处理文件失败: {Path(hyp_file).name}, 错误: {e}")
return False
def batch_process(hyperspectral_dir: str, correction_file: str, output_dir: str) -> Dict[str, int]:
"""
批量处理文件夹中的所有高光谱文件
参数:
-----------
hyperspectral_dir : str
高光谱文件文件夹
correction_file : str
校正文件路径
output_dir : str
输出目录
返回:
-----------
results : dict
处理结果统计
"""
print("=" * 60)
print("🏁 开始高光谱反射率校正批量处理")
print("=" * 60)
# 检查依赖
if not GDAL_AVAILABLE:
print("❌ 错误: 需要安装GDAL库")
return {'total': 0, 'success': 0, 'failed': 0}
# 确保输出目录存在
Path(output_dir).mkdir(parents=True, exist_ok=True)
try:
# 解析校正文件
print("📖 解析校正文件...")
wavelengths_corr, corrections = parse_correction_file(correction_file)
# 查找高光谱文件
print(f"\n📂 查找高光谱文件...")
hyp_files = find_hyperspectral_files(hyperspectral_dir)
if not hyp_files:
print("❌ 未找到高光谱文件,处理终止")
return {'total': 0, 'success': 0, 'failed': 0}
print(f"找到 {len(hyp_files)} 个高光谱数据文件:")
for f in hyp_files:
print(f" - {Path(f).name} (需要对应的.hdr头文件)")
# 处理每个文件
results = {'total': len(hyp_files), 'success': 0, 'failed': 0}
for hyp_file in hyp_files:
success = process_single_file(hyp_file, wavelengths_corr, corrections, output_dir)
if success:
results['success'] += 1
else:
results['failed'] += 1
# 输出总结
print("\n" + "=" * 60)
print("📊 处理完成总结:")
print(f" 总文件数: {results['total']}")
print(f" 成功处理: {results['success']}")
print(f" 处理失败: {results['failed']}")
print(f" 输出目录: {output_dir}")
print("=" * 60)
return results
except Exception as e:
print(f"❌ 批量处理失败: {e}")
return {'total': 0, 'success': 0, 'failed': 0}
def main():
"""
主函数 - 命令行接口
"""
parser = argparse.ArgumentParser(
description='高光谱反射率校正工具',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
文件要求:
- 航带文件夹中应包含ENVI格式的高光谱数据文件(.bil/.bip/.bsq)和对应的头文件(.hdr)
- 校正文件应为ENVI ASCII Plot File格式包含波长和校正值两列数据
使用示例:
python redlence.py /path/to/hyperspectral/folder /path/to/correction.txt
python redlence.py /path/to/hyperspectral/folder /path/to/correction.txt /path/to/output/folder
"""
)
parser.add_argument('hyperspectral_dir', help='包含高光谱文件的文件夹路径')
parser.add_argument('correction_file', help='反射率校正文件路径 (ENVI ASCII Plot File格式)')
parser.add_argument('output_dir', nargs='?', default=None,
help='输出目录路径 (可选默认在输入文件夹下创建output文件夹)')
args = parser.parse_args()
# 设置默认输出目录
if args.output_dir is None:
args.output_dir = str(Path(args.hyperspectral_dir) / 'reflectance_output')
# 检查输入文件存在
if not Path(args.correction_file).exists():
print(f"❌ 校正文件不存在: {args.correction_file}")
return 1
if not Path(args.hyperspectral_dir).exists():
print(f"❌ 高光谱文件夹不存在: {args.hyperspectral_dir}")
return 1
# 执行批量处理
results = batch_process(args.hyperspectral_dir, args.correction_file, args.output_dir)
# 返回适当的退出码
if results['success'] > 0:
print("✅ 处理完成!")
return 0
else:
print("❌ 没有成功处理任何文件")
return 1
if __name__ == "__main__":
exit(main())