code wiki / _hdl_build / nx_colorspace_gate.nx
nx_colorspace_gate.nx source
↩ module page · 69 lines · 4295 B
1// nx_colorspace_gate.nx -- proves + MEASURES sovereign RGB<->YCbCr + 4:2:0 (nx_colorspace). Native, no node.
2// 1) round-trip RGB->YCbCr->RGB within a bounded integer error (MEASURED)
3// 2) neutral gray -> Cb=Cr=128 (correct chroma centering)
4// 3) pure red -> Cr>128 (red chroma) + round-trips back to red
5// 4) 4:2:0 subsample->upsample on smooth chroma is near-lossless (MEASURED)
6// 5) anti-tautology: distinct colours -> distinct YCbCr
7// license_tier: ORIGINAL
8import "nx_syscalls.nx"
9import "nx_gate_emit_lib.nx"
10import "nx_colorspace.nx"
11
12func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
13func planemax(a: *u8, b: *u8, n: i64) -> i64 { var m: i64=0; var i: i64=0; while i<n { let e: i64=g_abs((a[i] as i64)-(b[i] as i64)); if e>m { m=e } i=i+1 } return m }
14
15func main() -> i64 {
16 g_puts("nx_colorspace gate (sovereign RGB<->YCbCr + 4:2:0, MEASURED)\n" as *u8)
17 var pass: i64 = 0; var total: i64 = 0
18
19 let W: i64 = 8; let H: i64 = 8; let n: i64 = W*H
20 let r: *u8 = sys_mmap(n); let g: *u8 = sys_mmap(n); let b: *u8 = sys_mmap(n)
21 let y: *u8 = sys_mmap(n); let cb: *u8 = sys_mmap(n); let cr: *u8 = sys_mmap(n)
22 let r2: *u8 = sys_mmap(n); let g2: *u8 = sys_mmap(n); let b2: *u8 = sys_mmap(n)
23
24 // a varied colour image
25 var i: i64 = 0
26 while i < n { r[i] = ((i*4) & 0xff) as u8; g[i] = ((255 - i*3) & 0xff) as u8; b[i] = ((i*9 + 30) & 0xff) as u8; i = i + 1 }
27
28 // 1) round-trip
29 cs_rgb_to_yuv(r, g, b, n, y, cb, cr)
30 cs_yuv_to_rgb(y, cb, cr, n, r2, g2, b2)
31 let er: i64 = planemax(r, r2, n); let eg: i64 = planemax(g, g2, n); let eb: i64 = planemax(b, b2, n)
32 var emax: i64 = er; if eg > emax { emax = eg } if eb > emax { emax = eb }
33 g_puts(" [measure] RGB round-trip max error = " as *u8); g_pn(emax); g_puts(" (0-255 scale)\n" as *u8)
34 pass = pass + g_check("RGB->YCbCr->RGB round-trip bounded (<= 8)" as *u8, emax <= 8); total=total+1
35
36 // 2) neutral gray
37 var k: i64 = 0; while k < n { r[k]=100 as u8; g[k]=100 as u8; b[k]=100 as u8; k=k+1 }
38 cs_rgb_to_yuv(r, g, b, n, y, cb, cr)
39 g_puts(" [measure] gray(100): Y=" as *u8); g_pn(y[0] as i64); g_puts(" Cb=" as *u8); g_pn(cb[0] as i64); g_puts(" Cr=" as *u8); g_pn(cr[0] as i64); g_puts("\n" as *u8)
40 pass = pass + g_check("neutral gray -> Cb=Cr=128 (centered chroma)" as *u8, (cb[0]==(128 as u8)) & (cr[0]==(128 as u8)) & (g_abs((y[0] as i64)-100)<=1)); total=total+1
41
42 // 3) pure red
43 k = 0; while k < n { r[k]=255 as u8; g[k]=0 as u8; b[k]=0 as u8; k=k+1 }
44 cs_rgb_to_yuv(r, g, b, n, y, cb, cr)
45 cs_yuv_to_rgb(y, cb, cr, n, r2, g2, b2)
46 g_puts(" [measure] red(255,0,0) -> Cr=" as *u8); g_pn(cr[0] as i64); g_puts(" round-trips to R=" as *u8); g_pn(r2[0] as i64); g_puts(" G=" as *u8); g_pn(g2[0] as i64); g_puts(" B=" as *u8); g_pn(b2[0] as i64); g_puts("\n" as *u8)
47 pass = pass + g_check("red -> Cr>128 + round-trips back to red" as *u8, ((cr[0] as i64) > 128) & ((r2[0] as i64) > 200) & ((g2[0] as i64) < 50) & ((b2[0] as i64) < 50)); total=total+1
48
49 // 4) 4:2:0 on a smooth chroma plane
50 let hf: *u8 = sys_mmap(n) // smooth full-res chroma
51 let half: *u8 = sys_mmap(n/4)
52 let up: *u8 = sys_mmap(n)
53 var yy: i64 = 0
54 while yy < H { var xx: i64 = 0; while xx < W { hf[yy*W+xx] = (110 + xx + yy) as u8; xx=xx+1 } yy=yy+1 } // smooth gradient
55 cs_subsample(hf, W, H, half)
56 cs_upsample(half, W, H, up)
57 let ce: i64 = planemax(hf, up, n)
58 g_puts(" [measure] 4:2:0 chroma subsample->upsample max error = " as *u8); g_pn(ce); g_puts(" (smooth chroma)\n" as *u8)
59 pass = pass + g_check("4:2:0 on smooth chroma near-lossless (<= 4)" as *u8, ce <= 4); total=total+1
60
61 // 5) anti-tautology: red vs blue
62 let yr: i64 = cs_y(255,0,0); let cbr: i64 = cs_cb(255,0,0); let crr: i64 = cs_cr(255,0,0)
63 let ybl: i64 = cs_y(0,0,255); let cbbl: i64 = cs_cb(0,0,255); let crbl: i64 = cs_cr(0,0,255)
64 pass = pass + g_check("anti-tautology: red YCbCr != blue YCbCr" as *u8, (cbr != cbbl) & (crr != crbl)); total=total+1
65
66 g_puts("---- colorspace gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
67 if pass == total { g_puts("verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
68 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1
69}