ESA-Combination / app.py
Menezes
Upload app.py
52eabca verified
import os
import zipfile
import tempfile
import uuid
import rasterio
import numpy as np
import matplotlib.pyplot as plt
import gradio as gr
from rasterio.enums import Resampling
def generate_temp_path(suffix=".tif"):
return os.path.join(tempfile.gettempdir(), f"{uuid.uuid4().hex}{suffix}")
def read_band(path):
with rasterio.open(path) as src:
return src.read(1).astype(np.float32), src.profile
def resample_to_10m(band_path, ref_shape, ref_transform):
with rasterio.open(band_path) as src:
data = src.read(
out_shape=(1, ref_shape[0], ref_shape[1]),
resampling=Resampling.bilinear
)
return data[0].astype(np.float32)
def normalize(array):
array /= 10000.0
return np.clip(array, 0, 1)
def array_to_plot(img, title, cmap=None):
fig = plt.figure(figsize=(6, 6))
if cmap:
plt.imshow(img, cmap=cmap)
plt.colorbar()
else:
plt.imshow(img)
plt.title(title)
plt.axis('off')
return fig
def save_tif(path, array, profile, count=3):
profile = profile.copy()
profile.update({
'driver': 'GTiff',
'count': count,
'dtype': rasterio.float32,
'compress': 'deflate',
'predictor': 2,
'tiled': True,
'blockxsize': 512,
'blockysize': 512
})
with rasterio.open(path, 'w', **profile) as dst:
if count == 1:
dst.write(array, 1)
else:
for i in range(count):
dst.write(array[:, :, i], i + 1)
def process_visualization(zip_file_path, vis_type):
with tempfile.TemporaryDirectory() as temp_dir:
with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
zip_ref.extractall(temp_dir)
dirs = [d for d in os.listdir(temp_dir) if d.endswith(".SAFE")]
if not dirs:
raise Exception(".SAFE folder not found inside the zip file.")
extract_dir = os.path.join(temp_dir, dirs[0])
granule_dir = os.path.join(extract_dir, "GRANULE")
granule_path = [os.path.join(granule_dir, d) for d in os.listdir(granule_dir) if d.startswith("L2A_")][0]
img_data_dir = os.path.join(granule_path, "IMG_DATA")
res_paths = {
"R10m": os.path.join(img_data_dir, "R10m"),
"R20m": os.path.join(img_data_dir, "R20m")
}
# Geometry reference
b4, profile = read_band(os.path.join(res_paths["R10m"], [f for f in os.listdir(res_paths["R10m"]) if "_B04" in f][0]))
if vis_type == "Natural Color (B4, B3, B2)":
b2, _ = read_band(os.path.join(res_paths["R10m"], [f for f in os.listdir(res_paths["R10m"]) if "_B02" in f][0]))
b3, _ = read_band(os.path.join(res_paths["R10m"], [f for f in os.listdir(res_paths["R10m"]) if "_B03" in f][0]))
rgb = np.stack([b4, b3, b2], axis=-1)
rgb_plot = array_to_plot(normalize(rgb), vis_type)
tif_path = generate_temp_path(".tif")
save_tif(tif_path, rgb, profile, count=3)
return rgb_plot, tif_path
elif vis_type == "False Color Vegetation (B8, B4, B3)":
b3, _ = read_band(os.path.join(res_paths["R10m"], [f for f in os.listdir(res_paths["R10m"]) if "_B03" in f][0]))
b8, _ = read_band(os.path.join(res_paths["R10m"], [f for f in os.listdir(res_paths["R10m"]) if "_B08" in f][0]))
fcv = np.stack([b8, b4, b3], axis=-1)
fcv_plot = array_to_plot(normalize(fcv), vis_type)
tif_path = generate_temp_path(".tif")
save_tif(tif_path, fcv, profile, count=3)
return fcv_plot, tif_path
elif vis_type == "False Color SWIR (B12, B8, B4)":
b8, _ = read_band(os.path.join(res_paths["R10m"], [f for f in os.listdir(res_paths["R10m"]) if "_B08" in f][0]))
b12_path = os.path.join(res_paths["R20m"], [f for f in os.listdir(res_paths["R20m"]) if "_B12" in f][0])
b12 = resample_to_10m(b12_path, b4.shape, profile["transform"])
fcswir = np.stack([b12, b8, b4], axis=-1)
swir_plot = array_to_plot(normalize(fcswir), vis_type)
tif_path = generate_temp_path(".tif")
save_tif(tif_path, fcswir, profile, count=3)
return swir_plot, tif_path
elif vis_type == "NDVI":
b8, _ = read_band(os.path.join(res_paths["R10m"], [f for f in os.listdir(res_paths["R10m"]) if "_B08" in f][0]))
ndvi = (b8 - b4) / (b8 + b4 + 1e-6)
ndvi_plot = array_to_plot(ndvi, "NDVI", cmap='RdYlGn')
tif_path = generate_temp_path(".tif")
save_tif(tif_path, ndvi, profile, count=1)
return ndvi_plot, tif_path
else:
raise ValueError("Invalid visualization type.")
# === Gradio Interface ===
demo = gr.Interface(
fn=process_visualization,
inputs=[
gr.File(label="Sentinel-2 Archive (.zip)", type="filepath"),
gr.Dropdown(
choices=[
"Natural Color (B4, B3, B2)",
"False Color Vegetation (B8, B4, B3)",
"False Color SWIR (B12, B8, B4)",
"NDVI"
],
label="Visualization Type"
)
],
outputs=[
gr.Plot(label="Preview"),
gr.File(label="Download GeoTIFF")
],
title="Sentinel-2 Viewer + GeoTIFF Export",
description="Upload a .SAFE.zip file, choose a visualization type, and download the corresponding GeoTIFF file."
)
if __name__ == "__main__":
demo.launch()