code wiki / (root) / nx_pose_skeleton.nx

nx_pose_skeleton.nx source

↩ module page · 52 lines · 2977 B

1// nx_pose_skeleton.nx -- T2 POSE, the geometric skeleton analysis that turns keypoints (from nx_pose_keypoints) 2// into a coarse POSTURE = the first rung of position/dance classification. NO CNN, NO trig, NO float: the body 3// ORIENTATION comes from the spine vector (neck -> mid-hip) by comparing the dominant axis + its sign (image 4// coords: y DOWN). Composes with nx_pose_keypoints' quarter-pixel keypoints; ready for real skeletons once the 5// f32 pose CNN emits heatmaps. Honest first rung -- trained fine-grained position recognition is T3. 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8 9// midpoint of two joints (virtual joint, e.g. mid-hip from L/R hip) iff both are confident. Returns 1 on valid. 10func pose_mid(qx: *i64, qy: *i64, conf: *i64, a: i64, b: i64, thresh: i64, ox: *i64, oy: *i64) -> i64 { 11 if conf[a] < thresh { return 0 } 12 if conf[b] < thresh { return 0 } 13 ox[0] = (qx[a] + qx[b]) / 2; oy[0] = (qy[a] + qy[b]) / 2 14 return 1 15} 16// coarse body posture from the spine vector (neck -> mid-hip): 0=upright 1=horizontal/lying 2=inverted -1=unknown. 17func pose_posture(qx: *i64, qy: *i64, conf: *i64, thresh: i64, neck_i: i64, lhip_i: i64, rhip_i: i64) -> i64 { 18 if conf[neck_i] < thresh { return 0 - 1 } 19 let hxb: *i64 = sys_mmap(8) as *i64; let hyb: *i64 = sys_mmap(8) as *i64 20 if pose_mid(qx, qy, conf, lhip_i, rhip_i, thresh, hxb, hyb) == 0 { return 0 - 1 } 21 let nx: i64 = qx[neck_i]; let ny: i64 = qy[neck_i] 22 let hx: i64 = hxb[0]; let hy: i64 = hyb[0] 23 var dx: i64 = hx - nx; if dx < 0 { dx = 0 - dx } 24 let dyraw: i64 = hy - ny // >0: hip below neck (normal); <0: hip above neck (head-down) 25 var dy: i64 = dyraw; if dy < 0 { dy = 0 - dy } 26 if dx >= 2 * dy { return 1 } // spine mostly HORIZONTAL -> lying/prone 27 if dyraw < 0 { return 2 } // spine vertical but head-DOWN -> inverted 28 return 0 // spine vertical, head up -> upright 29} 30// bounding-box compactness x1000 = (spanY*1000)/(spanX+1) over confident joints: high=extended/tall, low=crouched/wide. 31// A coarse shape feature the position/dance classifier composes with posture. Returns -1 if <2 confident joints. 32func pose_compactness(qx: *i64, qy: *i64, conf: *i64, J: i64, thresh: i64) -> i64 { 33 var minx: i64 = 0; var maxx: i64 = 0; var miny: i64 = 0; var maxy: i64 = 0 34 var seen: i64 = 0 35 var j: i64 = 0 36 while j < J { 37 if conf[j] >= thresh { 38 if seen == 0 { minx = qx[j]; maxx = qx[j]; miny = qy[j]; maxy = qy[j]; seen = 1 } 39 if seen == 1 { 40 if qx[j] < minx { minx = qx[j] } 41 if qx[j] > maxx { maxx = qx[j] } 42 if qy[j] < miny { miny = qy[j] } 43 if qy[j] > maxy { maxy = qy[j] } 44 } 45 } 46 j = j + 1 47 } 48 if seen == 0 { return 0 - 1 } 49 let spanx: i64 = maxx - minx 50 let spany: i64 = maxy - miny 51 return (spany * 1000) / (spanx + 1) 52}