code wiki / (root) / nx_i2mesh.nx

nx_i2mesh.nx source

↩ module page · 138 lines · 5925 B

1// nx_i2mesh.nx -- sovereign IMAGE-to-MESH v0 (generator-path R3, operator: "z image be able to be ingested 2// like an i2mesh"). NOT neural (TripoSR/LRM); the honest v0 = SILHOUETTE INFLATION: an image -> foreground 3// MASK -> 2D chamfer distance transform (interior + exterior) -> a 3D field that balloons the silhouette 4// (thickest at the medial axis, pinched to 0 at the edge) -> nx_meshgen surface-nets -> emitted mesh. Ingests 5// ANY image the SAME way -- synthetic masks OR our own Z-Image/render foreground. Honest ceiling: single-view 6// inflation (front-back symmetric, no hidden geometry) vs neural multi-view; a real spine to grow. ORIGINAL 7import "nx_syscalls.nx" 8import "nx_meshgen.nx" 9 10const I2_MW: i64 = 96 11const I2_MH: i64 = 96 12const I2_LARGE: i64 = 1000000 13 14func i2m_px(m: *u8, x: i64, y: i64) -> i64 { return m[y * I2_MW + x] as i64 } 15func i2m_set(m: *u8, x: i64, y: i64, v: i64) -> i64 { m[y * I2_MW + x] = v as u8; return 0 } 16 17// --- mask generators (fill an I2_MW x I2_MH byte mask; 1=foreground) --- 18func i2m_mask_circle(m: *u8) -> i64 { 19 let cx: i64 = I2_MW / 2; let cy: i64 = I2_MH / 2; let r: i64 = I2_MW * 34 / 100 20 var y: i64 = 0 21 while y < I2_MH { var x: i64 = 0; while x < I2_MW { let dx: i64 = x - cx; let dy: i64 = y - cy; if dx * dx + dy * dy <= r * r { i2m_set(m, x, y, 1) } else { i2m_set(m, x, y, 0) } x = x + 1 } y = y + 1 } 22 return 0 23} 24func i2m_mask_square(m: *u8) -> i64 { 25 let cx: i64 = I2_MW / 2; let cy: i64 = I2_MH / 2; let w: i64 = I2_MW * 30 / 100 26 var y: i64 = 0 27 while y < I2_MH { var x: i64 = 0; while x < I2_MW { var ax: i64 = x - cx; if ax < 0 { ax = 0 - ax } var ay: i64 = y - cy; if ay < 0 { ay = 0 - ay } if ax < w { if ay < w { i2m_set(m, x, y, 1) } else { i2m_set(m, x, y, 0) } } else { i2m_set(m, x, y, 0) } x = x + 1 } y = y + 1 } 28 return 0 29} 30func i2m_mask_cross(m: *u8) -> i64 { 31 let cx: i64 = I2_MW / 2; let cy: i64 = I2_MH / 2; let a: i64 = I2_MW * 34 / 100; let b: i64 = I2_MW * 12 / 100 32 var y: i64 = 0 33 while y < I2_MH { 34 var x: i64 = 0 35 while x < I2_MW { 36 var ax: i64 = x - cx; if ax < 0 { ax = 0 - ax } 37 var ay: i64 = y - cy; if ay < 0 { ay = 0 - ay } 38 var f: i64 = 0 39 if ax < b { if ay < a { f = 1 } } 40 if ay < b { if ax < a { f = 1 } } 41 i2m_set(m, x, y, f) 42 x = x + 1 43 } 44 y = y + 1 45 } 46 return 0 47} 48// ingest OUR OWN image: a rendered framebuffer's foreground (skin = r>=b) -> mask (this is how Z-Image plugs in) 49func i2m_mask_from_fb(m: *u8, fb: *i64, w: i64, h: i64) -> i64 { 50 var my: i64 = 0 51 while my < I2_MH { 52 var mx: i64 = 0 53 while mx < I2_MW { 54 let sx: i64 = mx * w / I2_MW 55 let sy: i64 = my * h / I2_MH 56 let c: i64 = fb[sy * w + sx] 57 let r: i64 = c & 255; let b: i64 = (c >> 16) & 255 58 if r >= b { i2m_set(m, mx, my, 1) } else { i2m_set(m, mx, my, 0) } 59 mx = mx + 1 60 } 61 my = my + 1 62 } 63 return 0 64} 65 66// chamfer (3-4) distance transform: d = distance from each pixel of class (mask==fg) to the nearest pixel of 67// the OTHER class. fg=1 -> interior distance; fg=0 -> exterior distance. Units ~ 3x pixels. 68func i2m_dt(mask: *u8, d: *i64, fg: i64) -> i64 { 69 var p: i64 = 0 70 while p < I2_MW * I2_MH { if (mask[p] as i64) == fg { d[p] = I2_LARGE } else { d[p] = 0 } p = p + 1 } 71 var y: i64 = 0 72 while y < I2_MH { 73 var x: i64 = 0 74 while x < I2_MW { 75 let idx: i64 = y * I2_MW + x 76 var v: i64 = d[idx] 77 if x > 0 { if d[idx - 1] + 3 < v { v = d[idx - 1] + 3 } } 78 if y > 0 { if d[idx - I2_MW] + 3 < v { v = d[idx - I2_MW] + 3 } } 79 if x > 0 { if y > 0 { if d[idx - I2_MW - 1] + 4 < v { v = d[idx - I2_MW - 1] + 4 } } } 80 if x < I2_MW - 1 { if y > 0 { if d[idx - I2_MW + 1] + 4 < v { v = d[idx - I2_MW + 1] + 4 } } } 81 d[idx] = v 82 x = x + 1 83 } 84 y = y + 1 85 } 86 y = I2_MH - 1 87 while y >= 0 { 88 var x: i64 = I2_MW - 1 89 while x >= 0 { 90 let idx: i64 = y * I2_MW + x 91 var v: i64 = d[idx] 92 if x < I2_MW - 1 { if d[idx + 1] + 3 < v { v = d[idx + 1] + 3 } } 93 if y < I2_MH - 1 { if d[idx + I2_MW] + 3 < v { v = d[idx + I2_MW] + 3 } } 94 if x < I2_MW - 1 { if y < I2_MH - 1 { if d[idx + I2_MW + 1] + 4 < v { v = d[idx + I2_MW + 1] + 4 } } } 95 if x > 0 { if y < I2_MH - 1 { if d[idx + I2_MW - 1] + 4 < v { v = d[idx + I2_MW - 1] + 4 } } } 96 d[idx] = v 97 x = x - 1 98 } 99 y = y - 1 100 } 101 return 0 102} 103 104// fill the surface-nets corner grid F with the silhouette-inflation SDF (world units fx1024). 105func i2m_fill_field(F: *i64, mask: *u8, din: *i64, dout: *i64) -> i64 { 106 let R: i64 = MG_GR 107 var i: i64 = 0 108 while i <= MG_N { 109 var j: i64 = 0 110 while j <= MG_N { 111 let wx: i64 = mg_wc(i) 112 let wy: i64 = mg_wc(j) 113 var ix: i64 = (wx + R) * I2_MW / (2 * R) 114 var iy: i64 = (R - wy) * I2_MH / (2 * R) 115 if ix < 0 { ix = 0 } 116 if ix >= I2_MW { ix = I2_MW - 1 } 117 if iy < 0 { iy = 0 } 118 if iy >= I2_MH { iy = I2_MH - 1 } 119 let mp: i64 = iy * I2_MW + ix 120 var sdf2d: i64 = 0 121 if (mask[mp] as i64) == 1 { sdf2d = 0 - din[mp] * (2 * R) / (I2_MW * 3) } else { sdf2d = dout[mp] * (2 * R) / (I2_MW * 3) } 122 let thick: i64 = din[mp] * (2 * R) / (I2_MW * 3) 123 var k: i64 = 0 124 while k <= MG_N { 125 var az: i64 = mg_wc(k) 126 if az < 0 { az = 0 - az } 127 var v: i64 = sdf2d 128 let zc: i64 = az - thick 129 if zc > v { v = zc } 130 F[mg_fi(i, j, k)] = v 131 k = k + 1 132 } 133 j = j + 1 134 } 135 i = i + 1 136 } 137 return 0 138}