nx_haar_xml.nx source
↩ module page · 346 lines · 16298 B
1// nx_haar_xml.nx -- LOADER for a boosted Haar cascade published in the OpenCV 3+ XML schema (aesthetictwin AT30, 2026-09-16).
2// The trained data the field publishes (haarcascade_*.xml: 24x24 or 20x20 windows, stumps or depth-2 trees, rect features
3// with integer weights) enters the estate as a DATA asset mirrored beside its licence (knowledge/fetched/
4// cmp_aesthetictwin_haar_*.xml + cmp_aesthetictwin_haar_LICENSE.txt, Intel/OpenCV BSD-style and Apache-2.0). It is a
5// BETA-ONLY BOOTSTRAP ARM: the evaluator engine (nx_haar_cascade) is sovereign and stays; the data is replaced by a cascade the
6// estate trains itself (the R-FACE training rung) before any product path carries it, because NishiOS and the browser ship
7// no third-party bytes and no third-party licence. Every real number is fixed-point Q24 (one arithmetic for thresholds,
8// leaf values and weights); a tilted feature, a tree deeper than the shipped data uses, or a file without the <cascade>
9// root is REFUSED BY NAME, never evaluated wrong.
10// Layout of the loaded cascade (flat i64 arrays, see HC_* in nx_haar_cascade):
11// hdr [win_w, win_h, n_stages, n_weak, n_nodes, n_leaves, n_feats, max_rects]
12// stage [first_weak, n_weak, threshold_q24]
13// weak [first_node, n_nodes, first_leaf, n_leaves]
14// node [left, right, feature_idx, threshold_q24] (left/right > 0: node index within the tree; <= 0: leaf index = -value)
15// leaf [value_q24]
16// feat [n_rects, (x, y, w, h, weight_q24) x 3]
17// license_tier: ORIGINAL No hw writes (Rule 26).
18import "nx_syscalls.nx"
19import "nx_haar_cascade.nx"
20
21const HX_SP: i64 = 32
22const HX_TAB: i64 = 9
23const HX_NL: i64 = 10
24const HX_CR: i64 = 13
25const HX_MINUS: i64 = 45
26const HX_PLUS: i64 = 43
27const HX_DOT: i64 = 46
28const HX_D0: i64 = 48
29const HX_D9: i64 = 57
30const HX_LC_E: i64 = 101
31const HX_UC_E: i64 = 69
32const HX_ONE: i64 = 49
33const HX_BYTE: i64 = 255
34const HX_TEN: i64 = 10
35const HX_Q24: i64 = 16777216
36const HX_MANT_DIGITS: i64 = 11
37const HX_I64: i64 = 8
38const HX_OUT_N: i64 = 2
39const HX_NUMS_B: i64 = 64
40const HX_MAX_TREE_NODES: i64 = 8
41const HX_OK: i64 = 0
42const HX_E_READ: i64 = 0 - 1
43const HX_E_NOT_CASCADE: i64 = 0 - 2
44const HX_E_TILTED: i64 = 0 - 3
45const HX_E_SHAPE: i64 = 0 - 4
46const HX_E_TREE: i64 = 0 - 5
47const HX_E_FEATURE: i64 = 0 - 6
48const HX_E_EMPTY: i64 = 0 - 7
49const HX_T_CASCADE: *u8 = "<cascade" // the root carries an attribute (type_id) in the published files, so the prefix is the key
50const HX_T_HEIGHT: *u8 = "<height>"
51const HX_T_WIDTH: *u8 = "<width>"
52const HX_T_STAGE_THR: *u8 = "<stageThreshold>"
53const HX_T_STAGE_END: *u8 = "</stageThreshold>"
54const HX_T_WEAKS: *u8 = "<weakClassifiers>"
55const HX_T_WEAKS_END: *u8 = "</weakClassifiers>"
56const HX_T_NODES: *u8 = "<internalNodes>"
57const HX_T_NODES_END: *u8 = "</internalNodes>"
58const HX_T_LEAVES: *u8 = "<leafValues>"
59const HX_T_LEAVES_END: *u8 = "</leafValues>"
60const HX_T_FEATURES: *u8 = "<features>"
61const HX_T_RECTS: *u8 = "<rects>"
62const HX_T_RECTS_END: *u8 = "</rects>"
63const HX_T_ENTRY: *u8 = "<_>"
64const HX_T_ENTRY_END: *u8 = "</_>"
65const HX_T_TILTED: *u8 = "<tilted>"
66
67func hx_is_ws(c: i64) -> i64 { if c == HX_SP { return 1 } if c == HX_NL { return 1 } if c == HX_CR { return 1 } if c == HX_TAB { return 1 } return 0 }
68func hx_is_digit(c: i64) -> i64 { if c < HX_D0 { return 0 } if c > HX_D9 { return 0 } return 1 }
69func hx_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
70func hx_skip_ws(b: *u8, n: i64, pos: i64) -> i64 {
71 var p: i64 = pos
72 var go: i64 = 1
73 while go == 1 { if p >= n { go = 0 } else { if hx_is_ws((b[p] as i64) & HX_BYTE) == 1 { p = p + 1 } else { go = 0 } } }
74 return p
75}
76// index of the next occurrence of tag at or after pos, or -1
77func hx_find(b: *u8, n: i64, pos: i64, tag: *u8) -> i64 {
78 let tl: i64 = hx_slen(tag)
79 var p: i64 = pos
80 while p + tl <= n {
81 var k: i64 = 0
82 var same: i64 = 1
83 while k < tl { if b[p + k] != tag[k] { same = 0; k = tl } else { k = k + 1 } }
84 if same == 1 { return p }
85 p = p + 1
86 }
87 return 0 - 1
88}
89// a decimal token (sign, digits, optional fraction, optional exponent) as Q24; out[0] = value, out[1] = position after it
90func hx_num_q24(b: *u8, n: i64, pos: i64, out: *i64) -> i64 {
91 var p: i64 = hx_skip_ws(b, n, pos)
92 if p >= n { return 0 }
93 var neg: i64 = 0
94 var c: i64 = (b[p] as i64) & HX_BYTE
95 if c == HX_MINUS { neg = 1; p = p + 1 } else { if c == HX_PLUS { p = p + 1 } }
96 var mant: i64 = 0
97 var ndig: i64 = 0
98 var any: i64 = 0
99 var exp10: i64 = 0
100 var go: i64 = 1
101 while go == 1 {
102 if p >= n { go = 0 } else {
103 c = (b[p] as i64) & HX_BYTE
104 if hx_is_digit(c) == 1 {
105 any = 1
106 if ndig < HX_MANT_DIGITS { mant = mant * HX_TEN + (c - HX_D0); if mant > 0 { ndig = ndig + 1 } } else { exp10 = exp10 + 1 }
107 p = p + 1
108 } else { go = 0 }
109 }
110 }
111 if p < n { if ((b[p] as i64) & HX_BYTE) == HX_DOT {
112 p = p + 1
113 go = 1
114 while go == 1 {
115 if p >= n { go = 0 } else {
116 c = (b[p] as i64) & HX_BYTE
117 if hx_is_digit(c) == 1 {
118 any = 1
119 if ndig < HX_MANT_DIGITS { mant = mant * HX_TEN + (c - HX_D0); exp10 = exp10 - 1; if mant > 0 { ndig = ndig + 1 } }
120 p = p + 1
121 } else { go = 0 }
122 }
123 }
124 } }
125 if any == 0 { return 0 }
126 if p < n {
127 c = (b[p] as i64) & HX_BYTE
128 var isexp: i64 = 0
129 if c == HX_LC_E { isexp = 1 }
130 if c == HX_UC_E { isexp = 1 }
131 if isexp == 1 {
132 p = p + 1
133 var eneg: i64 = 0
134 if p < n { c = (b[p] as i64) & HX_BYTE; if c == HX_MINUS { eneg = 1; p = p + 1 } else { if c == HX_PLUS { p = p + 1 } } }
135 var e: i64 = 0
136 go = 1
137 while go == 1 { if p >= n { go = 0 } else { c = (b[p] as i64) & HX_BYTE; if hx_is_digit(c) == 1 { e = e * HX_TEN + (c - HX_D0); p = p + 1 } else { go = 0 } } }
138 if eneg == 1 { exp10 = exp10 - e } else { exp10 = exp10 + e }
139 }
140 }
141 var v: i64 = mant * HX_Q24
142 while exp10 > 0 { v = v * HX_TEN; exp10 = exp10 - 1 }
143 while exp10 < 0 { v = v / HX_TEN; exp10 = exp10 + 1 }
144 if neg == 1 { v = 0 - v }
145 out[0] = v
146 out[1] = p
147 return 1
148}
149// an integer token; out[0] = value, out[1] = position after it
150func hx_int(b: *u8, n: i64, pos: i64, out: *i64) -> i64 {
151 var p: i64 = hx_skip_ws(b, n, pos)
152 if p >= n { return 0 }
153 var neg: i64 = 0
154 var c: i64 = (b[p] as i64) & HX_BYTE
155 if c == HX_MINUS { neg = 1; p = p + 1 }
156 var v: i64 = 0
157 var any: i64 = 0
158 var go: i64 = 1
159 while go == 1 { if p >= n { go = 0 } else { c = (b[p] as i64) & HX_BYTE; if hx_is_digit(c) == 1 { v = v * HX_TEN + (c - HX_D0); any = 1; p = p + 1 } else { go = 0 } } }
160 if any == 0 { return 0 }
161 if neg == 1 { v = 0 - v }
162 out[0] = v
163 out[1] = p
164 return 1
165}
166// count the occurrences of tag in b[pos..n)
167func hx_count(b: *u8, n: i64, pos: i64, tag: *u8) -> i64 {
168 var c: i64 = 0
169 var p: i64 = hx_find(b, n, pos, tag)
170 while p >= 0 { c = c + 1; p = hx_find(b, n, p + 1, tag) }
171 return c
172}
173// the integer inside the first <tag>..</tag> at or after pos, or -1
174func hx_tag_int(b: *u8, n: i64, pos: i64, tag: *u8, out: *i64) -> i64 {
175 let p: i64 = hx_find(b, n, pos, tag)
176 if p < 0 { return 0 - 1 }
177 if hx_int(b, n, p + hx_slen(tag), out) == 0 { return 0 - 1 }
178 return out[0]
179}
180// LOAD a cascade file; rc_out[0] carries HX_OK or the named refusal; returns 0 on refusal
181func hx_load(path: *u8, rc_out: *i64) -> *HaarCascade {
182 let fl: *i64 = sys_mmap(16) as *i64
183 fl[0] = 0
184 let b: *u8 = sys_read_file(path, fl)
185 if (b as i64) == 0 { rc_out[0] = HX_E_READ; return 0 as *HaarCascade }
186 let n: i64 = fl[0]
187 if n <= 0 { rc_out[0] = HX_E_READ; return 0 as *HaarCascade }
188 return hx_parse(b, n, rc_out)
189}
190// PARSE a cascade held in memory (the loader's core, drivable by a gate on planted text)
191func hx_parse(b: *u8, n: i64, rc_out: *i64) -> *HaarCascade {
192 let root: i64 = hx_find(b, n, 0, HX_T_CASCADE)
193 if root < 0 { rc_out[0] = HX_E_NOT_CASCADE; return 0 as *HaarCascade }
194 // a tilted feature is refused by name: this engine evaluates upright rectangles only
195 var tp: i64 = hx_find(b, n, root, HX_T_TILTED)
196 while tp >= 0 {
197 let q: i64 = hx_skip_ws(b, n, tp + hx_slen(HX_T_TILTED))
198 if q < n { if ((b[q] as i64) & HX_BYTE) == HX_ONE { rc_out[0] = HX_E_TILTED; return 0 as *HaarCascade } }
199 tp = hx_find(b, n, tp + 1, HX_T_TILTED)
200 }
201 let out: *i64 = sys_mmap(HX_OUT_N * HX_I64) as *i64
202 let winh: i64 = hx_tag_int(b, n, root, HX_T_HEIGHT, out)
203 let winw: i64 = hx_tag_int(b, n, root, HX_T_WIDTH, out)
204 if winh <= 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
205 if winw <= 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
206 let n_stages: i64 = hx_count(b, n, root, HX_T_STAGE_THR)
207 let n_weak: i64 = hx_count(b, n, root, HX_T_NODES)
208 let n_feats: i64 = hx_count(b, n, root, HX_T_RECTS)
209 if n_stages <= 0 { rc_out[0] = HX_E_EMPTY; return 0 as *HaarCascade }
210 if n_weak <= 0 { rc_out[0] = HX_E_EMPTY; return 0 as *HaarCascade }
211 if n_feats <= 0 { rc_out[0] = HX_E_EMPTY; return 0 as *HaarCascade }
212 let c: *HaarCascade = sys_mmap(HC_BYTES) as *HaarCascade
213 c.hdr = sys_mmap(HC_HDR_N * HX_I64) as *i64
214 c.stages = sys_mmap(n_stages * HC_STAGE_FIELDS * HX_I64) as *i64
215 c.weaks = sys_mmap(n_weak * HC_WEAK_FIELDS * HX_I64) as *i64
216 c.nodes = sys_mmap(n_weak * HX_MAX_TREE_NODES * HC_NODE_FIELDS * HX_I64) as *i64
217 c.leaves = sys_mmap(n_weak * (HX_MAX_TREE_NODES + 1) * HX_I64) as *i64
218 c.feats = sys_mmap(n_feats * HC_FEAT_FIELDS * HX_I64) as *i64
219 c.hdr[HC_H_WINW] = winw
220 c.hdr[HC_H_WINH] = winh
221 c.hdr[HC_H_NSTAGES] = n_stages
222 c.hdr[HC_H_NWEAK] = n_weak
223 c.hdr[HC_H_NFEATS] = n_feats
224 c.hdr[HC_H_MAXRECTS] = HC_MAX_RECTS
225 // stages and their weak classifiers, in file order
226 var pos: i64 = root
227 var si: i64 = 0
228 var wi: i64 = 0
229 var ni: i64 = 0
230 var li: i64 = 0
231 while si < n_stages {
232 let sp: i64 = hx_find(b, n, pos, HX_T_STAGE_THR)
233 if sp < 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
234 if hx_num_q24(b, n, sp + hx_slen(HX_T_STAGE_THR), out) == 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
235 let so: i64 = si * HC_STAGE_FIELDS
236 c.stages[so + HC_S_THR] = out[0]
237 c.stages[so + HC_S_FIRST] = wi
238 let wstart: i64 = hx_find(b, n, sp, HX_T_WEAKS)
239 if wstart < 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
240 let wend: i64 = hx_find(b, n, wstart, HX_T_WEAKS_END)
241 if wend < 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
242 var np: i64 = hx_find(b, n, wstart, HX_T_NODES)
243 var count: i64 = 0
244 while np >= 0 { if np > wend { np = 0 - 1 } else {
245 if wi >= n_weak { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
246 let nend: i64 = hx_find(b, n, np, HX_T_NODES_END)
247 if nend < 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
248 let wo: i64 = wi * HC_WEAK_FIELDS
249 c.weaks[wo + HC_W_FIRST_NODE] = ni
250 c.weaks[wo + HC_W_FIRST_LEAF] = li
251 var q: i64 = np + hx_slen(HX_T_NODES)
252 var tn: i64 = 0
253 var more: i64 = 1
254 while more == 1 {
255 let q0: i64 = hx_skip_ws(b, n, q)
256 if q0 >= nend { more = 0 } else {
257 if tn >= HX_MAX_TREE_NODES { rc_out[0] = HX_E_TREE; return 0 as *HaarCascade }
258 let no: i64 = ni * HC_NODE_FIELDS
259 if hx_int(b, n, q0, out) == 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
260 c.nodes[no + HC_N_LEFT] = out[0]
261 if hx_int(b, n, out[1], out) == 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
262 c.nodes[no + HC_N_RIGHT] = out[0]
263 if hx_int(b, n, out[1], out) == 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
264 c.nodes[no + HC_N_FEAT] = out[0]
265 if out[0] < 0 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
266 if out[0] >= n_feats { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
267 if hx_num_q24(b, n, out[1], out) == 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
268 c.nodes[no + HC_N_THR] = out[0]
269 q = out[1]
270 ni = ni + 1
271 tn = tn + 1
272 }
273 }
274 c.weaks[wo + HC_W_N_NODES] = tn
275 let lp: i64 = hx_find(b, n, nend, HX_T_LEAVES)
276 if lp < 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
277 let lend: i64 = hx_find(b, n, lp, HX_T_LEAVES_END)
278 if lend < 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
279 q = lp + hx_slen(HX_T_LEAVES)
280 var tl: i64 = 0
281 more = 1
282 while more == 1 {
283 let q1: i64 = hx_skip_ws(b, n, q)
284 if q1 >= lend { more = 0 } else {
285 if tl > HX_MAX_TREE_NODES { rc_out[0] = HX_E_TREE; return 0 as *HaarCascade }
286 if hx_num_q24(b, n, q1, out) == 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
287 c.leaves[li] = out[0]
288 q = out[1]
289 li = li + 1
290 tl = tl + 1
291 }
292 }
293 c.weaks[wo + HC_W_N_LEAVES] = tl
294 if tl != tn + 1 { rc_out[0] = HX_E_TREE; return 0 as *HaarCascade }
295 wi = wi + 1
296 count = count + 1
297 np = hx_find(b, n, lend, HX_T_NODES)
298 } }
299 c.stages[so + HC_S_N] = count
300 pos = wend
301 si = si + 1
302 }
303 if wi != n_weak { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
304 c.hdr[HC_H_NNODES] = ni
305 c.hdr[HC_H_NLEAVES] = li
306 // the features, in file order: each <rects> holds two or three <_>x y w h weight</_> entries
307 var fp: i64 = hx_find(b, n, root, HX_T_FEATURES)
308 if fp < 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
309 var fi: i64 = 0
310 while fi < n_feats {
311 let rp: i64 = hx_find(b, n, fp, HX_T_RECTS)
312 if rp < 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
313 let rend: i64 = hx_find(b, n, rp, HX_T_RECTS_END)
314 if rend < 0 { rc_out[0] = HX_E_SHAPE; return 0 as *HaarCascade }
315 let fo: i64 = fi * HC_FEAT_FIELDS
316 var nr: i64 = 0
317 var ep: i64 = hx_find(b, n, rp, HX_T_ENTRY)
318 while ep >= 0 { if ep > rend { ep = 0 - 1 } else {
319 if nr >= HC_MAX_RECTS { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
320 let ro: i64 = fo + HC_F_RECTS + nr * HC_RECT_FIELDS
321 var q: i64 = ep + hx_slen(HX_T_ENTRY)
322 if hx_int(b, n, q, out) == 0 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
323 c.feats[ro + HC_R_X] = out[0]
324 if hx_int(b, n, out[1], out) == 0 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
325 c.feats[ro + HC_R_Y] = out[0]
326 if hx_int(b, n, out[1], out) == 0 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
327 c.feats[ro + HC_R_W] = out[0]
328 if hx_int(b, n, out[1], out) == 0 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
329 c.feats[ro + HC_R_H] = out[0]
330 if hx_num_q24(b, n, out[1], out) == 0 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
331 c.feats[ro + HC_R_WEIGHT] = out[0]
332 if c.feats[ro + HC_R_W] <= 0 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
333 if c.feats[ro + HC_R_H] <= 0 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
334 nr = nr + 1
335 let eend: i64 = hx_find(b, n, out[1], HX_T_ENTRY_END)
336 if eend < 0 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
337 ep = hx_find(b, n, eend, HX_T_ENTRY)
338 } }
339 if nr < 2 { rc_out[0] = HX_E_FEATURE; return 0 as *HaarCascade }
340 c.feats[fo + HC_F_N] = nr
341 fp = rend
342 fi = fi + 1
343 }
344 rc_out[0] = HX_OK
345 return c
346}