code wiki / (root) / nx_photogram_front_diag.nx

nx_photogram_front_diag.nx source

↩ module page · 191 lines · 6813 B

1// nx_photogram_front_diag.nx -- measurement probe, not a gate. T5 failed with the noise control scoring 2// 18/20, which says the epipolar residual is not separating true correspondences from garbage. Before 3// touching a tolerance constant I want the actual numbers: what does e3_residual return for a TRUE 4// correspondence, for a planted outlier, and for pure noise -- both under an E built from the known pose 5// (ep_build_E) and under an E estimated from the data (e3_estimate_norm). Tuning a threshold without 6// looking at the distribution is how a gate gets faked green. 7// license_tier: ORIGINAL expect_exit: 0 8import "nx_photogram_front.nx" 9import "nx_epose.nx" 10 11const D_N: i64 = 20 12const D_OUT: i64 = 6 13 14func dw(s: *u8) -> i64 { 15 var n: i64 = 0 16 while s[n] != (0 as u8) { n = n + 1 } 17 sys_write(1, s, n) 18 return 0 19} 20 21func dn(v: i64) -> i64 { 22 let bb: *u8 = sys_mmap(32) 23 let t: *u8 = sys_mmap(32) 24 var m: i64 = v 25 var neg: i64 = 0 26 if m < 0 { neg = 1; m = 0 - m } 27 var k: i64 = 0 28 if m == 0 { t[0] = 48 as u8; k = 1 } 29 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 30 var i: i64 = 0 31 if neg == 1 { bb[0] = 45 as u8; i = 1 } 32 var j: i64 = 0 33 while j < k { bb[i + j] = t[k - 1 - j]; j = j + 1 } 34 sys_write(1, bb, i + k) 35 return 0 36} 37 38func main() -> i64 { 39 pf_init() 40 dw("=== residual distribution probe ===\n" as *u8) 41 let Rt: *i64 = sys_mmap(9 * 8 + 64) as *i64 42 Rt[0] = 15137; Rt[1] = 0; Rt[2] = 6270 43 Rt[3] = 0; Rt[4] = 16384; Rt[5] = 0 44 Rt[6] = 0 - 6270; Rt[7] = 0; Rt[8] = 15137 45 let tt: *i64 = sys_mmap(3 * 8 + 64) as *i64 46 tt[0] = 1400 47 tt[1] = 250 48 tt[2] = 320 49 let c0: *i64 = sys_mmap(D_N * 2 * 8 + 64) as *i64 50 let c1: *i64 = sys_mmap(D_N * 2 * 8 + 64) as *i64 51 var st: i64 = 987654321 52 var n: i64 = 0 53 while n < D_N { 54 st = (st * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 55 let X: i64 = (st % 4000) - 2000 56 st = (st * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 57 let Y: i64 = (st % 4000) - 2000 58 st = (st * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 59 let Z: i64 = 4000 + (st % 4000) 60 c0[n * 2] = (X * PF_Q) / Z 61 c0[n * 2 + 1] = (Y * PF_Q) / Z 62 let p2x: i64 = (Rt[0] * X + Rt[1] * Y + Rt[2] * Z) / PF_Q + tt[0] 63 let p2y: i64 = (Rt[3] * X + Rt[4] * Y + Rt[5] * Z) / PF_Q + tt[1] 64 let p2z: i64 = (Rt[6] * X + Rt[7] * Y + Rt[8] * Z) / PF_Q + tt[2] 65 c1[n * 2] = (p2x * PF_Q) / p2z 66 c1[n * 2 + 1] = (p2y * PF_Q) / p2z 67 n = n + 1 68 } 69 // E from the KNOWN pose. NOTE the convention: for x2^T E x1 = 0 with P2 = [R | t], E = [t]_x R. 70 let Etrue: *i64 = sys_mmap(9 * 8 + 64) as *i64 71 ep_build_E(tt[0], tt[1], tt[2], Rt, Etrue) 72 dw("\n-- residual under E built from the TRUE pose (should be ~0 for all 20) --\n" as *u8) 73 var i: i64 = 0 74 while i < D_N { 75 let r: i64 = e3_residual(Etrue, c0[i * 2], c0[i * 2 + 1], c1[i * 2], c1[i * 2 + 1]) 76 dw(" pt " as *u8) 77 dn(i) 78 dw(" resid=" as *u8) 79 dn(r) 80 dw("\n" as *u8) 81 i = i + 1 82 } 83 // E estimated from all 20 clean correspondences 84 let Eest: *i64 = sys_mmap(9 * 8 + 64) as *i64 85 e3_estimate_norm(c0, c1, D_N, Eest) 86 dw("\n-- E entries: TRUE vs ESTIMATED (both max-entry normalized to Q14) --\n" as *u8) 87 var e: i64 = 0 88 while e < 9 { 89 dw(" E[" as *u8) 90 dn(e) 91 dw("] true=" as *u8) 92 dn(Etrue[e]) 93 dw(" est=" as *u8) 94 dn(Eest[e]) 95 dw("\n" as *u8) 96 e = e + 1 97 } 98 dw("\n-- residual under the ESTIMATED E (clean data) --\n" as *u8) 99 var mx: i64 = 0 100 i = 0 101 while i < D_N { 102 let r2: i64 = e3_residual(Eest, c0[i * 2], c0[i * 2 + 1], c1[i * 2], c1[i * 2 + 1]) 103 if r2 > mx { mx = r2 } 104 dw(" pt " as *u8) 105 dn(i) 106 dw(" resid=" as *u8) 107 dn(r2) 108 dw("\n" as *u8) 109 i = i + 1 110 } 111 dw(" max clean residual = " as *u8) 112 dn(mx) 113 dw("\n" as *u8) 114 // now: what does a GARBAGE correspondence score under the same estimated E? 115 dw("\n-- residual for RANDOM (garbage) pairs under the estimated E --\n" as *u8) 116 var g: i64 = 0 117 var gmin: i64 = 0 - 1 118 while g < 12 { 119 st = (st * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 120 let ax: i64 = (st % 8000) - 4000 121 st = (st * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 122 let ay: i64 = (st % 8000) - 4000 123 st = (st * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 124 let bx: i64 = (st % 8000) - 4000 125 st = (st * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 126 let by: i64 = (st % 8000) - 4000 127 let r3: i64 = e3_residual(Eest, ax, ay, bx, by) 128 if gmin < 0 { gmin = r3 } else { if r3 < gmin { gmin = r3 } } 129 dw(" rnd " as *u8) 130 dn(g) 131 dw(" resid=" as *u8) 132 dn(r3) 133 dw("\n" as *u8) 134 g = g + 1 135 } 136 dw(" min garbage residual = " as *u8) 137 dn(gmin) 138 dw("\n\nSEPARATION (e3_estimate_norm): clean max=" as *u8) 139 dn(mx) 140 dw(" garbage min=" as *u8) 141 dn(gmin) 142 dw("\n" as *u8) 143 144 // ---- A/B: the same data through pf_estimate_e (repeated squaring) ---- 145 dw("\n=== A/B: pf_estimate_e (repeated squaring) on the SAME data ===\n" as *u8) 146 let Enew: *i64 = sys_mmap(9 * 8 + 64) as *i64 147 pf_estimate_e(c0, c1, D_N, Enew) 148 var e2: i64 = 0 149 while e2 < 9 { 150 dw(" E[" as *u8) 151 dn(e2) 152 dw("] true=" as *u8) 153 dn(Etrue[e2]) 154 dw(" pf_est=" as *u8) 155 dn(Enew[e2]) 156 dw("\n" as *u8) 157 e2 = e2 + 1 158 } 159 var mx2: i64 = 0 160 i = 0 161 while i < D_N { 162 let r4: i64 = e3_residual(Enew, c0[i * 2], c0[i * 2 + 1], c1[i * 2], c1[i * 2 + 1]) 163 if r4 > mx2 { mx2 = r4 } 164 i = i + 1 165 } 166 var gmin2: i64 = 0 - 1 167 var g2: i64 = 0 168 var st2: i64 = 55555555 169 while g2 < 200 { 170 st2 = (st2 * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 171 let ax2: i64 = (st2 % 8000) - 4000 172 st2 = (st2 * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 173 let ay2: i64 = (st2 % 8000) - 4000 174 st2 = (st2 * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 175 let bx2: i64 = (st2 % 8000) - 4000 176 st2 = (st2 * PF_LCG_MUL + PF_LCG_ADD) & PF_LCG_MASK 177 let by2: i64 = (st2 % 8000) - 4000 178 let r5: i64 = e3_residual(Enew, ax2, ay2, bx2, by2) 179 if gmin2 < 0 { gmin2 = r5 } else { if r5 < gmin2 { gmin2 = r5 } } 180 g2 = g2 + 1 181 } 182 dw("\nSEPARATION (pf_estimate_e): clean max=" as *u8) 183 dn(mx2) 184 dw(" garbage min over 200 draws=" as *u8) 185 dn(gmin2) 186 dw("\n" as *u8) 187 dw("VERDICT: " as *u8) 188 if mx2 < mx { dw("pf_estimate_e is MORE accurate on clean data" as *u8) } else { dw("NO improvement on clean data" as *u8) } 189 dw("\n" as *u8) 190 return 0 191}