code wiki / (root) / nx_skin_pore_detail.nx

nx_skin_pore_detail.nx source

↩ module page · 115 lines · 4118 B

1// nx_skin_pore_detail.nx -- high-frequency pore-scale texture detector. 2// 3// At 8k+ render quality real skin shows individual pores: tiny dark 4// micro-spots of pore-scale (1-2 px at full res) creating high- 5// frequency texture. Mannequin / SDXL-smooth renders suppress this: 6// skin is uniform within local 3x3 neighborhoods. The substrate 7// measures MEAN |Y(x,y) - mean(Y, 3x3)| over skin-mask pixels — the 8// classic high-pass-vs-flat metric. 9// 10// Math: 11// For each skin-mask pixel: 12// local_mean = sum of 3x3 luminance / 9 13// residual = |luminance - local_mean| 14// detail_score = sum(residual) / count(skin_pixels) 15// 16// < 3 → SMOOTH_MANNEQUIN (no pores) 17// 3..8 → MODERATE_TEXTURE (acceptable) 18// ≥ 8 → DETAILED_NATURAL (visible pore-scale detail) 19// 20// Output flat-array: 21// result[0] = pixel_count 22// result[1] = mean_residual 23// result[2] = max_residual 24// result[3] = pore_candidate_count (pixels with residual > 12) 25// result[4] = verdict 26 27// nx_safety_envelope: 28// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 29// sil_target: SIL1 30// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 31// verdict: NOT_YET_EVALUATED 32 33import "nx_syscalls.nx" 34import "nx_image.nx" 35 36const NX_PORE_RES_PIXELS: i64 = 0 37const NX_PORE_RES_MEAN_RES: i64 = 1 38const NX_PORE_RES_MAX_RES: i64 = 2 39const NX_PORE_RES_CANDIDATES: i64 = 3 40const NX_PORE_RES_VERDICT: i64 = 4 41const NX_PORE_RES_FIELDS: i64 = 5 42 43const NX_PORE_VERDICT_SMOOTH_MANNEQUIN: i64 = 0 44const NX_PORE_VERDICT_MODERATE_TEXTURE: i64 = 1 45const NX_PORE_VERDICT_DETAILED_NATURAL: i64 = 2 46 47const NX_PORE_THRESH_SMOOTH: i64 = 3 48const NX_PORE_THRESH_DETAILED: i64 = 8 49const NX_PORE_CANDIDATE_THRESH: i64 = 12 50 51// Compute 3x3 mean luminance at (x, y). Boundary pixels skipped by caller. 52func nx_pore_local_mean(rgb: *Image, x: i64, y: i64) -> i64 { 53 var sum: i64 = 0 54 var dy: i64 = -1 55 while dy <= 1 { 56 var dx: i64 = -1 57 while dx <= 1 { 58 let r: i64 = nx_image_get(rgb, x + dx, y + dy, 0) 59 let g: i64 = nx_image_get(rgb, x + dx, y + dy, 1) 60 let b: i64 = nx_image_get(rgb, x + dx, y + dy, 2) 61 let yv: i64 = (77 * r + 150 * g + 29 * b) / 256 62 sum = sum + yv 63 dx = dx + 1 64 } 65 dy = dy + 1 66 } 67 return sum / 9 68} 69 70func nx_skin_pore_detail(rgb: *Image, skin_mask: *Image, result: *i64) -> i64 { 71 var i: i64 = 0 72 while i < NX_PORE_RES_FIELDS { result[i] = 0; i = i + 1 } 73 let w: i64 = rgb.width 74 let h: i64 = rgb.height 75 76 var sum_res: i64 = 0 77 var max_res: i64 = 0 78 var candidates: i64 = 0 79 var pixels: i64 = 0 80 81 var y: i64 = 1 82 while y < h - 1 { 83 var x: i64 = 1 84 while x < w - 1 { 85 if nx_image_get(skin_mask, x, y, 0) > 0 { 86 let r: i64 = nx_image_get(rgb, x, y, 0) 87 let g: i64 = nx_image_get(rgb, x, y, 1) 88 let b: i64 = nx_image_get(rgb, x, y, 2) 89 let yv: i64 = (77 * r + 150 * g + 29 * b) / 256 90 let local_mean: i64 = nx_pore_local_mean(rgb, x, y) 91 var residual: i64 = yv - local_mean 92 if residual < 0 { residual = -residual } 93 sum_res = sum_res + residual 94 if residual > max_res { max_res = residual } 95 if residual > NX_PORE_CANDIDATE_THRESH { candidates = candidates + 1 } 96 pixels = pixels + 1 97 } 98 x = x + 1 99 } 100 y = y + 1 101 } 102 103 result[NX_PORE_RES_PIXELS] = pixels 104 if pixels == 0 { return 0 } 105 let mean_res: i64 = sum_res / pixels 106 result[NX_PORE_RES_MEAN_RES] = mean_res 107 result[NX_PORE_RES_MAX_RES] = max_res 108 result[NX_PORE_RES_CANDIDATES] = candidates 109 110 var verdict: i64 = NX_PORE_VERDICT_MODERATE_TEXTURE 111 if mean_res < NX_PORE_THRESH_SMOOTH { verdict = NX_PORE_VERDICT_SMOOTH_MANNEQUIN } 112 if mean_res >= NX_PORE_THRESH_DETAILED { verdict = NX_PORE_VERDICT_DETAILED_NATURAL } 113 result[NX_PORE_RES_VERDICT] = verdict 114 return 0 115}