nx_multi_body.nx source
↩ module page · 83 lines · 2718 B
1// nx_multi_body.nx -- count of major skin regions (interaction-presence).
2//
3// Major-body floor: 5% of image area. Emits sealed kind:
4// NO_BODY | SOLO | TWO_BODY | MULTI_BODY.
5
6// nx_safety_envelope:
7// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
8// sil_target: SIL1
9// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
10// verdict: NOT_YET_EVALUATED
11
12import "nx_syscalls.nx"
13import "nx_image.nx"
14import "nx_color_v2.nx"
15import "nx_features.nx"
16const NX_MAGIC_1024: i64 = 1024
17
18const NX_MB_NO_BODY: i64 = 0
19const NX_MB_SOLO: i64 = 1
20const NX_MB_TWO_BODY: i64 = 2
21const NX_MB_MULTI_BODY: i64 = 3
22const NX_MB_MAJOR_FLOOR_Q10: i64 = 50
23
24struct MultiBodyVerdict {
25 kind: i64,
26 skin_region_count: i64,
27 largest_area: i64,
28 second_area: i64,
29 second_to_largest_q10: i64,
30 severity_q10: i64,
31 fidelity_q10: i64,
32}
33
34func nx_multi_body_compute(rgb: *Image, verdict: *MultiBodyVerdict) -> i64 {
35 verdict.kind = NX_MB_NO_BODY
36 verdict.skin_region_count = 0
37 verdict.largest_area = 0
38 verdict.second_area = 0
39 verdict.second_to_largest_q10 = 0
40 verdict.severity_q10 = 0
41 verdict.fidelity_q10 = 0
42
43 let total_area: i64 = rgb.width * rgb.height
44 if total_area <= 0 { return 1 }
45 let major_floor: i64 = (total_area * NX_MB_MAJOR_FLOOR_Q10) / NX_MAGIC_1024
46
47 let mask: *Image = nx_color_skin_mask(rgb)
48 let cc: *CCResult = nx_feat_connected_components(mask)
49 let n: i64 = cc.n_components
50 if n == 0 { return 0 }
51
52 let stats: *i64 = (sys_mmap(n * 7 * 8 + 16)) as *i64
53 nx_feat_component_stats(cc, stats)
54
55 var count: i64 = 0
56 var largest: i64 = 0
57 var second: i64 = 0
58 var i: i64 = 0
59 while i < n {
60 let area: i64 = stats[i * 7]
61 if area >= major_floor {
62 count = count + 1
63 if area > largest { second = largest; largest = area }
64 if area <= largest {
65 if area > second { second = area }
66 }
67 }
68 i = i + 1
69 }
70 verdict.skin_region_count = count
71 verdict.largest_area = largest
72 verdict.second_area = second
73 if largest > 0 { verdict.second_to_largest_q10 = (second * NX_MAGIC_1024) / largest }
74 if count == 0 { verdict.kind = NX_MB_NO_BODY }
75 if count == 1 { verdict.kind = NX_MB_SOLO }
76 if count == 2 { verdict.kind = NX_MB_TWO_BODY }
77 if count >= 3 { verdict.kind = NX_MB_MULTI_BODY }
78 var fid: i64 = 256
79 if count >= 1 { fid = 768 }
80 if count >= 2 { fid = NX_MAGIC_1024 }
81 verdict.fidelity_q10 = fid
82 return 0
83}