Add GIS-friendly exports and update contributor guide
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
import glob
|
||||
import math
|
||||
import os
|
||||
|
||||
from osgeo import gdal
|
||||
@@ -16,26 +15,68 @@ RESAMPLE = "bilinear"
|
||||
os.makedirs("work", exist_ok=True)
|
||||
os.makedirs(OUT_DIR, exist_ok=True)
|
||||
|
||||
# Open VRT
|
||||
ds = gdal.Open(VRT_PATH)
|
||||
if ds is None:
|
||||
raise SystemExit(f"Could not open {VRT_PATH}. Did you run gdalbuildvrt?")
|
||||
gdal.UseExceptions()
|
||||
|
||||
|
||||
def open_dataset(path, purpose):
|
||||
"""Open a dataset and fail fast with context."""
|
||||
try:
|
||||
ds = gdal.Open(path)
|
||||
except RuntimeError as exc:
|
||||
raise SystemExit(f"{purpose}: {exc}") from exc
|
||||
if ds is None:
|
||||
raise SystemExit(f"{purpose}: GDAL returned None for {path}")
|
||||
return ds
|
||||
|
||||
|
||||
def safe_remove(path):
|
||||
"""Remove a file if present; return True when deleted."""
|
||||
try:
|
||||
os.remove(path)
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
except OSError as exc:
|
||||
print(f"Warning: could not remove {path}: {exc}")
|
||||
return False
|
||||
|
||||
|
||||
def cleanup_aux_files():
|
||||
"""Clear GDAL sidecars and leftover temp files to keep the repo tidy."""
|
||||
patterns = [
|
||||
os.path.join("work", "*_tmp.tif"),
|
||||
os.path.join("work", "*_tmp.tif.aux.xml"),
|
||||
os.path.join("work", "*.aux.xml"),
|
||||
os.path.join(RAW_DIR, "*.aux.xml"),
|
||||
]
|
||||
removed = 0
|
||||
for pattern in patterns:
|
||||
for path in glob.glob(pattern):
|
||||
if safe_remove(path):
|
||||
removed += 1
|
||||
print(f"Cleanup removed {removed} temporary files/sidecars.")
|
||||
|
||||
|
||||
ds = open_dataset(VRT_PATH, f"Could not open {VRT_PATH}. Did you run gdalbuildvrt?")
|
||||
|
||||
band = ds.GetRasterBand(1)
|
||||
|
||||
# Strategy B: compute global min/max for CURRENT downloaded AOI (full scan for stability)
|
||||
gmin, gmax = band.ComputeRasterMinMax(False)
|
||||
print(f"GLOBAL_MIN={gmin}, GLOBAL_MAX={gmax}")
|
||||
|
||||
# Export manifest for Unity placement later
|
||||
manifest_path = os.path.join("export_unity", "tile_index.csv")
|
||||
with open(manifest_path, "w", encoding="utf-8") as f:
|
||||
f.write("tile_id,xmin,ymin,xmax,ymax,global_min,global_max,out_res\n")
|
||||
|
||||
skipped = 0
|
||||
written = 0
|
||||
|
||||
for tif in sorted(glob.glob(os.path.join(RAW_DIR, "*.tif"))):
|
||||
tds = gdal.Open(tif)
|
||||
if tds is None:
|
||||
print(f"Skipping unreadable: {tif}")
|
||||
try:
|
||||
tds = open_dataset(tif, f"Skipping unreadable {tif}")
|
||||
except SystemExit as exc:
|
||||
print(exc)
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
gt = tds.GetGeoTransform()
|
||||
@@ -61,17 +102,36 @@ with open(manifest_path, "w", encoding="utf-8") as f:
|
||||
srcNodata=-9999,
|
||||
dstNodata=gmin, # fill nodata with global min to avoid deep pits
|
||||
)
|
||||
gdal.Warp(tmp_path, ds, options=warp_opts)
|
||||
try:
|
||||
gdal.Warp(tmp_path, ds, options=warp_opts)
|
||||
except RuntimeError as exc:
|
||||
print(f"Warp failed for {tile_id}: {exc}")
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
# Scale to UInt16 (0..65535) using Strategy-B global min/max
|
||||
trans_opts = gdal.TranslateOptions(
|
||||
outputType=gdal.GDT_UInt16,
|
||||
scaleParams=[(gmin, gmax, 0, 65535)],
|
||||
format="PNG",
|
||||
creationOptions=["WORLDFILE=YES"], # emit .wld so GIS tools place tiles correctly
|
||||
)
|
||||
gdal.Translate(out_path, tmp_path, options=trans_opts)
|
||||
try:
|
||||
gdal.Translate(out_path, tmp_path, options=trans_opts)
|
||||
except RuntimeError as exc:
|
||||
print(f"Translate failed for {tile_id}: {exc}")
|
||||
skipped += 1
|
||||
continue
|
||||
safe_remove(tmp_path)
|
||||
safe_remove(f"{tmp_path}.aux.xml")
|
||||
|
||||
f.write(f"{tile_id},{xmin},{ymin},{xmax},{ymax},{gmin},{gmax},{OUT_RES}\n")
|
||||
print(f"Wrote {out_path}")
|
||||
written += 1
|
||||
|
||||
print(f"Manifest: {manifest_path}")
|
||||
print(f"Summary: wrote {written} tiles; skipped {skipped}.")
|
||||
cleanup_aux_files()
|
||||
|
||||
if skipped:
|
||||
raise SystemExit(1)
|
||||
|
||||
Reference in New Issue
Block a user