code wiki / (root) / nx_breast_localize.nx

nx_breast_localize.nx source

↩ module page · 129 lines · 4531 B

1// nx_breast_localize.nx -- find left/right breast sub-regions in torso. 2// 3// In real renders the two breasts are connected to torso as one CC, 4// so we can't isolate them by connected-component alone. The substrate 5// splits the upper-third of the torso at midline and computes the 6// bounding box of skin-mask pixels in each half. Outputs per-breast 7// bbox + centroid + area_px. 8// 9// Output flat-array (packed): 10// result[0..4] left breast: x0, y0, x1, y1, area_px 11// result[5..9] right breast: x0, y0, x1, y1, area_px 12// result[10] left centroid_x 13// result[11] left centroid_y 14// result[12] right centroid_x 15// result[13] right centroid_y 16 17// nx_safety_envelope: 18// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 19// sil_target: SIL1 20// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 21// verdict: NOT_YET_EVALUATED 22 23import "nx_syscalls.nx" 24import "nx_image.nx" 25 26const NX_BLOC_RES_L_X0: i64 = 0 27const NX_BLOC_RES_L_Y0: i64 = 1 28const NX_BLOC_RES_L_X1: i64 = 2 29const NX_BLOC_RES_L_Y1: i64 = 3 30const NX_BLOC_RES_L_AREA: i64 = 4 31const NX_BLOC_RES_R_X0: i64 = 5 32const NX_BLOC_RES_R_Y0: i64 = 6 33const NX_BLOC_RES_R_X1: i64 = 7 34const NX_BLOC_RES_R_Y1: i64 = 8 35const NX_BLOC_RES_R_AREA: i64 = 9 36const NX_BLOC_RES_L_CX: i64 = 10 37const NX_BLOC_RES_L_CY: i64 = 11 38const NX_BLOC_RES_R_CX: i64 = 12 39const NX_BLOC_RES_R_CY: i64 = 13 40const NX_BLOC_RES_FIELDS: i64 = 14 41 42// Localize left/right breast in upper-third of torso. 43// bbox layout: [torso_x0, torso_y0, torso_x1, torso_y1] 44func nx_breast_localize(skin_mask: *Image, bbox: *i64, result: *i64) -> i64 { 45 var i: i64 = 0 46 while i < NX_BLOC_RES_FIELDS { result[i] = 0; i = i + 1 } 47 48 let torso_x0: i64 = bbox[0] 49 let torso_y0: i64 = bbox[1] 50 let torso_x1: i64 = bbox[2] 51 let torso_y1: i64 = bbox[3] 52 let torso_w: i64 = torso_x1 - torso_x0 53 let torso_h: i64 = torso_y1 - torso_y0 54 if torso_w <= 0 { return 1 } 55 if torso_h <= 0 { return 2 } 56 57 let upper_y1: i64 = torso_y0 + torso_h / 3 // upper third of torso 58 let midline_x: i64 = torso_x0 + torso_w / 2 59 60 // Init left bbox to invalid; we'll narrow it. 61 var l_x0: i64 = torso_x1 62 var l_y0: i64 = torso_y1 63 var l_x1: i64 = torso_x0 64 var l_y1: i64 = torso_y0 65 var l_area: i64 = 0 66 var l_sum_x: i64 = 0 67 var l_sum_y: i64 = 0 68 69 var r_x0: i64 = torso_x1 70 var r_y0: i64 = torso_y1 71 var r_x1: i64 = torso_x0 72 var r_y1: i64 = torso_y0 73 var r_area: i64 = 0 74 var r_sum_x: i64 = 0 75 var r_sum_y: i64 = 0 76 77 var y: i64 = torso_y0 78 while y < upper_y1 { 79 if y >= 0 { if y < skin_mask.height { 80 var x: i64 = torso_x0 81 while x < torso_x1 { 82 if x >= 0 { if x < skin_mask.width { 83 let m: i64 = nx_image_get(skin_mask, x, y, 0) 84 if m > 0 { 85 if x < midline_x { 86 if x < l_x0 { l_x0 = x } 87 if x > l_x1 { l_x1 = x } 88 if y < l_y0 { l_y0 = y } 89 if y > l_y1 { l_y1 = y } 90 l_area = l_area + 1 91 l_sum_x = l_sum_x + x 92 l_sum_y = l_sum_y + y 93 } else { 94 if x < r_x0 { r_x0 = x } 95 if x > r_x1 { r_x1 = x } 96 if y < r_y0 { r_y0 = y } 97 if y > r_y1 { r_y1 = y } 98 r_area = r_area + 1 99 r_sum_x = r_sum_x + x 100 r_sum_y = r_sum_y + y 101 } 102 } 103 } } 104 x = x + 1 105 } 106 } } 107 y = y + 1 108 } 109 110 if l_area > 0 { 111 result[NX_BLOC_RES_L_X0] = l_x0 112 result[NX_BLOC_RES_L_Y0] = l_y0 113 result[NX_BLOC_RES_L_X1] = l_x1 114 result[NX_BLOC_RES_L_Y1] = l_y1 115 result[NX_BLOC_RES_L_AREA] = l_area 116 result[NX_BLOC_RES_L_CX] = l_sum_x / l_area 117 result[NX_BLOC_RES_L_CY] = l_sum_y / l_area 118 } 119 if r_area > 0 { 120 result[NX_BLOC_RES_R_X0] = r_x0 121 result[NX_BLOC_RES_R_Y0] = r_y0 122 result[NX_BLOC_RES_R_X1] = r_x1 123 result[NX_BLOC_RES_R_Y1] = r_y1 124 result[NX_BLOC_RES_R_AREA] = r_area 125 result[NX_BLOC_RES_R_CX] = r_sum_x / r_area 126 result[NX_BLOC_RES_R_CY] = r_sum_y / r_area 127 } 128 return 0 129}