Spaces:
Running
Running
| """ | |
| Materialize Delhi eval GeoTIFFs referenced in manifest.json (not stored in git). | |
| Priyanka's manifest lists library_sources/.../sentinel2_delhi_r{row}_c{col}.tif | |
| paths. Run this once after merging New/Priyanka to fetch those windows from the | |
| public Sentinel-2 COGs. | |
| python scripts/materialize_delhi_images.py | |
| python scripts/materialize_delhi_images.py --dry-run | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import os | |
| import re | |
| from pathlib import Path | |
| import numpy as np | |
| import rasterio | |
| from rasterio.windows import Window | |
| from rasterio.windows import transform as window_transform | |
| os.environ.setdefault("AWS_NO_SIGN_REQUEST", "YES") | |
| os.environ.setdefault("GDAL_DISABLE_READDIR_ON_OPEN", "EMPTY_DIR") | |
| ROOT = Path(__file__).resolve().parent.parent | |
| MANIFEST = ROOT / "docs" / "delhi_eval" / "manifest.json" | |
| BEFORE_URL = ( | |
| "https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/" | |
| "43/R/FM/2019/6/S2A_43RFM_20190629_1_L2A/TCI.tif" | |
| ) | |
| AFTER_URL = ( | |
| "https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/" | |
| "43/R/FM/2026/6/S2B_43RFM_20260617_0_L2A/TCI.tif" | |
| ) | |
| CELL_RE = re.compile(r"sentinel2_delhi_r(\d+)_c(\d+)\.tif$", re.I) | |
| def _parse_cell(path: Path) -> tuple[int, int, int] | None: | |
| m = CELL_RE.search(path.name) | |
| if not m: | |
| return None | |
| row, col = int(m.group(1)), int(m.group(2)) | |
| return row, col, 300 # Priyanka's default cell-px | |
| def _write_cell(ds, row: int, col: int, size: int, dest: Path, dry_run: bool) -> bool: | |
| if dest.is_file() and dest.stat().st_size > 0: | |
| return False | |
| if dry_run: | |
| print(f" would write {dest.relative_to(ROOT)}") | |
| return True | |
| dest.parent.mkdir(parents=True, exist_ok=True) | |
| window = Window(col, row, size, size) | |
| arr = ds.read([1, 2, 3], window=window) | |
| profile = dict( | |
| driver="GTiff", width=size, height=size, count=3, dtype="uint8", | |
| crs=ds.crs, transform=window_transform(window, ds.transform), compress="deflate", | |
| ) | |
| with rasterio.open(dest, "w", **profile) as dst: | |
| dst.write(arr) | |
| print(f" wrote {dest.relative_to(ROOT)}") | |
| return True | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) | |
| parser.add_argument("--manifest", type=str, default=str(MANIFEST)) | |
| parser.add_argument("--dry-run", action="store_true") | |
| args = parser.parse_args() | |
| manifest = json.loads(Path(args.manifest).read_text(encoding="utf-8")) | |
| jobs: list[tuple[Path, str, int, int, int]] = [] | |
| for pair in manifest.get("pairs", []): | |
| for key in ("before_path", "after_path"): | |
| rel = pair.get(key) | |
| if not rel: | |
| continue | |
| dest = ROOT / rel | |
| parsed = _parse_cell(dest) | |
| if parsed is None: | |
| continue | |
| row, col, size = parsed | |
| url = BEFORE_URL if "2019" in rel else AFTER_URL | |
| jobs.append((dest, url, row, col, size)) | |
| if not jobs: | |
| print("No Sentinel-2 cells to materialize.") | |
| return | |
| print(f"Materializing {len(jobs)} GeoTIFF window(s)...") | |
| written = 0 | |
| with rasterio.open(BEFORE_URL) as before_ds, rasterio.open(AFTER_URL) as after_ds: | |
| for dest, url, row, col, size in jobs: | |
| ds = before_ds if url == BEFORE_URL else after_ds | |
| if _write_cell(ds, row, col, size, dest, args.dry_run): | |
| written += 1 | |
| print(f"Done ({written} file(s) {'planned' if args.dry_run else 'written'}).") | |
| if __name__ == "__main__": | |
| main() | |