nx_skin_texture.nx source
↩ module page · 102 lines · 3925 B
1// nx_skin_texture.nx -- skin-texture realism detector.
2//
3// Pre-segmented-set convention: caller computes nx_region_segment(rgb)
4// in main() and passes set in. Verdict is allocated inside compute()
5// and returned by pointer. Field comparisons on the returned verdict
6// MUST bind through a local first (let k = v.kind; if k != X), per
7// docs/NISHILANG_TYPED_PRIMITIVES_GAP.md Gap 3.
8
9// nx_safety_envelope:
10// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
11// sil_target: SIL1
12// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
13// verdict: NOT_YET_EVALUATED
14
15import "nx_syscalls.nx"
16import "nx_image.nx"
17import "nx_features.nx"
18import "nx_texture.nx"
19import "nx_region.nx"
20
21const NX_ST_UNKNOWN: i64 = 0
22const NX_ST_NORMAL: i64 = 1
23const NX_ST_PLASTIC_SHEEN: i64 = 2
24const NX_ST_TOO_NOISY: i64 = 3
25
26const NX_ST_ENERGY_PLASTIC_Q10: i64 = 900
27const NX_ST_CONTRAST_PLASTIC_Q10: i64 = 50
28const NX_ST_CONTRAST_NOISY_Q10: i64 = 500
29const NX_ST_HOMOGENEITY_NOISY_Q10: i64 = 300
30
31struct SkinTextureVerdict {
32 kind: i64,
33 torso_present: i64,
34 torso_glcm_contrast_q10: i64,
35 torso_glcm_energy_q10: i64,
36 torso_glcm_homogeneity_q10: i64,
37 face_freckle_count: i64,
38 severity_q10: i64,
39 fidelity_q10: i64,
40}
41
42func nx_skin_crop_gray(src: *Image, x0: i64, y0: i64, x1: i64, y1: i64) -> *Image {
43 let w: i64 = x1 - x0
44 let h: i64 = y1 - y0
45 let dst: *Image = nx_image_alloc(w, h, 1)
46 var y: i64 = 0
47 while y < h {
48 var x: i64 = 0
49 while x < w {
50 nx_image_set(dst, x, y, 0, nx_image_get(src, x + x0, y + y0, 0))
51 x = x + 1
52 }
53 y = y + 1
54 }
55 return dst
56}
57
58func nx_skin_texture_compute(rgb: *Image, set: *RegionSet) -> *SkinTextureVerdict {
59 let verdict: *SkinTextureVerdict = (sys_mmap(96)) as *SkinTextureVerdict
60 verdict.kind = NX_ST_UNKNOWN
61 verdict.torso_present = 0
62 verdict.torso_glcm_contrast_q10 = 0
63 verdict.torso_glcm_energy_q10 = 0
64 verdict.torso_glcm_homogeneity_q10 = 0
65 verdict.face_freckle_count = 0
66 verdict.severity_q10 = 0
67 verdict.fidelity_q10 = 0
68
69 let t_idx: i64 = nx_region_find_kind(set, NX_REGION_TORSO)
70 if t_idx < 0 { return verdict }
71 verdict.torso_present = 1
72
73 let t_min_x: i64 = nx_region_get_field(set, t_idx, NX_REGION_F_BBOX_MIN_X)
74 let t_min_y: i64 = nx_region_get_field(set, t_idx, NX_REGION_F_BBOX_MIN_Y)
75 let t_max_x: i64 = nx_region_get_field(set, t_idx, NX_REGION_F_BBOX_MAX_X)
76 let t_max_y: i64 = nx_region_get_field(set, t_idx, NX_REGION_F_BBOX_MAX_Y)
77 let gray: *Image = nx_image_to_grayscale(rgb)
78 let torso_gray: *Image = nx_skin_crop_gray(gray, t_min_x, t_min_y, t_max_x + 1, t_max_y + 1)
79 let glcm: *i64 = (sys_mmap(64 * 8 + 16)) as *i64
80 nx_texture_glcm(torso_gray, 1, 0, glcm)
81 verdict.torso_glcm_contrast_q10 = nx_texture_contrast(glcm)
82 verdict.torso_glcm_energy_q10 = nx_texture_energy(glcm)
83 verdict.torso_glcm_homogeneity_q10 = nx_texture_homogeneity(glcm)
84
85 var kind: i64 = NX_ST_NORMAL
86 var sev: i64 = 0
87 let energy: i64 = verdict.torso_glcm_energy_q10
88 let contrast: i64 = verdict.torso_glcm_contrast_q10
89 let homo: i64 = verdict.torso_glcm_homogeneity_q10
90 if energy >= NX_ST_ENERGY_PLASTIC_Q10 {
91 if contrast < NX_ST_CONTRAST_PLASTIC_Q10 { kind = NX_ST_PLASTIC_SHEEN; sev = 768 }
92 }
93 if kind == NX_ST_NORMAL {
94 if contrast > NX_ST_CONTRAST_NOISY_Q10 {
95 if homo < NX_ST_HOMOGENEITY_NOISY_Q10 { kind = NX_ST_TOO_NOISY; sev = 384 }
96 }
97 }
98 verdict.kind = kind
99 verdict.severity_q10 = sev
100 verdict.fidelity_q10 = nx_region_get_field(set, t_idx, NX_REGION_F_CONF_Q10)
101 return verdict
102}