Spaces:
Sleeping
Sleeping
| """R4-1 — intrinsic vs heuristic shading evaluation on the reference bundles. | |
| LOCAL evaluation tool (needs torch + the intrinsic package + model weights); | |
| not part of `make verify` — the CI-safe integration harness is | |
| verify_r4_intrinsic_sim.py. | |
| For each committed reference bundle this runs the REAL build_shade_map | |
| (heuristic) and build_intrinsic_shade_map (intrinsic) from app.py on the | |
| bundle's photo + floor mask, then writes a panel to verify_out/: | |
| original | heuristic shade applied to flat gray | intrinsic shade applied | |
| Applying the decoded shade to a flat gray floor is the most direct artifact | |
| view: any tile pattern, stain or halo visible in the gray region is shading | |
| transfer that would contaminate every replacement floor. | |
| Usage: python verify_r4_eval.py | |
| """ | |
| import base64 | |
| import io | |
| import json | |
| import os | |
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| HERE = os.path.dirname(os.path.abspath(__file__)) | |
| OUT = os.path.join(HERE, "verify_out") | |
| BUNDLES = [ | |
| ("desk", os.path.join(HERE, "data", "current_bundle.vizbundle.json")), | |
| ("kitchen", os.path.join(HERE, "data", "ref_kitchen.vizbundle.json")), | |
| ] | |
| # --- real implementations from app.py ---------------------------------------- | |
| src = open(os.path.join(HERE, "app.py")).read() | |
| ns = {"np": np, "cv2": cv2} | |
| for fn in [ | |
| "_adaptive_shade_range", | |
| "_encode_shade", | |
| "_dominant_period", | |
| "_suppress_periodic_shading", | |
| "build_shade_map", | |
| "build_intrinsic_shade_map", | |
| ]: | |
| start = src.index(f"def {fn}") | |
| end = src.index("\ndef ", start + 10) | |
| exec(compile(src[start:end], "app.py", "exec"), ns) | |
| def load_bundle(path): | |
| d = json.load(open(path)) | |
| img = np.asarray( | |
| Image.open(io.BytesIO(base64.b64decode(d["pixels"]))).convert("RGB") | |
| ) | |
| h, w = d["height"], d["width"] | |
| mask = np.zeros(w * h, bool) | |
| for s in d["segments"]: | |
| idx = np.frombuffer(base64.b64decode(s["mask"]), dtype=np.uint32) | |
| mask[idx] = True | |
| return img, mask.reshape(h, w).astype(np.uint8) | |
| def decode(enc, rng): | |
| lo, hi = rng | |
| return lo + enc.astype(np.float64) / 255.0 * (hi - lo) | |
| def shade_on_gray(img, mask, rel): | |
| """Composite: flat gray floor x shade over the original photo.""" | |
| out = img.astype(np.float64).copy() | |
| gray = 205.0 * np.clip(rel, 0.0, 2.0) | |
| for c in range(3): | |
| ch = out[:, :, c] | |
| ch[mask > 0] = np.clip(gray[mask > 0], 0, 255) | |
| return out.astype(np.uint8) | |
| def main(): | |
| os.makedirs(OUT, exist_ok=True) | |
| print("loading intrinsic model (v2)...", flush=True) | |
| # same headless-trust shim as app._load_intrinsic_model | |
| import torch.hub as _hub | |
| os.makedirs(_hub.get_dir(), exist_ok=True) | |
| tl = os.path.join(_hub.get_dir(), "trusted_list") | |
| if "rwightman_gen-efficientnet-pytorch" not in ( | |
| open(tl).read() if os.path.exists(tl) else "" | |
| ): | |
| with open(tl, "a") as f: | |
| f.write("rwightman_gen-efficientnet-pytorch\n") | |
| from intrinsic.pipeline import load_models | |
| ns["device"] = "cpu" | |
| ns["intrinsic_models"] = load_models("v2", device="cpu") | |
| print("model loaded.", flush=True) | |
| for name, path in BUNDLES: | |
| img, mask = load_bundle(path) | |
| h, w = mask.shape | |
| enc_h, rng_h = ns["build_shade_map"](img, mask) | |
| import time | |
| t0 = time.perf_counter() | |
| enc_i, rng_i = ns["build_intrinsic_shade_map"](img, mask) | |
| dt = time.perf_counter() - t0 | |
| if enc_h is None or enc_i is None: | |
| print(f" [{name}] FAILED: heuristic={enc_h is not None} intrinsic={enc_i is not None}") | |
| continue | |
| rel_h = decode(enc_h.reshape(h, w), rng_h) | |
| rel_i = decode(enc_i.reshape(h, w), rng_i) | |
| for label, rel in (("heuristic", rel_h), ("intrinsic", rel_i)): | |
| v = rel[mask > 0] | |
| print( | |
| f" [{name}] {label:9s} p5={np.percentile(v,5):.3f} " | |
| f"p50={np.percentile(v,50):.3f} p95={np.percentile(v,95):.3f} " | |
| f"range=({min(rng_h if label=='heuristic' else rng_i):.2f}," | |
| f"{max(rng_h if label=='heuristic' else rng_i):.2f})" | |
| ) | |
| print(f" [{name}] intrinsic runtime: {dt:.1f}s on cpu", flush=True) | |
| panel = np.concatenate( | |
| [img, shade_on_gray(img, mask, rel_h), shade_on_gray(img, mask, rel_i)], | |
| axis=1, | |
| ) | |
| scale = min(2200 / panel.shape[1], 1.0) | |
| if scale < 1.0: | |
| panel = cv2.resize( | |
| panel, (round(panel.shape[1] * scale), round(panel.shape[0] * scale)) | |
| ) | |
| out_path = os.path.join(OUT, f"r4_eval_{name}.png") | |
| Image.fromarray(panel).save(out_path) | |
| print(f" [{name}] panel: {out_path} (original | heuristic | intrinsic)") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |