123 lines
4.4 KiB
Python
123 lines
4.4 KiB
Python
from osgeo import gdal
|
|
import numpy as np
|
|
import sys
|
|
import os
|
|
import re
|
|
import math
|
|
|
|
def tif_to_array(path):
|
|
data = gdal.Open(path)
|
|
if data is None:
|
|
raise FileNotFoundError(f"Cannot open file: {path}")
|
|
band = data.GetRasterBand(1)
|
|
array = band.ReadAsArray().astype(np.float32)
|
|
return data, array
|
|
|
|
def handle_nodata(array):
|
|
# Replace only negative values with NaN
|
|
clean_array = np.where(array < 0, np.nan, array)
|
|
return clean_array
|
|
|
|
def reflectance_calc(array, reflectance_mult, reflectance_add, sun_elevation):
|
|
# Debugging print statements
|
|
print(f"Reflectance Mult: {reflectance_mult}, Reflectance Add: {reflectance_add}, Sun Elevation: {sun_elevation}")
|
|
print(f"Array Sample Before: {array[:5, :5]}") # Print a small portion of the array for inspection
|
|
|
|
result = ((array * reflectance_mult) + reflectance_add) / math.sin(math.radians(sun_elevation))
|
|
|
|
# Debugging print statements
|
|
print(f"Array Sample After: {result[:5, :5]}") # Print a small portion of the result for inspection
|
|
return result
|
|
|
|
def save_tif(array, data, output_path):
|
|
driver = gdal.GetDriverByName('GTiff')
|
|
rows, cols = array.shape
|
|
out_data = driver.Create(output_path, cols, rows, 1, gdal.GDT_Float32)
|
|
out_data.SetGeoTransform(data.GetGeoTransform())
|
|
out_data.SetProjection(data.GetProjection())
|
|
out_band = out_data.GetRasterBand(1)
|
|
out_band.WriteArray(array)
|
|
out_band.SetNoDataValue(-9999)
|
|
out_band.FlushCache()
|
|
out_data = None
|
|
|
|
def get_output_path(output_dir, input_path, suffix):
|
|
basename = os.path.basename(input_path)
|
|
basename_no_ext = os.path.splitext(basename)[0]
|
|
# basename_no_ext = re.sub(r'_B[1-9]|_B10|_B11', '', basename_no_ext)
|
|
path = os.path.join(output_dir, f"{basename_no_ext}_{suffix}.TIF")
|
|
return path
|
|
|
|
def print_min_max(array, label):
|
|
print(label, " Min:", np.nanmin(array), " Max:", np.nanmax(array))
|
|
|
|
def get_reflectance_params(band_number, metadata_lines):
|
|
reflectance_mult = None
|
|
reflectance_add = None
|
|
for line in metadata_lines:
|
|
if f"REFLECTANCE_MULT_BAND_{band_number}" in line:
|
|
variable, value = line.split(" = ")
|
|
reflectance_mult = float(value.strip())
|
|
if f"REFLECTANCE_ADD_BAND_{band_number}" in line:
|
|
variable, value = line.split(" = ")
|
|
reflectance_add = float(value.strip())
|
|
if reflectance_mult is None or reflectance_add is None:
|
|
raise ValueError(f"Reflectance parameters not found for band {band_number} in metadata.")
|
|
return reflectance_mult, reflectance_add
|
|
|
|
def process_bands(band_paths, metadata_path, output_dir):
|
|
# Read metadata
|
|
with open(metadata_path, "r") as file:
|
|
metadata_lines = file.readlines()
|
|
|
|
# Extract sun elevation
|
|
sun_elevation = None
|
|
for line in metadata_lines:
|
|
if "SUN_ELEVATION" in line:
|
|
variable, value = line.split(" = ")
|
|
sun_elevation = float(value.strip())
|
|
break
|
|
|
|
if sun_elevation is None:
|
|
raise ValueError("Sun elevation not found in metadata.")
|
|
|
|
# Debugging sun elevation value
|
|
print(f"Sun Elevation: {sun_elevation}, Sun Elevation Radians: {math.radians(sun_elevation)}")
|
|
|
|
# Process each band
|
|
for band_path in band_paths:
|
|
band_number = int(re.search(r'_B(\d+)', band_path).group(1))
|
|
data, array = tif_to_array(band_path)
|
|
array = handle_nodata(array)
|
|
|
|
# Get reflectance parameters for the band
|
|
reflectance_mult, reflectance_add = get_reflectance_params(band_number, metadata_lines)
|
|
|
|
# Calculate reflectance for the band
|
|
reflectance = reflectance_calc(array, reflectance_mult, reflectance_add, sun_elevation)
|
|
|
|
# Create output directory if it doesn't exist
|
|
if not os.path.exists(output_dir):
|
|
os.makedirs(output_dir)
|
|
|
|
# Save Top of Atmosphere (TOA) reflectance for the band
|
|
output_path = get_output_path(output_dir, band_path, f"toa")
|
|
save_tif(reflectance, data, output_path)
|
|
|
|
# Print min and max for the reflectance band
|
|
print_min_max(reflectance, f"Band {band_number} Reflectance")
|
|
|
|
def main():
|
|
if len(sys.argv) < 4:
|
|
print("Usage: python3 script.py <metadata_path> <output_directory> <band_paths...>")
|
|
sys.exit(1)
|
|
|
|
metadata_path = sys.argv[1]
|
|
output_dir = sys.argv[2]
|
|
band_paths = sys.argv[3:]
|
|
|
|
process_bands(band_paths, metadata_path, output_dir)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|