room-visualizer / verify_n2_sim.py
GitHub Actions
Deploy from GitHub commit e5655c5148bdf9ff2f4a5d17d6cefe1ca9563ba1
6da2618
Raw
History Blame Contribute Delete
3.57 kB
"""N2 β€” fill_enclosed_islands must absorb accent-tile islands even when
segmentation noise bridges them to a large protected hole or sprinkles a few
protected pixels over them (the room-4 blue accent tile escaped both ways).
Cases:
1. plain enclosed island -> filled (regression)
2. island bridged (1px chain) to big mat hole -> filled (N2 fix)
3. island 30% covered by protect (chair leg) -> kept (guard)
4. island with 2 stray protected pixels (~1%) -> filled (N2 fix)
5. hole touching the image border -> kept (guard)
6. large hole (over max_area) -> kept (guard)
"""
import cv2
import numpy as np
# --- extract the real implementation from app.py ---------------------------
src = open("app.py").read()
ns = {"np": np, "cv2": cv2}
start = src.index("def fill_enclosed_islands")
end = src.index("\ndef ", start + 10)
exec(compile(src[start:end], "app.py", "exec"), ns)
fill_enclosed_islands = ns["fill_enclosed_islands"]
def main():
h, w = 400, 600
mask = np.ones((h, w), np.uint8)
protect = np.zeros((h, w), np.uint8)
# 1. plain island, 20x20
mask[50:70, 50:70] = 0
# 2. island 16x16 + 1px bridge to a big protected mat hole (90x40)
mask[200:240, 150:240] = 0 # mat hole
protect[200:240, 150:240] = 1 # mat is occluder-protected
mask[210:226, 260:276] = 0 # accent island nearby
mask[217, 240:260] = 0 # 1px bridge connecting them
# 3. island 20x20 with 30% protect coverage (a real object remnant)
mask[300:320, 60:80] = 0
protect[300:320, 60:66] = 1 # 6/20 columns = 30%
# 4. island 20x20 with 2 stray protected pixels
mask[80:100, 400:420] = 0
protect[85, 405] = 1
protect[92, 412] = 1
# 5. border-touching hole
mask[0:30, 500:540] = 0
# 6. big hole, over max_area
mask[280:360, 380:560] = 0 # 80x180 = 14400
out = fill_enclosed_islands(mask, protect, max_area=2000)
# 7. final unprotected sweep (N2b): a fully-protected small island β€” a
# pattern feature the segmenter calls an object β€” must fill when the sweep
# runs without class protection on the finished surface, while the big
# protected mat hole still survives via max_area.
mask7 = np.ones((400, 600), np.uint8)
mask7[150:175, 300:330] = 0 # "blue accent tile" island
mask7[200:240, 100:190] = 0 # mat-sized hole (3600 px)
out7 = fill_enclosed_islands(mask7, None, max_area=1000)
checks = [
("1 plain island filled", bool((out[52:68, 52:68] == 1).all())),
("2 bridged island filled", bool((out[212:224, 262:274] == 1).all())),
("2 mat hole kept", bool((out[205:235, 155:235] == 0).all())),
("3 protected island kept", bool((out[302:318, 62:78] == 0).all())),
("4 stray-pixel island filled", bool((out[82:98, 402:418] == 1).all())),
("5 border hole kept", bool((out[2:28, 502:538] == 0).all())),
("6 big hole kept", bool((out[285:355, 385:555] == 0).all())),
("7 final sweep fills pattern island", bool((out7[152:173, 302:328] == 1).all())),
("7 final sweep keeps big hole", bool((out7[205:235, 105:185] == 0).all())),
]
ok = True
for name, passed in checks:
print(f" [{'PASS' if passed else 'FAIL'}] {name}")
ok &= passed
print("\n" + ("ALL N2 CHECKS PASSED" if ok else "N2 CHECKS FAILED"))
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())