code wiki / _hdl_build / nx_poseest2.nx
nx_poseest2.nx source
↩ module page · 167 lines · 7514 B
1// nx_poseest2.nx -- R2 v0 with the pose-estimate funcs INLINED (importing nx_pose_estimate TOGETHER WITH
2// nx_figure_render tripped an nx_cc empty-.s codegen bug; each alone compiles -> module-combination bug, routed
3// to the compiler workstream). Learned hand-region-from-silhouette, held-out generalization. expect_exit:0 ORIGINAL
4import "nx_syscalls.nx"
5import "nx_figure_render.nx"
6const K_MAGIC_1900000000: i64 = 1900000000
7const K_MAGIC_12868: i64 = 12868
8
9func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
10func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 }
11
12const PW: i64 = 64
13const PH: i64 = 48
14const GW: i64 = 8
15const GH: i64 = 6
16const NCELL: i64 = 48
17const NFEAT: i64 = 49
18const NR: i64 = 3 // hand HEIGHT bands (low/mid/high) -- the signal shoulder pitch most strongly drives
19const NTR: i64 = 30
20const NHO: i64 = 9
21const NALL: i64 = 39
22
23// ---- inlined pose-estimate ----
24func pe_occ(zb: *i64, w: i64, h: i64, gw: i64, gh: i64, occ: *i64) -> i64 {
25 var cy: i64 = 0
26 while cy < gh {
27 var cx: i64 = 0
28 while cx < gw {
29 let x0: i64 = cx*w/gw; let x1: i64 = (cx+1)*w/gw; let y0: i64 = cy*h/gh; let y1: i64 = (cy+1)*h/gh
30 var cnt: i64 = 0; var tot: i64 = 0
31 var y: i64 = y0
32 while y < y1 { var x: i64 = x0; while x < x1 { tot=tot+1; if zb[y*w+x] > (0-K_MAGIC_1900000000) { cnt=cnt+1 } x=x+1 } y=y+1 }
33 var v: i64 = 0
34 if tot > 0 { v = cnt*256/tot }
35 occ[cy*gw+cx] = v
36 cx = cx + 1
37 }
38 cy = cy + 1
39 }
40 return 0
41}
42func pe_score(W: *i64, r: i64, occ: *i64, nf: i64) -> i64 { var s: i64=0; var c: i64=0; while c<nf { s=s+W[r*nf+c]*occ[c]; c=c+1 } return s }
43func pe_predict(W: *i64, occ: *i64, nf: i64, nr: i64) -> i64 { var best: i64=0; var bs: i64=pe_score(W,0,occ,nf); var r: i64=1; while r<nr { let s: i64=pe_score(W,r,occ,nf); if s>bs { bs=s; best=r } r=r+1 } return best }
44func pe_train(W: *i64, occs: *i64, labels: *i64, ns: i64, nf: i64, nr: i64, ep: i64) -> i64 {
45 var i: i64=0; while i<nr*nf { W[i]=0; i=i+1 }
46 var last: i64=0; var e: i64=0
47 while e < ep {
48 var mist: i64=0; var n: i64=0
49 while n < ns {
50 let occ: *i64 = (occs as i64 + n*nf*8) as *i64
51 let pred: i64 = pe_predict(W, occ, nf, nr); let lab: i64 = labels[n]
52 if pred != lab { mist=mist+1; var c: i64=0; while c<nf { W[lab*nf+c]=W[lab*nf+c]+occ[c]; W[pred*nf+c]=W[pred*nf+c]-occ[c]; c=c+1 } }
53 n = n + 1
54 }
55 last = mist; e = e + 1
56 }
57 return last
58}
59func clamp3(v: i64) -> i64 { if v < 0 { return 0 } if v > 2 { return 2 } return v }
60func pdg(d: i64) -> i64 { return d * K_MAGIC_12868 / 180 } // degrees -> rig angle unit (md_deg lives in nx_movelib, not imported here)
61func pe_sample(sk: i64, fb: *i64, zb: *i64, pitch: i64, elbow: i64, occ: *i64, wxy: *i64) -> i64 {
62 sk_pose(sk, RG_SHR, 0, pdg(pitch)); sk_pose(sk, RG_ELR, pdg(elbow), 0)
63 sk_update(sk)
64 rig_draw(sk, fb, zb, PW, PH, pdg(15), 70)
65 pe_occ(zb, PW, PH, GW, GH, occ)
66 occ[NCELL] = 256
67 let bw: *i64 = sk_bone(sk, RG_WRR); wxy[0] = bw[15]; wxy[1] = bw[16]
68 return 0
69}
70
71func main() -> i64 {
72 hw("=== nx_poseest2 -- learned hand-region from silhouette (R2 v0) ===\n" as *u8)
73 let sk: i64 = sys_mmap(sk_bytes()) as i64
74 let fb: *i64 = sys_mmap(PW * PH * 8) as *i64
75 let zb: *i64 = sys_mmap(PW * PH * 8) as *i64
76 let occs: *i64 = sys_mmap(NALL * NFEAT * 8) as *i64
77 let wx: *i64 = sys_mmap(NALL * 8) as *i64
78 let wy: *i64 = sys_mmap(NALL * 8) as *i64
79 let trp: *i64 = sys_mmap(6 * 8) as *i64
80 trp[0]=0-70; trp[1]=0-40; trp[2]=0-10; trp[3]=20; trp[4]=50; trp[5]=80
81 let tre: *i64 = sys_mmap(5 * 8) as *i64
82 tre[0]=0; tre[1]=25; tre[2]=50; tre[3]=75; tre[4]=100
83 let hop: *i64 = sys_mmap(3 * 8) as *i64
84 hop[0]=0-55; hop[1]=5; hop[2]=65
85 let hoe: *i64 = sys_mmap(3 * 8) as *i64
86 hoe[0]=12; hoe[1]=37; hoe[2]=62
87
88 rig_build(sk)
89 let wxy: *i64 = sys_mmap(2 * 8) as *i64
90 // DELTA FEATURES: a neutral arm-down reference silhouette; every sample subtracts it, so the STATIC body
91 // cancels and the moving ARM is the signal the perceptron sees.
92 let ref: *i64 = sys_mmap(NFEAT * 8) as *i64
93 pe_sample(sk, fb, zb, 0 - 80, 0, ref, wxy)
94 var idx: i64 = 0
95 var pi: i64 = 0
96 while pi < 6 {
97 var ei: i64 = 0
98 while ei < 5 {
99 let occp: *i64 = (occs as i64 + idx * NFEAT * 8) as *i64
100 pe_sample(sk, fb, zb, trp[pi], tre[ei], occp, wxy)
101 var c: i64 = 0
102 while c < NCELL { occp[c] = occp[c] - ref[c]; c = c + 1 }
103 wx[idx] = wxy[0]; wy[idx] = wxy[1]; idx = idx + 1
104 ei = ei + 1
105 }
106 pi = pi + 1
107 }
108 pi = 0
109 while pi < 3 {
110 var ei: i64 = 0
111 while ei < 3 {
112 let occp: *i64 = (occs as i64 + idx * NFEAT * 8) as *i64
113 pe_sample(sk, fb, zb, hop[pi], hoe[ei], occp, wxy)
114 var c: i64 = 0
115 while c < NCELL { occp[c] = occp[c] - ref[c]; c = c + 1 }
116 wx[idx] = wxy[0]; wy[idx] = wxy[1]; idx = idx + 1
117 ei = ei + 1
118 }
119 pi = pi + 1
120 }
121
122 var xmin: i64 = wx[0]; var xmax: i64 = wx[0]; var ymin: i64 = wy[0]; var ymax: i64 = wy[0]
123 var i: i64 = 1
124 while i < NALL {
125 if wx[i] < xmin { xmin = wx[i] }
126 if wx[i] > xmax { xmax = wx[i] }
127 if wy[i] < ymin { ymin = wy[i] }
128 if wy[i] > ymax { ymax = wy[i] }
129 i = i + 1
130 }
131 let labels: *i64 = sys_mmap(NALL * 8) as *i64
132 i = 0
133 while i < NALL {
134 let yr: i64 = clamp3(3 * (wy[i] - ymin) / (ymax - ymin + 1))
135 labels[i] = yr // 3 height bands
136 i = i + 1
137 }
138 hw(" wrist range x["); pn(xmin); hw(","); pn(xmax); hw("] y["); pn(ymin); hw(","); pn(ymax); hw("]\n" as *u8)
139
140 let W: *i64 = sys_mmap(NR * NFEAT * 8) as *i64
141 let mist: i64 = pe_train(W, occs, labels, NTR, NFEAT, NR, 60)
142 hw(" perceptron trained on "); pn(NTR); hw(" poses, last-epoch mistakes="); pn(mist); hw("\n" as *u8)
143
144 let W0: *i64 = sys_mmap(NR * NFEAT * 8) as *i64
145 var z: i64 = 0
146 while z < NR * NFEAT { W0[z] = 0; z = z + 1 }
147 var corr: i64 = 0
148 var corr0: i64 = 0
149 i = NTR
150 while i < NALL {
151 let occ: *i64 = (occs as i64 + i * NFEAT * 8) as *i64
152 if pe_predict(W, occ, NFEAT, NR) == labels[i] { corr = corr + 1 }
153 if pe_predict(W0, occ, NFEAT, NR) == labels[i] { corr0 = corr0 + 1 }
154 i = i + 1
155 }
156 hw(" HELD-OUT: TRAINED "); pn(corr); hw("/"); pn(NHO); hw(" vs UNTRAINED "); pn(corr0); hw("/"); pn(NHO); hw("\n" as *u8)
157
158 var fails: i64 = 0
159 if corr > corr0 {
160 if corr * 100 >= NHO * 55 { hw("T PASS GENERALIZES (trained "); pn(corr); hw("/"); pn(NHO); hw(" >> untrained "); pn(corr0); hw(")\n" as *u8) }
161 else { fails = fails + 1; hw("T FAIL accuracy low "); pn(corr); hw("\n" as *u8) }
162 } else { fails = fails + 1; hw("T FAIL not > untrained\n" as *u8) }
163
164 if fails == 0 { hw("POSEEST2 GREEN -- learned pose localization generalizes (R2 v0; coarse, our-render domain)\n" as *u8); sys_exit(0); return 0 }
165 hw("POSEEST2 RED fails="); pn(fails); hw("\n" as *u8)
166 sys_exit(1); return 1
167}