Spaces:
Sleeping
Sleeping
| 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() |