"""R1-1 — metric depth certification (local harness; needs torch+transformers and reference room photos — not part of `make verify`, which uses precomputed bundles). Runs the configured depth checkpoint on reference room photos and validates that the output is genuinely METRIC: 1. floor depth range plausible for an interior (p5/p95 within 0.3-20 m) 2. ground-plane consistency: on a floor plane, inverse depth is linear in image row (1/Z = (y - y_horizon) / (h_cam * f)); the fit must hold (R^2 >= 0.9 over floor rows) 3. absolute scale: the camera height recovered from that fit's slope (h = 1 / (slope * f), f ~ image width) must land in 0.7-2.5 m — the handheld-phone band. This is the automated equivalent of the backlog's "door height ~2.0 m +/-15%" check: both test absolute metric scale, but this one needs no manual annotation. Usage: python verify_r1_metric.py [more photos...] """ import sys import cv2 import numpy as np import torch from PIL import Image from transformers import AutoImageProcessor, AutoModelForDepthEstimation # single source of truth: read the configured model + metric predicate from app.py src = open("app.py").read() ns = {} start = src.index("def depth_model_is_metric") end = src.index("\nENABLE_DEPTH", start) exec(compile(src[start:end], "app.py", "exec"), ns) import re MODEL = re.search(r'depth_model_name",\s*\n(?:\s*#.*\n)*\s*"([^"]+)"', src).group(1) depth_model_is_metric = ns["depth_model_is_metric"] FLOOR_FRAC = 0.45 # treat the bottom 45% of the frame as floor-dominated def run_depth(img): processor = run_depth.processor model = run_depth.model inputs = processor(images=img, return_tensors="pt") with torch.no_grad(): out = model(**inputs) depth = torch.nn.functional.interpolate( out.predicted_depth.unsqueeze(1), size=(img.height, img.width), mode="bicubic", align_corners=False, ).squeeze().numpy() return cv2.GaussianBlur(depth.astype(np.float32), (0, 0), sigmaX=3) def main(): photos = sys.argv[1:] if not photos: print(__doc__) return 2 print(f"model: {MODEL}") if not depth_model_is_metric(MODEL): print("!! configured model is not metric — R1-1 not in effect") return 1 print("loading checkpoint...") run_depth.processor = AutoImageProcessor.from_pretrained(MODEL) run_depth.model = AutoModelForDepthEstimation.from_pretrained(MODEL).eval() ok = True for path in photos: img = Image.open(path).convert("RGB") if max(img.size) > 1280: s = 1280 / max(img.size) img = img.resize((round(img.width * s), round(img.height * s)), Image.LANCZOS) w, h = img.size depth = run_depth(img) floor = depth[int(h * (1 - FLOOR_FRAC)):, :] p5, p95 = np.percentile(floor, 5), np.percentile(floor, 95) range_ok = 0.3 <= p5 and p95 <= 20.0 # row-median inverse depth over the floor band; fit 1/Z = a*y + b ys = np.arange(int(h * (1 - FLOOR_FRAC)), h) inv = np.array([np.median(1.0 / np.maximum(depth[y], 0.05)) for y in ys]) a, b = np.polyfit(ys, inv, 1) pred = a * ys + b ss_res = float(np.sum((inv - pred) ** 2)) ss_tot = float(np.sum((inv - inv.mean()) ** 2)) + 1e-12 r2 = 1 - ss_res / ss_tot focal = float(w) # P0 convention: f ~ image width horizon_y = -b / a if abs(a) > 1e-12 else float("nan") # exact ground-plane relation for a pitched camera: # 1/Z = (sin(t)*f - cos(t)*y') / (h*f) -> h = cos(t) / (a*f) # with pitch t recovered from the fitted horizon row. pitch = np.arctan2(h / 2 - horizon_y, focal) cam_h = float(np.cos(pitch) / (a * focal)) if a > 1e-9 else float("inf") plane_ok = r2 >= 0.90 and a > 0 height_ok = 0.7 <= cam_h <= 2.5 passed = range_ok and plane_ok and height_ok ok &= passed print( f" [{'PASS' if passed else 'FAIL'}] {path.split('/')[-1]}: " f"floor p5-p95 = {p5:.2f}-{p95:.2f} m | invZ-fit R2={r2:.3f} | " f"camera height = {cam_h:.2f} m | horizon y = {horizon_y:.0f}/{h}" ) if not range_ok: print(" !! floor depth outside 0.3-20 m") if not plane_ok: print(" !! inverse depth not linear in row — not plane-consistent") if not height_ok: print(" !! camera height outside handheld band 0.7-2.5 m") print("\n" + ("ALL R1-1 METRIC CHECKS PASSED" if ok else "R1-1 METRIC CHECKS FAILED")) return 0 if ok else 1 if __name__ == "__main__": raise SystemExit(main())