nx_ocr_classify_gate.nx source
↩ module page · 67 lines · 3369 B
1// nx_ocr_classify_gate.nx -- proves R4 (glyph -> character). Templates for '0','1','7' on a 3x5 grid. Renders a '7'
2// as a binary image, resamples it, and classifies it correctly; checks Hamming distance and 1-pixel noise tolerance.
3// Exit 0 iff all pass. license_tier: ORIGINAL
4import "nx_gate.nx"
5import "nx_ocr_classify.nx"
6import "nx_img_core.nx"
7
8func chk(name: *u8, got: i64, want: i64, st: *i64) -> i64 {
9 if got == want { st[0] = st[0] + 1; gw(" PASS " as *u8); gw(name); gw("\n" as *u8) }
10 else { st[1] = st[1] + 1; gw(" FAIL " as *u8); gw(name); gw(" got=" as *u8); gn(got); gw(" want=" as *u8); gn(want); gw("\n" as *u8) }
11 return 0
12}
13
14func set15(t: *i64, o: i64, a0: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64, a7: i64, a8: i64, a9: i64, a10: i64, a11: i64, a12: i64, a13: i64, a14: i64) -> i64 {
15 t[o+0]=a0; t[o+1]=a1; t[o+2]=a2; t[o+3]=a3; t[o+4]=a4; t[o+5]=a5; t[o+6]=a6; t[o+7]=a7
16 t[o+8]=a8; t[o+9]=a9; t[o+10]=a10; t[o+11]=a11; t[o+12]=a12; t[o+13]=a13; t[o+14]=a14
17 return 0
18}
19
20func main() -> i64 {
21 let st: *i64 = sys_mmap(16) as *i64
22 st[0] = 0; st[1] = 0
23 let NC: i64 = 15 // 3x5
24
25 // template set: index 0='0', 1='1', 2='7'
26 let tpl: *i64 = sys_mmap(3 * 15 * 8) as *i64
27 set15(tpl, 0, 1,1,1, 1,0,1, 1,0,1, 1,0,1, 1,1,1) // '0'
28 set15(tpl, 15, 0,1,0, 1,1,0, 0,1,0, 0,1,0, 1,1,1) // '1'
29 set15(tpl, 30, 1,1,1, 0,0,1, 0,1,0, 0,1,0, 0,1,0) // '7'
30
31 // render a '7' as a 3x5 binary image (ink=0, paper=255)
32 let src: *u8 = "P2\n3 5\n255\n0 0 0\n255 255 0\n255 0 255\n255 0 255\n255 0 255\n" as *u8
33 var len: i64 = 0; while src[len] != (0 as u8) { len = len + 1 }
34 let pix: *u8 = sys_mmap(256)
35 let dims: *i64 = sys_mmap(64) as *i64
36 let n: i64 = img_pgm_decode(src, len, pix, 256, dims)
37 chk("decoded 15-pixel glyph" as *u8, n, 15, st)
38
39 // resample the whole 3x5 glyph (bbox 0,0,3,5) into a 3x5 grid
40 let cell: *i64 = sys_mmap(15 * 8) as *i64
41 ocr_resample(pix, 3, 0, 0, 3, 5, 3, 5, cell)
42 let t7: *i64 = ((tpl as i64) + 30 * 8) as *i64
43 chk("resampled '7' matches template exactly (Hamming 0)" as *u8, ocr_hamming(cell, t7, NC), 0, st)
44
45 // classify -> should be index 2 ('7'), distance 0
46 let bd: *i64 = sys_mmap(16) as *i64
47 chk("classify '7' -> template index 2" as *u8, ocr_classify(cell, NC, tpl, 3, bd), 2, st)
48 chk("classify '7' distance = 0" as *u8, bd[0], 0, st)
49
50 // distance between distinct templates '0' and '7'
51 let t0: *i64 = ((tpl as i64) + 0 * 8) as *i64
52 chk("Hamming('0','7') = 9" as *u8, ocr_hamming(t0, t7, NC), 9, st)
53
54 // copy the '0' template into a cell and classify -> index 0
55 var i: i64 = 0; while i < NC { cell[i] = t0[i]; i = i + 1 }
56 chk("classify clean '0' -> index 0" as *u8, ocr_classify(cell, NC, tpl, 3, bd), 0, st)
57
58 // flip ONE cell (noise) -> still classified '0', distance 1
59 cell[4] = 1 - cell[4]
60 chk("classify noisy '0' (1 flip) -> still index 0" as *u8, ocr_classify(cell, NC, tpl, 3, bd), 0, st)
61 chk("noisy '0' distance = 1" as *u8, bd[0], 1, st)
62
63 gw("nx_ocr_classify_gate: PASS=" as *u8); gn(st[0]); gw(" FAIL=" as *u8); gn(st[1]); gw("\n" as *u8)
64 if st[1] == 0 { gw("R4 nx_ocr_classify: GREEN (glyph -> char: resample + nearest-neighbour template match)\n" as *u8); return 0 }
65 gw("R4 nx_ocr_classify: RED\n" as *u8)
66 return 1
67}