room-visualizer / verify_r4_intrinsic_sim.py
GitHub Actions
Deploy from GitHub commit 0b4a46d6249523704b10c03464426d0ab07f81cd
0d1fbc6
Raw
History Blame Contribute Delete
9.26 kB
"""R4-1 β€” intrinsic shading integration certification (CI-safe: fake model,
no torch).
build_intrinsic_shade_map is fed a synthetic scene with a KNOWN decomposition:
a checker/stripe albedo (the old floor's pattern β€” must NOT transfer) times a
smooth linear shading field (a daylight gradient + a soft contact shadow β€”
MUST transfer). The intrinsic.pipeline module is faked in sys.modules to
return the ground-truth shading, so what's certified is the integration:
key handling, inverse-encoding decode, boundary fill, linear->display
conversion, normalisation, encoding, and every fallback path.
Checks:
1. engages on a clean scene and reproduces the display-space shading on the
floor interior (the lighting survives)
2. albedo-blind: the checker pattern's contrast does not reach the output
(the artifact class N3 patched β€” patterns, any orientation β€” is dead
by construction)
3. boundary-safe: bright non-floor shading (furniture) does not halo into
the floor edge band (the desk/curtain light-leak)
4. inverse-shading key ('inv_shd') is decoded, not used raw
5. fallbacks: no model / pipeline raises / no shading key / empty mask
all return (None, default) so the caller falls back to the heuristic
"""
import sys
import types
import cv2
import numpy as np
H, W = 480, 640
GAMMA = 2.2
# --- fake intrinsic.pipeline BEFORE extracting app code ----------------------
_fake_results = {}
def _fake_run_pipeline(models, img, device=None):
if isinstance(_fake_results.get("exc"), Exception):
raise _fake_results["exc"]
return dict(_fake_results)
_pkg = types.ModuleType("intrinsic")
_mod = types.ModuleType("intrinsic.pipeline")
_mod.run_pipeline = _fake_run_pipeline
_pkg.pipeline = _mod
sys.modules["intrinsic"] = _pkg
sys.modules["intrinsic.pipeline"] = _mod
# --- real implementations from app.py ----------------------------------------
src = open("app.py").read()
ns = {"np": np, "cv2": cv2, "intrinsic_models": object(), "device": "cpu"}
for fn in ["_adaptive_shade_range", "_encode_shade", "repair_intrinsic_floor_shading", "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)
build_intrinsic_shade_map = ns["build_intrinsic_shade_map"]
def scene():
"""Floor = lower half. Albedo checker x smooth linear shading."""
yy, xx = np.mgrid[0:H, 0:W].astype(np.float64)
mask = np.zeros((H, W), np.uint8)
mask[H // 2 :, :] = 1
albedo = np.where(((xx // 40).astype(int) + (yy // 40).astype(int)) % 2 == 0, 0.75, 0.35)
shading = 0.35 + 0.55 * (yy / H)
blob = 0.45 * np.exp(-(((xx - W * 0.7) / 70.0) ** 2 + ((yy - H * 0.8) / 50.0) ** 2))
shading = np.clip(shading - blob, 0.05, 1.5)
img_lin = albedo * shading
img = (np.clip(img_lin, 0, 1) ** (1 / GAMMA) * 255).astype(np.uint8)
img = np.stack([img] * 3, axis=2)
return img, mask, shading, albedo
def decode(enc, rng):
lo, hi = rng
return lo + enc.astype(np.float64) / 255.0 * (hi - lo)
def expected_display(shading, mask):
med = float(np.median(shading[mask > 0]))
return np.power(np.clip(shading / med, 0, None), 1 / GAMMA)
def main():
ok = True
img, mask, shading, albedo = scene()
# 1 β€” engages + reproduces display-space shading on the interior
_fake_results.clear()
_fake_results["gry_shd"] = shading.astype(np.float32)
enc, rng = build_intrinsic_shade_map(img, mask)
if enc is None:
print(" [FAIL] did not engage on a clean scene")
print("\nR4-1 SIM CHECKS FAILED")
return 1
rel = decode(enc.reshape(H, W), rng)
want = expected_display(shading, mask)
interior = cv2.erode(mask, np.ones((41, 41), np.uint8)) > 0
# the encoder clips to the adaptive range; compare where 'want' is in-range
in_rng = (want > min(rng) + 0.02) & (want < max(rng) - 0.02)
sel = interior & in_rng
err = np.abs(rel[sel] - want[sel])
good = float(err.mean()) < 0.02 and float(np.percentile(err, 99)) < 0.06
print(f" [{'PASS' if good else 'FAIL'}] lighting survives: mean err {err.mean():.4f}, "
f"p99 {np.percentile(err, 99):.4f} (display space)")
ok &= good
# 2 β€” albedo-blind: checker cells must not differ in the output
cell_a = sel & (((np.indices((H, W))[1] // 40) + (np.indices((H, W))[0] // 40)) % 2 == 0)
cell_b = sel & ~cell_a
# compare horizontally adjacent same-row cells via local means
diff = abs(float(rel[cell_a].mean()) - float(rel[cell_b].mean()))
alb_contrast = abs(float(albedo[cell_a].mean()) - float(albedo[cell_b].mean()))
good = diff < 0.01 and alb_contrast > 0.3
print(f" [{'PASS' if good else 'FAIL'}] albedo-blind: checker leakage {diff:.4f} "
f"(albedo contrast {alb_contrast:.2f} in, <0.01 out)")
ok &= good
# 3 β€” boundary-safe: blazing-bright furniture shading above the floor
bright = shading.copy()
bright[mask == 0] = 5.0
_fake_results.clear()
_fake_results["gry_shd"] = bright.astype(np.float32)
enc_b, rng_b = build_intrinsic_shade_map(img, mask)
rel_b = decode(enc_b.reshape(H, W), rng_b)
edge_band = (mask > 0) & (np.indices((H, W))[0] < H // 2 + 12)
band_sel = edge_band & in_rng
err_b = np.abs(rel_b[band_sel] - want[band_sel])
good = float(err_b.mean()) < 0.04 and float(err_b.max()) < 0.12
print(f" [{'PASS' if good else 'FAIL'}] boundary-safe: edge-band err mean "
f"{err_b.mean():.4f}, max {err_b.max():.4f} with 5x furniture shading")
ok &= good
# 4 β€” inverse-shading key decoded
_fake_results.clear()
_fake_results["inv_shd"] = (1.0 / (shading + 1.0)).astype(np.float32)
enc_i, rng_i = build_intrinsic_shade_map(img, mask)
good = enc_i is not None
if good:
rel_i = decode(enc_i.reshape(H, W), rng_i)
err_i = np.abs(rel_i[sel] - want[sel])
good = float(err_i.mean()) < 0.02
print(f" [{'PASS' if good else 'FAIL'}] inv_shd decoded: mean err {err_i.mean():.4f}")
else:
print(" [FAIL] inv_shd: did not engage")
ok &= good
# 5 β€” R4-1 v2 glare repair: the model inverts specular glare into a dark
# blob (2026-06-12 dataset, room 2). Photo: bright glare patch on the
# floor; model: shading collapses there. The repaired output must sit at
# the ambient level, not the dip β€” while the REAL shadow (photo-dark,
# check 1) keeps transferring.
yy, xx = np.indices((H, W)).astype(np.float64)
glare_zone = ((xx - W * 0.3) ** 2 + ((yy - H * 0.75) * 1.4) ** 2) < 45.0 ** 2
img_g = img.copy()
img_g[glare_zone & (mask > 0)] = 250
inverted = shading.copy()
inverted[glare_zone & (mask > 0)] = 0.12
_fake_results.clear()
_fake_results["gry_shd"] = inverted.astype(np.float32)
enc_g, rng_g = build_intrinsic_shade_map(img_g, mask)
rel_g = decode(enc_g.reshape(H, W), rng_g)
core = glare_zone & interior
ring = (~glare_zone) & interior & (
((xx - W * 0.3) ** 2 + ((yy - H * 0.75) * 1.4) ** 2) < 90.0 ** 2
)
dip = float(rel_g[ring].mean()) - float(rel_g[core].mean())
good = dip < 0.06
print(f" [{'PASS' if good else 'FAIL'}] glare repair: blob dip {dip:.3f} "
f"below ambient (<0.06; was an inverted dark blob)")
ok &= good
# 6 β€” R4-1 v2 grout-ghost removal: thin dark lines in the model's
# shading (the OLD floor's grout grooves) must not reach the output;
# the wide soft shadow survives via check 1.
ghost = shading.copy()
line_mask = (mask > 0) & (((xx + 2 * yy) % 60) < 3)
ghost[line_mask] *= 0.72
_fake_results.clear()
_fake_results["gry_shd"] = ghost.astype(np.float32)
enc_l, rng_l = build_intrinsic_shade_map(img, mask)
rel_l = decode(enc_l.reshape(H, W), rng_l)
on_line = line_mask & sel
off_line = (~line_mask) & sel
leak = abs(float(rel_l[on_line].mean()) - float(rel_l[off_line].mean()))
good = leak < 0.02
print(f" [{'PASS' if good else 'FAIL'}] grout-ghost removal: line leakage "
f"{leak:.4f} (<0.02; lines were 28% deep)")
ok &= good
# 7 β€” fallback paths all return None (caller then uses the heuristic)
cases = []
_fake_results.clear()
_fake_results["albedo_only"] = shading.astype(np.float32)
cases.append(("no shading key", build_intrinsic_shade_map(img, mask)[0] is None))
_fake_results.clear()
_fake_results["exc"] = RuntimeError("model exploded")
cases.append(("pipeline raises", build_intrinsic_shade_map(img, mask)[0] is None))
_fake_results.clear()
_fake_results["gry_shd"] = shading.astype(np.float32)
cases.append(("empty mask", build_intrinsic_shade_map(img, np.zeros_like(mask))[0] is None))
saved = ns["intrinsic_models"]
ns["intrinsic_models"] = None
cases.append(("model not loaded", build_intrinsic_shade_map(img, mask)[0] is None))
ns["intrinsic_models"] = saved
for label, passed in cases:
print(f" [{'PASS' if passed else 'FAIL'}] fallback: {label} -> None")
ok &= passed
print("\n" + ("ALL R4-1 SIM CHECKS PASSED" if ok else "R4-1 SIM CHECKS FAILED"))
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())