| | |
| | | import json |
| | | from pathlib import Path |
| | | |
| | | import importlib.util |
| | | |
| | | |
| | | def load_demo(): |
| | | path = Path(__file__).with_name("run_change_detection.py") |
| | | spec = importlib.util.spec_from_file_location("change_detection_demo", path) |
| | | if spec is None or spec.loader is None: |
| | | raise RuntimeError("Unable to load change-detection vector helpers.") |
| | | module = importlib.util.module_from_spec(spec) |
| | | spec.loader.exec_module(module) |
| | | return module |
| | | |
| | | |
| | | def source_probability_path(scan_dir: Path) -> Path: |
| | | summary = json.loads((scan_dir / "scan_summary.json").read_text(encoding="utf-8")) |
| | | source_run = str(summary.get("source_run") or "") |
| | | output_root = scan_dir.parent.parent if scan_dir.parent.name == "parameter-scans" else scan_dir.parent |
| | | probability = output_root / "runs" / source_run / "change_probability.tif" |
| | | if not probability.is_file(): |
| | | probability = output_root / source_run / "change_probability.tif" |
| | | if not probability.is_file(): |
| | | raise FileNotFoundError("The source run probability raster is unavailable for vector export.") |
| | | return probability |
| | | |
| | | |
| | | def materialize(scan_dir: Path, candidates: list[str]) -> list[dict]: |
| | | from geoai import masks_to_vector |
| | | from rectangularize_vectors import rectangularize_vector |
| | | |
| | | demo = load_demo() |
| | | probability_path = source_probability_path(scan_dir) |
| | | results: list[dict] = [] |
| | | for candidate in candidates: |
| | | item_dir = scan_dir / candidate |
| | |
| | | raise FileNotFoundError(f"Missing scan result: {candidate}") |
| | | summary = json.loads(summary_path.read_text(encoding="utf-8")) |
| | | vector_path = item_dir / "changes.geojson" |
| | | vector = masks_to_vector( |
| | | str(mask_path), |
| | | str(vector_path), |
| | | simplify_tolerance=1.0, |
| | | mask_threshold=0.5, |
| | | min_object_area=int(summary["minimum_area_pixels"]), |
| | | ) |
| | | _, vector_count = demo.vectorize_cleaned_mask(mask_path, probability_path, vector_path) |
| | | rectangle_path = item_dir / "changes_rectangles.geojson" |
| | | rectangle_wgs84_path = item_dir / "changes_rectangles_wgs84.geojson" |
| | | rectangle_count = rectangularize_vector(vector_path, rectangle_path, rectangle_wgs84_path) |
| | | record = { |
| | | **summary, |
| | | "full_vector_feature_count": len(vector), |
| | | "full_vector_feature_count": vector_count, |
| | | "full_vector": vector_path.name, |
| | | "rectangle_vector_feature_count": rectangle_count, |
| | | "rectangle_vector": rectangle_path.name, |