code wiki / (root) / nx_blob.nx

nx_blob.nx source

↩ module page · 148 lines · 5148 B

1// nx_blob.nx -- largest connected skin region (R2-refine). Fixes localization: 2// a global skin bbox spans the whole frame when skin is everywhere; the LARGEST 3// CONNECTED COMPONENT is the actual subject. Builds a GRIDxGRID occupancy map 4// (cell = skin if >=50% of its pixels are skin), labels it with two-pass 5// union-find connected-component labeling (4-connectivity), and returns the 6// biggest component's cell count + grid bounding box + box area. 7// 8// Coarse grid (not per-pixel CCL) keeps it cheap and robust: a person is a 9// coarse blob; scattered skin-coloured speckle never forms a big component. 10// 11// out[]: [0]=blob_cells [1..4]=grid bbox minx,miny,maxx,maxy [5]=bbox_cells 12// [6]=total_occupied_cells [7]=grid 13// genealogy_id: connected_component_labeling_union_find (record-hint) 14// lineage_id: occupancy_grid + two_pass_ccl + largest_component 15// license_tier: ORIGINAL 16import "syscalls.nx" 17import "nx_image.nx" 18import "nx_presence.nx" 19 20const NX_BLOB_GRID: i64 = 32 21 22func nx_blob_find(parent: *i64, x: i64) -> i64 { 23 var r: i64 = x 24 while parent[r] != r { r = parent[r] } 25 var c: i64 = x 26 while parent[c] != r { let n: i64 = parent[c]; parent[c] = r; c = n } 27 return r 28} 29func nx_blob_union(parent: *i64, a: i64, b: i64) -> i64 { 30 let ra: i64 = nx_blob_find(parent, a) 31 let rb: i64 = nx_blob_find(parent, b) 32 if ra != rb { parent[ra] = rb } 33 return 0 34} 35 36func nx_blob_largest(img: *Image, out: *i64) -> i64 { 37 let g: i64 = NX_BLOB_GRID 38 let w: i64 = img.width 39 let h: i64 = img.height 40 let ncell: i64 = g * g 41 let occ: *i64 = sys_mmap(ncell * 8) as *i64 42 let lab: *i64 = sys_mmap(ncell * 8) as *i64 43 let parent: *i64 = sys_mmap((ncell + 1) * 8) as *i64 44 45 // occupancy: a cell is occupied if >= 50% of its pixels are skin. 46 var occupied: i64 = 0 47 var cy: i64 = 0 48 while cy < g { 49 let y0: i64 = cy * h / g 50 let y1: i64 = (cy + 1) * h / g 51 var cx: i64 = 0 52 while cx < g { 53 let x0: i64 = cx * w / g 54 let x1: i64 = (cx + 1) * w / g 55 var sc: i64 = 0 56 var tot: i64 = 0 57 var y: i64 = y0 58 while y < y1 { 59 var x: i64 = x0 60 while x < x1 { 61 let rr: i64 = nx_image_get(img, x, y, 0) 62 let gg: i64 = nx_image_get(img, x, y, 1) 63 let bb: i64 = nx_image_get(img, x, y, 2) 64 if nx_skin_is_pixel(rr, gg, bb) == 1 { sc = sc + 1 } 65 tot = tot + 1 66 x = x + 1 67 } 68 y = y + 1 69 } 70 var o: i64 = 0 71 if tot > 0 { if sc * 2 >= tot { o = 1 } } 72 occ[cy * g + cx] = o 73 lab[cy * g + cx] = 0 74 if o == 1 { occupied = occupied + 1 } 75 cx = cx + 1 76 } 77 cy = cy + 1 78 } 79 80 // pass 1: provisional labels + unions (neighbours up and left) 81 var nl: i64 = 1 82 var i: i64 = 0 83 while i < ncell { 84 if occ[i] == 1 { 85 let ccx: i64 = i % g 86 let ccy: i64 = i / g 87 var up: i64 = 0 88 if ccy > 0 { if occ[i - g] == 1 { up = lab[i - g] } } 89 var lf: i64 = 0 90 if ccx > 0 { if occ[i - 1] == 1 { lf = lab[i - 1] } } 91 if up == 0 && lf == 0 { parent[nl] = nl; lab[i] = nl; nl = nl + 1 } 92 if up != 0 && lf == 0 { lab[i] = up } 93 if up == 0 && lf != 0 { lab[i] = lf } 94 if up != 0 && lf != 0 { 95 var m: i64 = up 96 if lf < m { m = lf } 97 lab[i] = m 98 if up != lf { nx_blob_union(parent, up, lf) } 99 } 100 } 101 i = i + 1 102 } 103 104 // pass 2: per-root count + bounding box 105 let cnt: *i64 = sys_mmap((ncell + 1) * 8) as *i64 106 let bminx: *i64 = sys_mmap((ncell + 1) * 8) as *i64 107 let bminy: *i64 = sys_mmap((ncell + 1) * 8) as *i64 108 let bmaxx: *i64 = sys_mmap((ncell + 1) * 8) as *i64 109 let bmaxy: *i64 = sys_mmap((ncell + 1) * 8) as *i64 110 var z: i64 = 0 111 while z <= ncell { cnt[z] = 0; bminx[z] = g; bminy[z] = g; bmaxx[z] = 0 - 1; bmaxy[z] = 0 - 1; z = z + 1 } 112 i = 0 113 while i < ncell { 114 if occ[i] == 1 { 115 let r: i64 = nx_blob_find(parent, lab[i]) 116 cnt[r] = cnt[r] + 1 117 let px: i64 = i % g 118 let py: i64 = i / g 119 if px < bminx[r] { bminx[r] = px } 120 if px > bmaxx[r] { bmaxx[r] = px } 121 if py < bminy[r] { bminy[r] = py } 122 if py > bmaxy[r] { bmaxy[r] = py } 123 } 124 i = i + 1 125 } 126 127 // largest component 128 var best: i64 = 0 129 var bc: i64 = 0 130 var r2: i64 = 1 131 while r2 < nl { 132 if cnt[r2] > bc { bc = cnt[r2]; best = r2 } 133 r2 = r2 + 1 134 } 135 out[7] = g 136 out[6] = occupied 137 out[0] = bc 138 if bc == 0 { 139 out[1] = 0 - 1; out[2] = 0 - 1; out[3] = 0 - 1; out[4] = 0 - 1; out[5] = 0 140 return 0 141 } 142 out[1] = bminx[best] 143 out[2] = bminy[best] 144 out[3] = bmaxx[best] 145 out[4] = bmaxy[best] 146 out[5] = (bmaxx[best] - bminx[best] + 1) * (bmaxy[best] - bminy[best] + 1) 147 return 0 148}