| |
| """Write an auditable preflight and multiview verification report for one run.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import sys |
| from pathlib import Path |
|
|
| import numpy as np |
| from PIL import Image |
|
|
| PROJECT_ROOT = Path(__file__).resolve().parents[1] |
| sys.path.insert(0, str(PROJECT_ROOT)) |
|
|
| from accessibilityamodal.verification import build_verification |
|
|
|
|
| def read_json(path: Path) -> dict: |
| return json.loads(path.read_text(encoding="utf-8")) |
|
|
|
|
| def read_mask(path: Path) -> np.ndarray: |
| mask = np.asarray(Image.open(path).convert("L")) > 127 |
| return mask |
|
|
|
|
| def find_sam_quality(run_dir: Path, sample_id: str) -> dict | None: |
| for root in (run_dir / "01_sam3", run_dir / "01_sam3_retry"): |
| path = root / "samples" / sample_id / "quality.json" |
| if path.is_file(): |
| return read_json(path) |
| return None |
|
|
|
|
| def find_reviewed_visible_metadata(run_dir: Path) -> dict | None: |
| path = run_dir / "01_reviewed_visible" / "metadata.json" |
| return read_json(path) if path.is_file() else None |
|
|
|
|
| def main() -> int: |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("--run-dir", required=True) |
| parser.add_argument("--sample-id", required=True) |
| parser.add_argument("--category", required=True, choices=["curb_cut", "ramp", "stairs", "tactile_paving", "walkway"]) |
| parser.add_argument("--output", default=None) |
| parser.add_argument("--preflight-only", action="store_true") |
| parser.add_argument("--print-decision", action="store_true") |
| args = parser.parse_args() |
|
|
| run_dir = Path(args.run_dir).expanduser().resolve() |
| masks_dir = run_dir / "02_masks" |
| visible = read_mask(masks_dir / "target_visible.png") |
| amodal = read_mask(masks_dir / "target_amodal.png") |
| hidden = read_mask(masks_dir / "hidden.png") |
| obstacle = read_mask(masks_dir / "obstacle.png") |
| geometry_path = run_dir / "04_3d_completion" / "geometry" / "geometry_manifest.json" |
| geometry = None if args.preflight_only or not geometry_path.is_file() else read_json(geometry_path) |
| learned_dir = None |
| if not args.preflight_only: |
| learned_candidates = ( |
| run_dir / "accessibility3d", |
| run_dir / "04_3d_completion" / "visual_candidate", |
| ) |
| learned_dir = next( |
| (candidate for candidate in learned_candidates if candidate.is_dir()), |
| learned_candidates[0], |
| ) |
| report = build_verification( |
| sample_id=args.sample_id, |
| category=args.category, |
| visible_mask=visible, |
| amodal_mask=amodal, |
| hidden_mask=hidden, |
| obstacle_mask=obstacle, |
| sam3_quality=find_sam_quality(run_dir, args.sample_id), |
| reviewed_visible_metadata=find_reviewed_visible_metadata(run_dir), |
| geometry_manifest=geometry, |
| learned_dir=learned_dir, |
| ) |
| output = ( |
| Path(args.output).expanduser().resolve() |
| if args.output |
| else run_dir / "05_quality_checks" / "verification.json" |
| ) |
| output.parent.mkdir(parents=True, exist_ok=True) |
| output.write_text(json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) + "\n", encoding="utf-8") |
| if args.print_decision: |
| print(report["decision"]) |
| else: |
| print(json.dumps({"output": str(output), "decision": report["decision"], "gate": report["gate"]}, ensure_ascii=False)) |
| return 0 |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|