code wiki / _hdl_build / nx_editjudge_lib.nx
nx_editjudge_lib.nx
buildroot/runtime/_hdl_build/nx_editjudge_lib.nx
about
nx_editjudge_lib.nx -- THE EDIT-COMPLIANCE JUDGE: did the requested change actually happen?
WHY IT EXISTS (a MEASURED result, not a guess). The convergence loop optimised RETENTION and
converged in 4 renders to 845 -- and the requested emerald-green dress was still YELLOW. Retention
measures PRESERVATION, so maximising it alone walks toward changing nothing. That is the metric
quietly becoming the target. The cure is a SECOND, ORTHOGONAL judge asking the opposite question,
and reporting the two jointly (MIN) so a pipeline cannot win by only preserving OR only changing.
WHAT IT MEASURES, for a colour edit from_hue -> to_hue:
1. In the REFERENCE, find the garment: pixels whose hue is near from_hue AND that are saturated
enough to be a real colour (not near-gray/white/black). That mask IS the region to be edited --
derived from the image, not hand-drawn, so it cannot be gamed by choosing a flattering box.
2. At those SAME pixel locations in the generated image, count how many have shifted to near
to_hue. compliance_permil = shifted / masked.
3. Also report how many DRIFTED (moved off from_hue but not onto to_hue) and how many STAYED, so
"nothing changed" (stayed high) and "changed to the wrong thing" (drift high) are distinguishable
failures, not one blended number.
The signal is orthogonal to retention BY CONSTRUCTION: retention rises when pixels stay put;
compliance rises when the masked pixels move to a specific new hue. You cannot maximise both by
doing nothing, and you cannot maximise both by re-rolling the whole frame.
Composes nx_png_decoder + nx_image; the hue/sat math is integer HSV (no float, never-brick #26).
license_tier: ORIGINAL
dependencies 2 imports · 4 importers
imports: nx_png_decoder.nxnx_image.nx
imported by: nx_editjudge.nxnx_editjudge_gate.nxnx_garment_lib.nxnx_recolor.nx
structs
| none |
consts
| 28 | const EJ_SAT_MIN: i64 = 60 // permil-of-255 saturation floor: below this a pixel is too gray to |
| 30 | const EJ_HUE_TOL: i64 = 30 // degrees: a hue within this of the anchor counts as "that colour" |
functions
| 32 | func ej_min3(a: i64, b: i64, c: i64) -> i64 { var m: i64 = a; if b < m { m = b } if c < m { m = c } return m } |
| 33 | func ej_max3(a: i64, b: i64, c: i64) -> i64 { var m: i64 = a; if b > m { m = b } if c > m { m = c } return m } |
| 37 | func ej_hue(r: i64, g: i64, b: i64) -> i64 |
| 51 | func ej_sat(r: i64, g: i64, b: i64) -> i64 |
| 59 | func ej_hue_dist(a: i64, b: i64) -> i64 |
| 70 | func ej_load_rgb(path: *u8, out_w: *i64, out_h: *i64) -> *u8 |
| 105 | func ej_in_box(i: i64, w: i64, h: i64, x0: i64, y0: i64, x1: i64, y1: i64) -> i64 |
| 127 | func ej_compliance_spec(ref: *u8, gen: *u8, w: i64, h: i64, from_hue: i64, to_hue: i64, |
| 171 | func ej_footprint(ref: *u8, gen: *u8, npix: i64) -> i64 |
| 185 | func ej_compliance_box(ref: *u8, gen: *u8, w: i64, h: i64, from_hue: i64, to_hue: i64, calls 1: ej_compliance_spec |
| 193 | func ej_compliance(ref: *u8, gen: *u8, npix: i64, from_hue: i64, to_hue: i64, |