nx_undertone_class.nx
buildroot/runtime/nx_undertone_class.nx
about
nx_undertone_class.nx -- Tier 4 skin-undertone classification.
Tier 4 of nxc2/docs/IMAGE_VALIDATION_AMBIGUITY_LADDER.md.
Where ITA (nx_skin_tone_ita) classifies the LIGHT-TO-DARK axis
(luminance + b*), undertone classifies the CHROMA TYPE axis
(cool / warm / neutral) -- the dimension that makes the SAME ITA
band look "golden" vs "pink".
Standard cosmetic-industry definition (Suzuki 1987, Fitzpatrick
1988 supplement, Robinson-Bostom & DiGiovanna 2010):
h_ab = atan2(b*, a*) -- CIELab hue angle in degrees
For typical skin h_ab falls in [30, 80] degrees.
Within that range:
h_ab > 55 -> WARM (golden / yellow leaning)
45..55 -> NEUTRAL (balanced)
h_ab < 45 -> COOL (pink / red leaning)
Outside [20, 90]: classifier returns INVALID_RANGE -- the
pixel sample isn't typical-skin chroma; caller likely fed
a non-skin region.
Confidence proxy in Q10: distance from nearest threshold. Larger
distance from the WARM/COOL boundary = higher confidence in the
classification.
genealogy_id: suzuki_1987_robinson_2010
lineage_id: substrate_skin_chroma_v1
dependencies 3 imports · 3 importers
imports: nx_syscalls.nxnx_runtime.nxnx_tier.nx
imported by: nx_image_grade_v0.nxnx_image_grade_v1.nxnx_image_grade_v2.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| 70 | struct NxUndertoneResult |
consts
| 40 | const NX_MAGIC_46080: i64 = 46080 |
| 41 | const NX_MAGIC_27203: i64 = 27203 |
| 42 | const NX_MAGIC_14373: i64 = 14373 |
| 43 | const NX_MAGIC_7296: i64 = 7296 |
| 44 | const NX_MAGIC_3662: i64 = 3662 |
| 45 | const NX_MAGIC_1833: i64 = 1833 |
| 46 | const NX_MAGIC_1024: i64 = 1024 |
| 48 | const NX_UT_Q10: nx_int = 1024 |
| 51 | const NX_UT_INVALID: nx_int = 0 |
| 52 | const NX_UT_COOL: nx_int = 1 |
| 53 | const NX_UT_NEUTRAL: nx_int = 2 |
| 54 | const NX_UT_WARM: nx_int = 3 |
| 55 | const NX_UT_N_CLASSES: nx_int = 4 |
| 58 | const NX_UT_THR_WARM_Q10: nx_int = 56320 // 55 deg |
| 59 | const NX_UT_THR_NEUTRAL_LO: nx_int = 46080 // 45 deg |
| 60 | const NX_UT_THR_VALID_LO: nx_int = 20480 // 20 deg |
| 61 | const NX_UT_THR_VALID_HI: nx_int = 92160 // 90 deg |
| 66 | const NX_UT_CONF_DEG_MAX: nx_int = 35 |
| 79 | const NX_UT_RESULT_BYTES: nx_size = 48 |
| 88 | const NX_UT_CORDIC_ITERS: nx_int = 8 |
functions
| 90 | func _ut_cordic_angle_q10(i: nx_int) -> nx_int called by 1: _ut_atan2_q10 |
| 102 | func _ut_atan2_q10(y_q10: nx_int, x_q10: nx_int) -> nx_int |
| 153 | func _ut_distance_from_boundary_q10(h_q10: nx_int, verdict: nx_int) -> nx_int called by 1: nx_undertone_classify |
| 173 | func nx_undertone_classify(a_q10: nx_int, b_q10: nx_int) -> *NxUndertoneResult |
| 220 | func main() -> nx_int calls 1: nx_undertone_classify |