code wiki / (root) / nx_pressure_deformation.nx

nx_pressure_deformation.nx source

↩ module page · 144 lines · 5621 B

1// nx_pressure_deformation.nx -- skin-on-skin contact tissue compression check. 2// 3// Mannequin failure marker from image #45: hand cupping breast but the 4// breast tissue doesn't displace where the hand presses against it. 5// Real bodies show measurable compression at contact zones; mannequins 6// pass through each other or show rigid edges. 7// 8// Math: 9// Given primary region bbox (breast) + contact region bbox (where 10// arm/hand crosses), the EXPECTED skin-mask area inside the contact 11// region is the primary region's local density × contact area. 12// Measured area / expected area = compression ratio. 13// 14// < 0.7 ratio → strong compression (tissue displaced) NATURAL 15// 0.7..0.85 → mild compression AMBIGUOUS 16// > 0.85 → little/no compression MANNEQUIN_RIGID 17// 18// Also measure contact-boundary roughness: count skin-mask transitions 19// in horizontal slices through the contact band. Real flesh contacts 20// produce many transitions (wavy compression boundary); mannequins 21// produce a clean straight boundary. 22 23// nx_safety_envelope: 24// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 25// sil_target: SIL1 26// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 27// verdict: NOT_YET_EVALUATED 28 29import "nx_syscalls.nx" 30import "nx_image.nx" 31const NX_MAGIC_1024: i64 = 1024 32 33const NX_PRESS_RES_PRIMARY_AREA: i64 = 0 34const NX_PRESS_RES_CONTACT_AREA: i64 = 1 35const NX_PRESS_RES_EXPECTED: i64 = 2 36const NX_PRESS_RES_COMPRESSION_Q10: i64 = 3 // measured/expected in Q10 37const NX_PRESS_RES_BOUNDARY_TRANS: i64 = 4 // total horizontal transitions 38const NX_PRESS_RES_VERDICT: i64 = 5 39const NX_PRESS_RES_FIELDS: i64 = 6 40 41const NX_PRESS_VERDICT_MANNEQUIN_RIGID: i64 = 0 42const NX_PRESS_VERDICT_AMBIGUOUS: i64 = 1 43const NX_PRESS_VERDICT_NATURAL: i64 = 2 44 45const NX_PRESS_COMPRESS_NATURAL_Q10: i64 = 717 // ≤ 0.70 = natural 46const NX_PRESS_COMPRESS_AMBIG_Q10: i64 = 870 // 0.70..0.85 = ambiguous 47 48// Count skin-mask pixels inside a bbox. 49func nx_press_count_in_bbox(mask: *Image, x0: i64, y0: i64, 50 x1: i64, y1: i64) -> i64 { 51 var n: i64 = 0 52 var y: i64 = y0 53 while y <= y1 { 54 if y >= 0 { if y < mask.height { 55 var x: i64 = x0 56 while x <= x1 { 57 if x >= 0 { if x < mask.width { 58 if nx_image_get(mask, x, y, 0) > 0 { n = n + 1 } 59 } } 60 x = x + 1 61 } 62 } } 63 y = y + 1 64 } 65 return n 66} 67 68// Count horizontal mask transitions (0->1 or 1->0) within bbox. 69func nx_press_count_transitions(mask: *Image, x0: i64, y0: i64, 70 x1: i64, y1: i64) -> i64 { 71 var total: i64 = 0 72 var y: i64 = y0 73 while y <= y1 { 74 if y >= 0 { if y < mask.height { 75 var prev: i64 = 0 76 var x: i64 = x0 77 while x <= x1 { 78 if x >= 0 { if x < mask.width { 79 var cur: i64 = 0 80 if nx_image_get(mask, x, y, 0) > 0 { cur = 1 } 81 if cur != prev { total = total + 1 } 82 prev = cur 83 } } 84 x = x + 1 85 } 86 } } 87 y = y + 1 88 } 89 return total 90} 91 92// Score deformation at contact zone. 93// bbox layout (8 entries): 94// [0..3] primary region (breast) x0,y0,x1,y1 95// [4..7] contact region (overlap) x0,y0,x1,y1 96func nx_pressure_deformation(mask: *Image, bbox: *i64, result: *i64) -> i64 { 97 var i: i64 = 0 98 while i < NX_PRESS_RES_FIELDS { result[i] = 0; i = i + 1 } 99 100 let p_x0: i64 = bbox[0]; let p_y0: i64 = bbox[1] 101 let p_x1: i64 = bbox[2]; let p_y1: i64 = bbox[3] 102 let c_x0: i64 = bbox[4]; let c_y0: i64 = bbox[5] 103 let c_x1: i64 = bbox[6]; let c_y1: i64 = bbox[7] 104 105 let primary_w: i64 = p_x1 - p_x0 + 1 106 let primary_h: i64 = p_y1 - p_y0 + 1 107 let contact_w: i64 = c_x1 - c_x0 + 1 108 let contact_h: i64 = c_y1 - c_y0 + 1 109 if primary_w <= 0 { return 1 } 110 if primary_h <= 0 { return 2 } 111 if contact_w <= 0 { return 3 } 112 if contact_h <= 0 { return 4 } 113 114 let primary_area: i64 = nx_press_count_in_bbox(mask, p_x0, p_y0, p_x1, p_y1) 115 let contact_area: i64 = nx_press_count_in_bbox(mask, c_x0, c_y0, c_x1, c_y1) 116 result[NX_PRESS_RES_PRIMARY_AREA] = primary_area 117 result[NX_PRESS_RES_CONTACT_AREA] = contact_area 118 119 let primary_bbox_area: i64 = primary_w * primary_h 120 if primary_bbox_area == 0 { return 5 } 121 let primary_density_q10: i64 = (primary_area * NX_MAGIC_1024) / primary_bbox_area 122 let contact_bbox_area: i64 = contact_w * contact_h 123 let expected: i64 = (primary_density_q10 * contact_bbox_area) / NX_MAGIC_1024 124 result[NX_PRESS_RES_EXPECTED] = expected 125 126 var compression_q10: i64 = NX_MAGIC_1024 127 if expected > 0 { compression_q10 = (contact_area * NX_MAGIC_1024) / expected } 128 if compression_q10 > NX_MAGIC_1024 { compression_q10 = NX_MAGIC_1024 } 129 result[NX_PRESS_RES_COMPRESSION_Q10] = compression_q10 130 131 let trans: i64 = nx_press_count_transitions(mask, c_x0, c_y0, c_x1, c_y1) 132 result[NX_PRESS_RES_BOUNDARY_TRANS] = trans 133 134 var verdict: i64 = NX_PRESS_VERDICT_MANNEQUIN_RIGID 135 if compression_q10 <= NX_PRESS_COMPRESS_NATURAL_Q10 { 136 verdict = NX_PRESS_VERDICT_NATURAL 137 } else { 138 if compression_q10 <= NX_PRESS_COMPRESS_AMBIG_Q10 { 139 verdict = NX_PRESS_VERDICT_AMBIGUOUS 140 } 141 } 142 result[NX_PRESS_RES_VERDICT] = verdict 143 return 0 144}