File size: 8,669 Bytes
a4f876a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190bd61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4f876a
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
"""R1-5 β€” MoGe point-map plane fit certification (CI-safe: synthetic point
map, no torch, no model).

A ground plane is constructed analytically: rays through a known camera K
intersect a tilted floor plane, giving a perfect metric point map. The only
thing under test is the REAL plane_homography_from_moge from app.py: it must
recover a metre-unit homography (1 m in the world measures 1.0 in plane
space), report geometrySource=moge-plane, honour the model's own intrinsics
(passed normalized, the MoGe convention), and abstain on wall-dominant fits,
noise, and missing geometry.
"""

import numpy as np
import cv2  # noqa: F401  (the extracted code uses np only, cv2 kept for parity)

IMG_W, IMG_H = 640, 480
F_PX = 612.0  # deliberately NOT ~width: the old pinhole f~w guess would be wrong

# --- real implementation from app.py ------------------------------------------
src = open("app.py").read()
ns = {"np": np, "cv2": cv2}
for fn in ("def pixel_intrinsics_from_model", "def plane_homography_from_moge"):
    start = src.index(fn)
    end = src.index("\n\ndef ", start + 10)
    exec(compile(src[start:end], "app.py", "exec"), ns)
plane_homography_from_moge = ns["plane_homography_from_moge"]


def synthetic_geometry(pitch_deg=35.0, cam_h=1.5, noise=0.0, wall=False):
    """Perfect metric point map of a plane seen by a pitched camera.
    Camera frame: y down, z forward; camera pitched down by pitch_deg.
    Floor: world plane 1.5 m below the camera. Wall: vertical plane 3 m
    ahead (normal mostly horizontal β€” must trip the floor-sanity gate)."""
    pitch = np.deg2rad(pitch_deg)
    cp, sp = np.cos(pitch), np.sin(pitch)
    R = np.array([[1, 0, 0], [0, cp, -sp], [0, sp, cp]])  # world -> camera
    if wall:
        n = R @ np.array([0.0, 0.0, -1.0])
        c0 = R @ np.array([0.0, 0.0, 3.0])
    else:
        n = R @ np.array([0.0, -1.0, 0.0])
        c0 = R @ np.array([0.0, cam_h, 0.0])
    d = float(n @ c0)

    K = np.array([[F_PX, 0, IMG_W / 2.0], [0, F_PX, IMG_H / 2.0], [0, 0, 1.0]])
    Kinv = np.linalg.inv(K)
    uu, vv = np.meshgrid(np.arange(IMG_W, dtype=np.float64), np.arange(IMG_H, dtype=np.float64))
    rays = np.stack([uu, vv, np.ones_like(uu)], axis=-1) @ Kinv.T
    denom = rays @ n
    with np.errstate(divide="ignore", invalid="ignore"):
        t = np.where(np.abs(denom) > 1e-9, d / denom, np.nan)
    points = rays * t[..., None]
    ok = np.isfinite(t) & (t > 0.5) & (t < 30.0) & (points[..., 2] > 0.05)

    rng = np.random.default_rng(3)
    if noise > 0:
        points = points + rng.normal(0, noise, points.shape)

    mask = ok & (vv > IMG_H * 0.45)  # floor occupies the lower image
    pts = points.astype(np.float32)
    pts[~ok] = np.nan
    K_norm = K.copy()
    K_norm[0, 0] /= IMG_W
    K_norm[0, 2] /= IMG_W
    K_norm[1, 1] /= IMG_H
    K_norm[1, 2] /= IMG_H
    return {
        "provider": "moge-2",
        "points": pts,
        "validMask": ok,
        "intrinsics": K_norm.astype(np.float32),
    }, mask.astype(np.uint8), points, ok


def main():
    ok_all = True

    # 1 β€” recovers a metre-unit plane chart from a clean point map
    geometry, mask, points, ok = synthetic_geometry()
    fitted = plane_homography_from_moge(geometry, mask, IMG_W, IMG_H)
    good = fitted is not None
    if good:
        H = np.asarray(fitted[0], np.float64).reshape(3, 3)
        plane = fitted[1]
        # measure: random floor pixel pairs, 3D distance vs plane distance
        ys, xs = np.nonzero((mask > 0) & ok)
        rng = np.random.default_rng(5)
        sel = rng.choice(len(xs), 3000, replace=False)
        i, j = sel[: len(sel) // 2], sel[len(sel) // 2 :]
        P = points[ys, xs]
        d3 = np.linalg.norm(P[i] - P[j], axis=1)
        den = H[2, 0] * xs + H[2, 1] * ys + H[2, 2]
        pa = (H[0, 0] * xs + H[0, 1] * ys + H[0, 2]) / den
        pb = (H[1, 0] * xs + H[1, 1] * ys + H[1, 2]) / den
        dp = np.hypot(pa[i] - pa[j], pb[i] - pb[j])
        far = dp > 0.3
        ratio = float(np.median(d3[far] / dp[far]))
        good = abs(ratio - 1.0) <= 0.02 and plane.get("geometrySource") == "moge-plane"
        print(f"  [{'PASS' if good else 'FAIL'}] clean point map -> metre chart "
              f"(3D/plane ratio {ratio:.4f}, source {plane.get('geometrySource')})")
    else:
        print("  [FAIL] clean point map: abstained")
    ok_all &= good

    # 2 β€” model intrinsics honoured: with f=612 vs the f~w=640 guess, a wrong
    # K would skew the ratio by ~5%; the gate above (2%) already proves K is
    # consumed, so here check the fit survives mild sensor noise
    geometry_n, mask_n, _, _ = synthetic_geometry(noise=0.01)
    fitted_n = plane_homography_from_moge(geometry_n, mask_n, IMG_W, IMG_H)
    print(f"  [{'PASS' if fitted_n is not None else 'FAIL'}] 1 cm point noise -> still fits")
    ok_all &= fitted_n is not None

    # 3 β€” wall-dominant fit must abstain (floor-normal sanity gate)
    geometry_w, mask_w, _, _ = synthetic_geometry(wall=True)
    fitted_w = plane_homography_from_moge(geometry_w, mask_w, IMG_W, IMG_H)
    print(f"  [{'PASS' if fitted_w is None else 'FAIL'}] wall-like plane -> abstains")
    ok_all &= fitted_w is None

    # 4 β€” garbage points must abstain (scale self-check / inlier gates)
    rng = np.random.default_rng(9)
    geometry_g, mask_g, _, _ = synthetic_geometry()
    geometry_g["points"] = rng.uniform(0.1, 10.0, geometry_g["points"].shape).astype(np.float32)
    fitted_g = plane_homography_from_moge(geometry_g, mask_g, IMG_W, IMG_H)
    print(f"  [{'PASS' if fitted_g is None else 'FAIL'}] random point cloud -> abstains")
    ok_all &= fitted_g is None

    # 5 β€” missing geometry -> None (caller falls through to the depth path)
    none_ok = (
        plane_homography_from_moge(None, mask, IMG_W, IMG_H) is None
        and plane_homography_from_moge({"points": None}, mask, IMG_W, IMG_H) is None
    )
    print(f"  [{'PASS' if none_ok else 'FAIL'}] no geometry -> None")
    ok_all &= none_ok

    # --- R1-6 (Pull 2) β€” per-region plane charts -----------------------------
    start = src.index("def region_plane_chart")
    end = src.index("\n# ---", start)
    ns["plane_homography_from_depth"] = lambda *a, **k: None
    exec(compile(src[start:end], "app.py", "exec"), ns)
    region_plane_chart = ns["region_plane_chart"]

    # Two-level floor: left half is the main floor (1.5 m below the camera),
    # right half a raised platform (1.0 m). One point map, two region masks.
    geom_a, mask_a, points_a, ok_a = synthetic_geometry(cam_h=1.5)
    geom_b, mask_b, points_b, ok_b = synthetic_geometry(cam_h=1.0)
    half = IMG_W // 2
    points = points_a.copy()
    points[:, half:] = points_b[:, half:]
    okm = ok_a.copy()
    okm[:, half:] = ok_b[:, half:]
    geometry2 = dict(geom_a)
    geometry2["points"] = points.astype(np.float32)
    geometry2["validMask"] = okm
    region_a = (mask_a > 0) & (np.indices((IMG_H, IMG_W))[1] < half)
    region_b = (mask_b > 0) & (np.indices((IMG_H, IMG_W))[1] >= half)

    # 6 β€” each region gets its OWN metre chart for its OWN plane
    fit_b = region_plane_chart(region_b.astype(np.uint8), geometry2, None, IMG_W, IMG_H)
    good = fit_b is not None
    if good:
        Hb = np.asarray(fit_b[0], np.float64).reshape(3, 3)
        ys, xs = np.nonzero(region_b & okm)
        rngb = np.random.default_rng(13)
        sel = rngb.choice(len(xs), 3000, replace=False)
        i, j = sel[:1500], sel[1500:]
        P = points[ys, xs]
        d3 = np.linalg.norm(P[i] - P[j], axis=1)
        den = Hb[2, 0] * xs + Hb[2, 1] * ys + Hb[2, 2]
        pa = (Hb[0, 0] * xs + Hb[0, 1] * ys + Hb[0, 2]) / den
        pb = (Hb[1, 0] * xs + Hb[1, 1] * ys + Hb[1, 2]) / den
        dp = np.hypot(pa[i] - pa[j], pb[i] - pb[j])
        far = dp > 0.3
        ratio_b = float(np.median(d3[far] / dp[far]))
        good = abs(ratio_b - 1.0) <= 0.02
        print(f"  [{'PASS' if good else 'FAIL'}] region chart: raised region gets its own "
              f"metre chart (ratio {ratio_b:.4f})")
    else:
        print("  [FAIL] region chart: abstained on a clean raised region")
    ok_all &= good

    # 7 β€” tiny/garbage regions abstain so the caller keeps the shared chart
    tiny = np.zeros((IMG_H, IMG_W), np.uint8)
    tiny[200:230, 200:230] = 1
    abstain_ok = region_plane_chart(tiny, geometry2, None, IMG_W, IMG_H) is None
    print(f"  [{'PASS' if abstain_ok else 'FAIL'}] region chart: tiny region abstains "
          f"(shared chart kept)")
    ok_all &= abstain_ok

    print("\n" + ("ALL R1-5 SIM CHECKS PASSED" if ok_all else "R1-5 SIM CHECKS FAILED"))
    return 0 if ok_all else 1


if __name__ == "__main__":
    raise SystemExit(main())