satdetect-dev / scripts /make_roi_test_blocks.py
coderuday21's picture
Cursor
Deploy satdetect-dev with Priyanka audit/exception logs.
d70361b
Raw
History Blame Contribute Delete
3.27 kB
# -*- coding: utf-8 -*-
"""Crop small geo-aligned ROI blocks from a georeferenced before/after pair.
Prototypes the Wednesday ROI backend (windowed native crop + common-grid
alignment) AND produces ready-made small test pairs under data/roi_test/.
Usage:
venv\\Scripts\\python scripts\\make_roi_test_blocks.py <before.tif> <after.tif>
ROI blocks are fractional {x, y, w, h} in [0,1] of the images' geographic
overlap, so they're resolution-independent (the same contract the real ROI
feature will use).
"""
import sys
from pathlib import Path
import numpy as np
from PIL import Image
# Named test blocks (fractions of the geographic overlap). Tune as needed.
BLOCKS = {
"buildings": {"x": 0.34, "y": 0.66, "w": 0.16, "h": 0.16}, # the two new roofs
"buildings_wide": {"x": 0.28, "y": 0.52, "w": 0.32, "h": 0.34}, # roofs + car row
"parking": {"x": 0.30, "y": 0.10, "w": 0.24, "h": 0.22}, # cars only (nuisance)
}
def crop_block(before_path, after_path, roi, out_dir, name):
import rasterio
from rasterio.transform import from_origin
from rasterio.warp import Resampling, reproject, transform_bounds
with rasterio.open(before_path) as b, rasterio.open(after_path) as a:
b_in_a = transform_bounds(b.crs, a.crs, *b.bounds)
left = max(b_in_a[0], a.bounds.left)
bottom = max(b_in_a[1], a.bounds.bottom)
right = min(b_in_a[2], a.bounds.right)
top = min(b_in_a[3], a.bounds.top)
ow, oh = right - left, top - bottom
# fractional ROI -> geographic sub-box (y measured from the top)
gx0 = left + roi["x"] * ow
gx1 = gx0 + roi["w"] * ow
gy1 = top - roi["y"] * oh
gy0 = gy1 - roi["h"] * oh
res_x, res_y = a.res
W = max(1, int(round((gx1 - gx0) / res_x)))
H = max(1, int(round((gy1 - gy0) / res_y)))
dst_tf = from_origin(gx0, gy1, res_x, res_y)
def warp(src):
out = np.zeros((3, H, W), dtype=np.uint8)
for i in range(3):
reproject(
source=rasterio.band(src, i + 1), destination=out[i],
src_transform=src.transform, src_crs=src.crs,
dst_transform=dst_tf, dst_crs=a.crs,
resampling=Resampling.bilinear,
)
return np.ascontiguousarray(out.transpose(1, 2, 0))
bb, aa = warp(b), warp(a)
out_dir.mkdir(parents=True, exist_ok=True)
Image.fromarray(bb).save(out_dir / f"{name}_before.png")
Image.fromarray(aa).save(out_dir / f"{name}_after.png")
print(f" {name:16s} {W}x{H}px ({W*res_x:.1f}m x {H*res_y:.1f}m) "
f"-> {out_dir / (name + '_{before,after}.png')}")
return bb, aa
def main():
if len(sys.argv) >= 3:
before, after = Path(sys.argv[1]), Path(sys.argv[2])
else:
before = Path(r"C:\Users\Priyanka\Downloads\1.tif")
after = Path(r"C:\Users\Priyanka\Downloads\2.tif")
out_dir = Path(__file__).resolve().parent.parent / "data" / "roi_test"
print(f"source before: {before.name}\nsource after : {after.name}\nout: {out_dir}")
for name, roi in BLOCKS.items():
crop_block(before, after, roi, out_dir, name)
print("done")
if __name__ == "__main__":
main()