nx_body_flush.nx source
↩ module page · 180 lines · 6673 B
1// nx_body_flush.nx -- body-wide flush + mottle-pattern detector.
2//
3// Arousal flush extends beyond cheeks — chest, neck, decolletage,
4// ears all redden visibly. The pattern is MOTTLED (patchy, uneven)
5// not uniform. Substrate measures:
6// 1. Mean R-elevation per body region vs reference baseline
7// 2. Variance of R-channel within region (mottle = high variance)
8//
9// Inputs:
10// rgb image + skin mask
11// bbox pack (16 entries, 4 bboxes):
12// [0..3] reference_baseline (cool neutral skin area, e.g. shoulder)
13// [4..7] chest_region
14// [8..11] neck_region
15// [12..15] decolletage_region
16//
17// Output flat-array:
18// result[0] chest_R_delta (mean R - baseline R)
19// result[1] neck_R_delta
20// result[2] decolletage_R_delta
21// result[3] chest_R_variance
22// result[4] neck_R_variance
23// result[5] decolletage_R_variance
24// result[6] total_flush_score_q10 (composite 0..1024)
25// result[7] mottle_score_q10 (composite variance vs threshold)
26// result[8] verdict
27// 0=NO_FLUSH, 1=MILD_FLUSH, 2=AROUSAL_FLUSH, 3=INTENSE_AROUSAL_FLUSH
28
29// nx_safety_envelope:
30// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
31// sil_target: SIL1
32// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
33// verdict: NOT_YET_EVALUATED
34
35import "nx_syscalls.nx"
36import "nx_image.nx"
37const NX_MAGIC_1024: i64 = 1024
38
39const NX_FLUSH_RES_CHEST_R: i64 = 0
40const NX_FLUSH_RES_NECK_R: i64 = 1
41const NX_FLUSH_RES_DECOL_R: i64 = 2
42const NX_FLUSH_RES_CHEST_VAR: i64 = 3
43const NX_FLUSH_RES_NECK_VAR: i64 = 4
44const NX_FLUSH_RES_DECOL_VAR: i64 = 5
45const NX_FLUSH_RES_FLUSH_SCORE: i64 = 6
46const NX_FLUSH_RES_MOTTLE_SCORE: i64 = 7
47const NX_FLUSH_RES_VERDICT: i64 = 8
48const NX_FLUSH_RES_FIELDS: i64 = 9
49
50const NX_FLUSH_VERDICT_NONE: i64 = 0
51const NX_FLUSH_VERDICT_MILD: i64 = 1
52const NX_FLUSH_VERDICT_AROUSAL: i64 = 2
53const NX_FLUSH_VERDICT_INTENSE: i64 = 3
54
55const NX_FLUSH_R_DELTA_MILD: i64 = 10
56const NX_FLUSH_R_DELTA_AROUSAL: i64 = 20
57const NX_FLUSH_R_DELTA_INTENSE: i64 = 35
58const NX_FLUSH_MOTTLE_THRESH: i64 = 100 // variance threshold for patchy
59
60// Compute mean R + R-variance over a bbox region (skin pixels only).
61// Writes to out[0]=mean_R, out[1]=variance.
62func nx_flush_mean_variance_r(rgb: *Image, mask: *Image,
63 x0: i64, y0: i64, x1: i64, y1: i64,
64 out: *i64) -> i64 {
65 var sum: i64 = 0
66 var n: i64 = 0
67 var y: i64 = y0
68 while y <= y1 {
69 if y >= 0 { if y < rgb.height {
70 var x: i64 = x0
71 while x <= x1 {
72 if x >= 0 { if x < rgb.width {
73 if nx_image_get(mask, x, y, 0) > 0 {
74 sum = sum + nx_image_get(rgb, x, y, 0)
75 n = n + 1
76 }
77 } }
78 x = x + 1
79 }
80 } }
81 y = y + 1
82 }
83 if n == 0 {
84 out[0] = 0
85 out[1] = 0
86 return 0
87 }
88 let mean: i64 = sum / n
89 // Variance: sum of (R - mean)^2 / n.
90 var sq_sum: i64 = 0
91 y = y0
92 while y <= y1 {
93 if y >= 0 { if y < rgb.height {
94 var x: i64 = x0
95 while x <= x1 {
96 if x >= 0 { if x < rgb.width {
97 if nx_image_get(mask, x, y, 0) > 0 {
98 let r: i64 = nx_image_get(rgb, x, y, 0)
99 let d: i64 = r - mean
100 sq_sum = sq_sum + d * d
101 }
102 } }
103 x = x + 1
104 }
105 } }
106 y = y + 1
107 }
108 out[0] = mean
109 out[1] = sq_sum / n
110 return n
111}
112
113// Score the body flush + mottle pattern.
114// bbox_pack: 16 i64 (4 bboxes: baseline, chest, neck, decolletage)
115func nx_body_flush(rgb: *Image, skin_mask: *Image, bbox_pack: *i64,
116 result: *i64) -> i64 {
117 var i: i64 = 0
118 while i < NX_FLUSH_RES_FIELDS { result[i] = 0; i = i + 1 }
119
120 let mv: *i64 = (sys_mmap(2 * 8 + 16)) as *i64
121
122 // Baseline R.
123 nx_flush_mean_variance_r(rgb, skin_mask,
124 bbox_pack[0], bbox_pack[1],
125 bbox_pack[2], bbox_pack[3], mv)
126 let baseline_r: i64 = mv[0]
127
128 // Chest.
129 nx_flush_mean_variance_r(rgb, skin_mask,
130 bbox_pack[4], bbox_pack[5],
131 bbox_pack[6], bbox_pack[7], mv)
132 let chest_r: i64 = mv[0]
133 let chest_var: i64 = mv[1]
134 let chest_delta: i64 = chest_r - baseline_r
135 result[NX_FLUSH_RES_CHEST_R] = chest_delta
136 result[NX_FLUSH_RES_CHEST_VAR] = chest_var
137
138 // Neck.
139 nx_flush_mean_variance_r(rgb, skin_mask,
140 bbox_pack[8], bbox_pack[9],
141 bbox_pack[10], bbox_pack[11], mv)
142 let neck_r: i64 = mv[0]
143 let neck_var: i64 = mv[1]
144 let neck_delta: i64 = neck_r - baseline_r
145 result[NX_FLUSH_RES_NECK_R] = neck_delta
146 result[NX_FLUSH_RES_NECK_VAR] = neck_var
147
148 // Decolletage.
149 nx_flush_mean_variance_r(rgb, skin_mask,
150 bbox_pack[12], bbox_pack[13],
151 bbox_pack[14], bbox_pack[15], mv)
152 let decol_r: i64 = mv[0]
153 let decol_var: i64 = mv[1]
154 let decol_delta: i64 = decol_r - baseline_r
155 result[NX_FLUSH_RES_DECOL_R] = decol_delta
156 result[NX_FLUSH_RES_DECOL_VAR] = decol_var
157
158 // Composite flush score: mean of the 3 deltas, scaled.
159 var max_delta: i64 = chest_delta
160 if neck_delta > max_delta { max_delta = neck_delta }
161 if decol_delta > max_delta { max_delta = decol_delta }
162 if max_delta < 0 { max_delta = 0 }
163 let flush_score: i64 = (max_delta * NX_MAGIC_1024) / NX_FLUSH_R_DELTA_INTENSE
164 var flush_clamped: i64 = flush_score
165 if flush_clamped > NX_MAGIC_1024 { flush_clamped = NX_MAGIC_1024 }
166 result[NX_FLUSH_RES_FLUSH_SCORE] = flush_clamped
167
168 // Mottle: average variance / threshold, capped at Q10.
169 let avg_var: i64 = (chest_var + neck_var + decol_var) / 3
170 var mottle: i64 = (avg_var * NX_MAGIC_1024) / NX_FLUSH_MOTTLE_THRESH
171 if mottle > NX_MAGIC_1024 { mottle = NX_MAGIC_1024 }
172 result[NX_FLUSH_RES_MOTTLE_SCORE] = mottle
173
174 var verdict: i64 = NX_FLUSH_VERDICT_NONE
175 if max_delta >= NX_FLUSH_R_DELTA_INTENSE { verdict = NX_FLUSH_VERDICT_INTENSE }
176 else { if max_delta >= NX_FLUSH_R_DELTA_AROUSAL { verdict = NX_FLUSH_VERDICT_AROUSAL }
177 else { if max_delta >= NX_FLUSH_R_DELTA_MILD { verdict = NX_FLUSH_VERDICT_MILD } } }
178 result[NX_FLUSH_RES_VERDICT] = verdict
179 return 0
180}