Files
BRDF/Flexbrdf/scripts/rad2reflextance.py
2026-04-10 16:46:45 +08:00

814 lines
28 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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())