code wiki / (root) / nx_compose.nx

nx_compose.nx source

↩ module page · 211 lines · 7286 B

1// nx_compose.nx -- compositional primitives (V2 of vision rollout). 2// 3// Pure-math aesthetic measures that work on image PROPERTIES, never 4// on subjects. Per CAPTAIN_MORONI_DOCTRINE these are objective 5// scores; they never rank persons or assign beauty to humans. 6// 7// Ships: 8// - nx_compose_thirds_score: rule-of-thirds alignment 9// - nx_compose_h_symmetry: left/right mirror symmetry 10// - nx_compose_v_symmetry: top/bottom mirror symmetry 11// - nx_compose_visual_centroid: weighted center-of-intensity 12// - nx_compose_balance_score: distance from geometric center 13// 14// All scores in Q10 fixed-point (1024 = "perfect" depending on metric). 15// 16// What this unlocks: 17// + objective composition feedback ("subject not on thirds") 18// + symmetry detection (architecture, portrait framing, reflections) 19// + balance assessment (heavy on one side vs centered) 20// + aesthetic measurement at the image level (never the subject) 21// 22// genealogy_id: birkhoff_1933_aesthetic + datta_2006_56features 23// + cropping_aesthetics_research 24// lineage_id: image_property_measurement (not subject ranking) 25 26// nx_safety_envelope: 27// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 28// sil_target: SIL1 29// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 30// verdict: NOT_YET_EVALUATED 31 32import "syscalls.nx" 33import "nx_image.nx" 34 35const NX_COMP_Q: i64 = 1024 36 37// ===== Rule of thirds =================================================== 38// 39// Score how much grayscale intensity mass falls within bands of width 40// W/9 centered on the thirds lines (x = W/3, 2W/3) and height H/9 41// centered on (y = H/3, 2H/3). Returns Q10 score (1024 = all mass 42// on thirds; 0 = none). 43// 44// A baseline image with uniform brightness scores around 444 (4 bands 45// each W/9 wide = 4/9 of image area). A subject placed exactly on a 46// thirds intersection scores higher. 47 48func nx_compose_thirds_score(gray: *Image) -> i64 { 49 let w: i64 = gray.width 50 let h: i64 = gray.height 51 let band_w: i64 = w / 9 52 let band_h: i64 = h / 9 53 let x_third_1: i64 = w / 3 54 let x_third_2: i64 = (2 * w) / 3 55 let y_third_1: i64 = h / 3 56 let y_third_2: i64 = (2 * h) / 3 57 var on_thirds: i64 = 0 58 var total: i64 = 0 59 var y: i64 = 0 60 while y < h { 61 var x: i64 = 0 62 while x < w { 63 let v: i64 = nx_image_get(gray, x, y, 0) 64 total = total + v 65 // Pixel is "on a thirds line" if x within band_w of either 66 // vertical-third, OR y within band_h of either horizontal-third. 67 var on_x: i64 = 0 68 let dx1: i64 = x - x_third_1 69 var adx1: i64 = dx1 70 if adx1 < 0 { adx1 = -adx1 } 71 let dx2: i64 = x - x_third_2 72 var adx2: i64 = dx2 73 if adx2 < 0 { adx2 = -adx2 } 74 if adx1 < band_w { on_x = 1 } 75 if adx2 < band_w { on_x = 1 } 76 var on_y: i64 = 0 77 let dy1: i64 = y - y_third_1 78 var ady1: i64 = dy1 79 if ady1 < 0 { ady1 = -ady1 } 80 let dy2: i64 = y - y_third_2 81 var ady2: i64 = dy2 82 if ady2 < 0 { ady2 = -ady2 } 83 if ady1 < band_h { on_y = 1 } 84 if ady2 < band_h { on_y = 1 } 85 if on_x == 1 { on_thirds = on_thirds + v } 86 if on_y == 1 { 87 if on_x == 0 { // avoid double-count 88 on_thirds = on_thirds + v 89 } 90 } 91 x = x + 1 92 } 93 y = y + 1 94 } 95 if total == 0 { return 0 } 96 return (on_thirds * NX_COMP_Q) / total 97} 98 99// ===== Horizontal mirror symmetry ====================================== 100// 101// For each pixel (x, y), compare to mirror (W-1-x, y). Sum absolute 102// differences and normalize by total intensity. Return Q10 where 103// 1024 = perfect mirror symmetry, 0 = anti-symmetric. 104 105func nx_compose_h_symmetry(gray: *Image) -> i64 { 106 let w: i64 = gray.width 107 let h: i64 = gray.height 108 var diff_sum: i64 = 0 109 var total: i64 = 0 110 var y: i64 = 0 111 while y < h { 112 var x: i64 = 0 113 while x < w / 2 { 114 let lv: i64 = nx_image_get(gray, x, y, 0) 115 let rv: i64 = nx_image_get(gray, w - 1 - x, y, 0) 116 var d: i64 = lv - rv 117 if d < 0 { d = -d } 118 diff_sum = diff_sum + d 119 total = total + lv + rv 120 x = x + 1 121 } 122 y = y + 1 123 } 124 if total == 0 { return NX_COMP_Q } // empty image -> trivially symmetric 125 let asymmetry: i64 = (diff_sum * NX_COMP_Q) / total 126 if asymmetry >= NX_COMP_Q { return 0 } 127 return NX_COMP_Q - asymmetry 128} 129 130// ===== Vertical mirror symmetry ======================================== 131 132func nx_compose_v_symmetry(gray: *Image) -> i64 { 133 let w: i64 = gray.width 134 let h: i64 = gray.height 135 var diff_sum: i64 = 0 136 var total: i64 = 0 137 var y: i64 = 0 138 while y < h / 2 { 139 var x: i64 = 0 140 while x < w { 141 let tv: i64 = nx_image_get(gray, x, y, 0) 142 let bv: i64 = nx_image_get(gray, x, h - 1 - y, 0) 143 var d: i64 = tv - bv 144 if d < 0 { d = -d } 145 diff_sum = diff_sum + d 146 total = total + tv + bv 147 x = x + 1 148 } 149 y = y + 1 150 } 151 if total == 0 { return NX_COMP_Q } 152 let asymmetry: i64 = (diff_sum * NX_COMP_Q) / total 153 if asymmetry >= NX_COMP_Q { return 0 } 154 return NX_COMP_Q - asymmetry 155} 156 157// ===== Visual-weight centroid ========================================== 158// 159// Center of intensity (weighted by pixel brightness). Returned in 160// Q10 of image dimensions: 161// out_cx_q = 1024 * centroid_x / width 162// out_cy_q = 1024 * centroid_y / height 163// So 512 = exact center, 0 = far left/top, 1024 = far right/bottom. 164 165func nx_compose_visual_centroid(gray: *Image, out_cx_q: *i64, 166 out_cy_q: *i64) -> i64 { 167 let w: i64 = gray.width 168 let h: i64 = gray.height 169 var sum_v: i64 = 0 170 var sum_xv: i64 = 0 171 var sum_yv: i64 = 0 172 var y: i64 = 0 173 while y < h { 174 var x: i64 = 0 175 while x < w { 176 let v: i64 = nx_image_get(gray, x, y, 0) 177 sum_v = sum_v + v 178 sum_xv = sum_xv + x * v 179 sum_yv = sum_yv + y * v 180 x = x + 1 181 } 182 y = y + 1 183 } 184 if sum_v == 0 { 185 out_cx_q[0] = 512 186 out_cy_q[0] = 512 187 return 0 188 } 189 out_cx_q[0] = (sum_xv * NX_COMP_Q) / (sum_v * w) 190 out_cy_q[0] = (sum_yv * NX_COMP_Q) / (sum_v * h) 191 return 0 192} 193 194// ===== Balance score =================================================== 195// 196// Distance from geometric center. Q10 where 1024 = at corner (max 197// distance), 0 = perfectly centered. 198 199func nx_compose_balance_score(gray: *Image) -> i64 { 200 let cx_q: *i64 = (sys_mmap(8)) as *i64 201 let cy_q: *i64 = (sys_mmap(8)) as *i64 202 nx_compose_visual_centroid(gray, cx_q, cy_q) 203 var dx: i64 = cx_q[0] - 512 204 if dx < 0 { dx = -dx } 205 var dy: i64 = cy_q[0] - 512 206 if dy < 0 { dy = -dy } 207 // Manhattan distance from center, scaled so corner = 1024 208 var dist: i64 = dx + dy 209 if dist > NX_COMP_Q { dist = NX_COMP_Q } 210 return dist 211}