nx_uncanny_valley.nx source
↩ module page · 99 lines · 4645 B
1// nx_uncanny_valley.nx -- composite "person doesn't belong in scene" detector.
2//
3// Image #58 failure class: subject feels SLIGHTLY pasted onto the
4// scene. Multiple sub-signals contribute:
5// 1. Lighting consistency (already shipped: nx_lighting_consistency)
6// 2. Shadow integration — does subject cast shadows on environment?
7// 3. Skin-too-perfect signal (mannequin index lookup)
8// 4. Edge-seam / chroma-fringe artifact on subject silhouette
9// 5. Subject-environment color cast match
10//
11// This composite takes the 5 sub-scores and emits one uncanny-valley
12// verdict. High = compositing-seam visible / pasted. Low = subject
13// belongs in scene.
14//
15// Output flat-array:
16// result[0..4] = per-axis Q10 scores
17// result[5] = composite_q10
18// result[6] = verdict
19// result[7] = failing_axis
20
21// nx_safety_envelope:
22// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
23// sil_target: SIL1
24// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
25// verdict: NOT_YET_EVALUATED
26
27import "nx_syscalls.nx"
28const NX_MAGIC_2048: i64 = 2048
29
30const NX_UNCANNY_RES_LIGHTING: i64 = 0
31const NX_UNCANNY_RES_SHADOW: i64 = 1
32const NX_UNCANNY_RES_MANNEQUIN: i64 = 2
33const NX_UNCANNY_RES_EDGE_SEAM: i64 = 3
34const NX_UNCANNY_RES_COLOR_CAST: i64 = 4
35const NX_UNCANNY_RES_COMPOSITE: i64 = 5
36const NX_UNCANNY_RES_VERDICT: i64 = 6
37const NX_UNCANNY_RES_FAIL_AXIS: i64 = 7
38const NX_UNCANNY_RES_FIELDS: i64 = 8
39
40const NX_UNCANNY_V_PASTED_IN: i64 = 0
41const NX_UNCANNY_V_NOTICEABLE: i64 = 1
42const NX_UNCANNY_V_ACCEPTABLE: i64 = 2
43const NX_UNCANNY_V_BELONGS_IN_SCENE: i64 = 3
44
45const NX_UNCANNY_AXIS_LIGHTING: i64 = 0
46const NX_UNCANNY_AXIS_SHADOW: i64 = 1
47const NX_UNCANNY_AXIS_MANNEQUIN: i64 = 2
48const NX_UNCANNY_AXIS_EDGE_SEAM: i64 = 3
49const NX_UNCANNY_AXIS_COLOR_CAST: i64 = 4
50
51// Aggregate 5 axis scores. Each input is Q10 0..1024.
52// Pass -1 to mark "not measured" (axis skipped from composite).
53// lighting from nx_lighting_consistency composite
54// shadow presence/quality of subject-cast shadows on env (-1 if unavail)
55// mannequin from nx_mannequin_index (high = LIVING_PERSON)
56// edge_seam silhouette-edge cleanness (1024 = no seam visible)
57// color_cast subject color tint matches environment global cast
58//
59// Weighting: lighting 25 / shadow 20 / mannequin 25 / edge 15 / color 15.
60func nx_uncanny_valley(lighting_q10: i64, shadow_q10: i64,
61 mannequin_q10: i64, edge_seam_q10: i64,
62 color_cast_q10: i64, result: *i64) -> i64 {
63 var i: i64 = 0
64 while i < NX_UNCANNY_RES_FIELDS { result[i] = 0; i = i + 1 }
65
66 result[NX_UNCANNY_RES_LIGHTING] = lighting_q10
67 result[NX_UNCANNY_RES_SHADOW] = shadow_q10
68 result[NX_UNCANNY_RES_MANNEQUIN] = mannequin_q10
69 result[NX_UNCANNY_RES_EDGE_SEAM] = edge_seam_q10
70 result[NX_UNCANNY_RES_COLOR_CAST] = color_cast_q10
71
72 var sum: i64 = 0
73 var wsum: i64 = 0
74 if lighting_q10 >= 0 { sum = sum + lighting_q10 * 25; wsum = wsum + 25 }
75 if shadow_q10 >= 0 { sum = sum + shadow_q10 * 20; wsum = wsum + 20 }
76 if mannequin_q10 >= 0 { sum = sum + mannequin_q10 * 25; wsum = wsum + 25 }
77 if edge_seam_q10 >= 0 { sum = sum + edge_seam_q10 * 15; wsum = wsum + 15 }
78 if color_cast_q10 >= 0 { sum = sum + color_cast_q10 * 15; wsum = wsum + 15 }
79 if wsum == 0 { return 1 }
80 let composite: i64 = sum / wsum
81 result[NX_UNCANNY_RES_COMPOSITE] = composite
82
83 var verdict: i64 = NX_UNCANNY_V_PASTED_IN
84 if composite >= 410 { verdict = NX_UNCANNY_V_NOTICEABLE }
85 if composite >= 614 { verdict = NX_UNCANNY_V_ACCEPTABLE }
86 if composite >= 819 { verdict = NX_UNCANNY_V_BELONGS_IN_SCENE }
87 result[NX_UNCANNY_RES_VERDICT] = verdict
88
89 // Failing axis (lowest measured).
90 var min_score: i64 = NX_MAGIC_2048
91 var min_axis: i64 = -1
92 if lighting_q10 >= 0 { if lighting_q10 < min_score { min_score = lighting_q10; min_axis = NX_UNCANNY_AXIS_LIGHTING } }
93 if shadow_q10 >= 0 { if shadow_q10 < min_score { min_score = shadow_q10; min_axis = NX_UNCANNY_AXIS_SHADOW } }
94 if mannequin_q10 >= 0 { if mannequin_q10 < min_score { min_score = mannequin_q10; min_axis = NX_UNCANNY_AXIS_MANNEQUIN } }
95 if edge_seam_q10 >= 0 { if edge_seam_q10 < min_score { min_score = edge_seam_q10; min_axis = NX_UNCANNY_AXIS_EDGE_SEAM } }
96 if color_cast_q10 >= 0 { if color_cast_q10 < min_score { min_score = color_cast_q10; min_axis = NX_UNCANNY_AXIS_COLOR_CAST } }
97 result[NX_UNCANNY_RES_FAIL_AXIS] = min_axis
98 return 0
99}