code wiki / (root) / nx_lbp_core.nx

nx_lbp_core.nx source

↩ module page · 130 lines · 6419 B

1// nx_lbp_core.nx -- shared SOVEREIGN LBP descriptor primitives (NO main). Hardware-up, integer-only, 2// weight-free. Used by nx_lbp.nx (rung-1 KAT gate) and nx_lbp_img.nx (real-image descriptor rung). 3// license_tier: ORIGINAL 4import "nx_syscalls.nx" 5 6func lp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 7func ln(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; var neg: i64=0; if m<0{neg=1;m=0-m}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; if neg==1{b[0]=45;i=1}; var j: i64=0; while j<k{b[i]=t[k-1-j];i=i+1;j=j+1}; sys_write(1,b,i); return 0 } 8 9// 8-bit LBP code at interior pixel (x,y) of a w-wide grayscale image. 10// neighbor order (bit0->bit7), clockwise from top-left: TL,T,TR,R,BR,B,BL,L; bit set when neighbor >= center. 11func lbp_code(img: *u8, w: i64, x: i64, y: i64) -> i64 { 12 let c: i64 = img[y*w+x] as i64 13 var code: i64 = 0 14 if (img[(y-1)*w+(x-1)] as i64) >= c { code = code + 1 } 15 if (img[(y-1)*w+x] as i64) >= c { code = code + 2 } 16 if (img[(y-1)*w+(x+1)] as i64) >= c { code = code + 4 } 17 if (img[y*w+(x+1)] as i64) >= c { code = code + 8 } 18 if (img[(y+1)*w+(x+1)] as i64) >= c { code = code + 16 } 19 if (img[(y+1)*w+x] as i64) >= c { code = code + 32 } 20 if (img[(y+1)*w+(x-1)] as i64) >= c { code = code + 64 } 21 if (img[y*w+(x-1)] as i64) >= c { code = code + 128 } 22 return code 23} 24 25// 256-bin LBP histogram over a rectangular region [x0,x1) x [y0,y1) of a w-wide image (caller zeroes hist). 26// region must stay 1px inside the image edges so the 3x3 neighborhood is valid. 27func lbp_hist_region(img: *u8, w: i64, x0: i64, y0: i64, x1: i64, y1: i64, hist: *i64) -> i64 { 28 var y: i64 = y0 29 while y < y1 { var x: i64 = x0; while x < x1 { let cd: i64 = lbp_code(img, w, x, y); hist[cd] = hist[cd] + 1; x = x + 1 } y = y + 1 } 30 return 0 31} 32 33// whole-image interior histogram convenience 34func lbp_hist(img: *u8, w: i64, h: i64, hist: *i64) -> i64 { lbp_hist_region(img, w, 1, 1, w-1, h-1, hist); return 0 } 35 36// chi-square distance * scale (integer) over bins [off, off+n): sum (a-b)^2 * scale / (a+b), a+b>0 37func chi2_range(a: *i64, b: *i64, off: i64, n: i64, scale: i64) -> i64 { 38 var s: i64 = 0; var i: i64 = off; let e: i64 = off+n 39 while i < e { let av: i64 = a[i]; let bv: i64 = b[i]; let den: i64 = av+bv; if den > 0 { let d: i64 = av-bv; s = s + (d*d*scale)/den } i = i + 1 } 40 return s 41} 42// single 256-bin chi-square 43func chi2(a: *i64, b: *i64, scale: i64) -> i64 { return chi2_range(a, b, 0, 256, scale) } 44 45func zero256(p: *i64) -> i64 { var i: i64=0; while i<256 { p[i]=0; i=i+1 } return 0 } 46func hsum(p: *i64) -> i64 { var s: i64=0; var i: i64=0; while i<256 { s=s+p[i]; i=i+1 } return s } 47 48// integer luma grayscale: gray[i] = (77*R + 150*G + 29*B) >> 8 ; rgb = w*h*nch interleaved, nch>=3 49func rgb_to_gray(rgb: *u8, gray: *u8, w: i64, h: i64, nch: i64) -> i64 { 50 var i: i64 = 0; let npx: i64 = w*h 51 while i < npx { 52 let r: i64 = rgb[i*nch+0] as i64 53 let g: i64 = rgb[i*nch+1] as i64 54 let b: i64 = rgb[i*nch+2] as i64 55 gray[i] = ((77*r + 150*g + 29*b) >> 8) as u8 56 i = i + 1 57 } 58 return 0 59} 60 61// box-average grayscale resize: src(sw x sh) -> dst(dw x dh). Integer area average -> no aliasing/holes. 62func gray_resize_box(src: *u8, sw: i64, sh: i64, dst: *u8, dw: i64, dh: i64) -> i64 { 63 var dy: i64 = 0 64 while dy < dh { 65 let sy0: i64 = (dy*sh)/dh; var sy1: i64 = ((dy+1)*sh)/dh; if sy1 <= sy0 { sy1 = sy0+1 } 66 var dx: i64 = 0 67 while dx < dw { 68 let sx0: i64 = (dx*sw)/dw; var sx1: i64 = ((dx+1)*sw)/dw; if sx1 <= sx0 { sx1 = sx0+1 } 69 var sum: i64 = 0; var cnt: i64 = 0 70 var yy: i64 = sy0 71 while yy < sy1 { var xx: i64 = sx0; while xx < sx1 { sum = sum + (src[yy*sw+xx] as i64); cnt = cnt+1; xx = xx+1 } yy = yy+1 } 72 dst[dy*dw+dx] = (sum/cnt) as u8 73 dx = dx + 1 74 } 75 dy = dy + 1 76 } 77 return 0 78} 79 80// spatial-grid LBP descriptor: g x g cells, each a 256-bin LBP histogram, packed into descr (length g*g*256, 81// caller zeroes). Each interior pixel's code is binned by which cell its CENTER falls in (neighbors always read 82// from the full image, so cell boundaries stay correct). This keeps WHERE texture occurs -> face-discriminative. 83func lbp_grid_descr(gray: *u8, w: i64, h: i64, g: i64, descr: *i64) -> i64 { 84 var y: i64 = 1 85 while y < h-1 { 86 let cy: i64 = (y*g)/h 87 var x: i64 = 1 88 while x < w-1 { 89 let cx: i64 = (x*g)/w 90 let cd: i64 = lbp_code(gray, w, x, y) 91 let cell: i64 = cy*g + cx 92 descr[cell*256 + cd] = descr[cell*256 + cd] + 1 93 x = x + 1 94 } 95 y = y + 1 96 } 97 return 0 98} 99 100// distance over a full g x g grid descriptor = sum of per-cell chi-square 101func grid_chi2(a: *i64, b: *i64, g: i64, scale: i64) -> i64 { return chi2_range(a, b, 0, g*g*256, scale) } 102 103// chi-square between descriptor i and descriptor j packed in buf (each length d) 104func chi2_at(buf: *i64, i: i64, j: i64, d: i64, scale: i64) -> i64 { 105 var s: i64 = 0; let bi: i64 = i*d; let bj: i64 = j*d; var k: i64 = 0 106 while k < d { let av: i64 = buf[bi+k]; let bv: i64 = buf[bj+k]; let den: i64 = av+bv; if den > 0 { let dd: i64 = av-bv; s = s + (dd*dd*scale)/den } k = k + 1 } 107 return s 108} 109 110// greedy single-pass clustering of m descriptors (each length d) packed in buf. Each descriptor joins the 111// nearest existing cluster whose representative is within thresh (chi-square*scale), else starts a new cluster. 112// assign[i] = cluster id; reps[c] = index of cluster c's representative; returns the cluster count. 113func cluster_greedy(buf: *i64, m: i64, d: i64, thresh: i64, scale: i64, assign: *i64, reps: *i64) -> i64 { 114 var nc: i64 = 0 115 var i: i64 = 0 116 while i < m { 117 var best: i64 = 0 - 1; var bestd: i64 = 0 118 var c: i64 = 0 119 while c < nc { 120 let dist: i64 = chi2_at(buf, i, reps[c], d, scale) 121 if c == 0 { best = 0; bestd = dist } else { if dist < bestd { best = c; bestd = dist } } 122 c = c + 1 123 } 124 var made: i64 = 0 125 if nc > 0 { if bestd < thresh { assign[i] = best; made = 1 } } 126 if made == 0 { reps[nc] = i; assign[i] = nc; nc = nc + 1 } 127 i = i + 1 128 } 129 return nc 130}