code wiki / _hdl_build / nx_garment_lib.nx
nx_garment_lib.nx
buildroot/runtime/_hdl_build/nx_garment_lib.nx
about
nx_garment_lib.nx -- SPATIALLY-COHERENT GARMENT MASK: replaces the rectangle that left a visible seam.
THE MEASURED PROBLEM. A hue-only mask for a yellow dress also caught the model's FACE, because skin
and warm fabric are genuinely close in hue -- so no hue tolerance can separate them without either
losing the dress or taking the face. A rectangle "fixed" it only by brute force, and left a seam.
THE PRINCIPLED SEPARATOR IS SPATIAL COHERENCE, NOT A TIGHTER THRESHOLD. A garment is ONE LARGE
CONTIGUOUS REGION. Skin is a different region that merely resembles it in colour. So: build the
colour-candidate set, label 8-connected components, and keep the LARGEST -- the dress survives, the
face falls away as a separate component, and the boundary follows the actual fabric edge instead of
an invented rectangle. No tuned constant decides which is which; the geometry does.
Composes nx_img_segment's proven flood-fill labeller (ink=0/paper=255 convention) -- zero new
component-labelling maths -- and nx_editjudge_lib's hue/sat primitives, so ONE definition of "this
pixel is that colour" governs the candidate set here and the judging elsewhere.
license_tier: ORIGINAL
dependencies 3 imports · 1 importers
imports: nx_editjudge_lib.nxnx_img_segment.nxnx_color_v2.nx
imported by: nx_recolor.nx
structs
| none |
consts
| 21 | const GM_MAXCOMPS: i64 = 20000 // generous: a noisy candidate set fragments; seg_components bails past this |
| 99 | const GM_HUE_BINS: i64 = 36 // 10 degrees per bin: coarse enough to be robust to dithering noise |
| 100 | const GM_MODE_MIN_PM: i64 = 60 // a bin must hold >=6% of the region to count as a tone, not noise |
| 101 | const GM_MAX_MODES: i64 = 6 |
| 418 | const GM_SEED_SAT: i64 = 170 // saturation floor for the CONFIDENT CORE only (deliberately strict: |
| 420 | const GM_SPREAD_MIN: i64 = 24 // floor on a derived tolerance so a perfectly-flat core can still grow |
| 421 | const GM_SPREAD_MUL: i64 = 3 // half-widths are this multiple of the core's mean absolute deviation |
| 489 | const GM_SHADOW_MUL: i64 = 4 // how much further the model may reach in the shadow direction only |
functions
| 29 | func gm_candidate_mask(rgb: *u8, npix: i64, hue: i64, sat_min: i64, out_bin: *u8) -> i64 |
| 58 | func gm_candidate_mask_noskin(rgb: *u8, npix: i64, hue: i64, sat_min: i64, out_bin: *u8) -> i64 |
| 109 | func gm_dilate(mask: *u8, w: i64, h: i64, iters: i64, out: *u8) -> i64 called by 1: gm_segment_dilate |
| 150 | func gm_hue_modes_mask(rgb: *u8, npix: i64, region: *u8, sat_min: i64, out_modes: *i64) -> i64 |
| 187 | func gm_segment_dilate(rgb: *u8, w: i64, h: i64, hue: i64, sat_min: i64, reach: i64, out_mask: *u8, called by 1: main calls 9: gm_segment_noskingm_dilategm_hue_modes_masknx_color_kovac_skin_pixelej_satgm_near_any_mode+3 |
| 231 | func gm_mask_bbox(mask: *u8, w: i64, h: i64, out4: *i64) -> i64 called by 1: gm_segment_multimodal |
| 259 | func gm_hue_modes(rgb: *u8, w: i64, h: i64, bx: *i64, sat_min: i64, out_modes: *i64) -> i64 |
| 301 | func gm_near_any_mode(hue: i64, modes: *i64, nm: i64) -> i64 |
| 312 | func gm_segment_multimodal(rgb: *u8, w: i64, h: i64, hue: i64, sat_min: i64, out_mask: *u8, |
| 362 | func gm_segment_noskin(rgb: *u8, w: i64, h: i64, hue: i64, sat_min: i64, out_mask: *u8, |
| 385 | func gm_largest_id(labels: *i64, npix: i64, ncomp: i64) -> i64 |
| 424 | func gm_model(rgb: *u8, npix: i64, mask: *u8, out6: *i64) -> i64 |
| 491 | func gm_fits(rgb: *u8, i: i64, m: *i64) -> i64 |
| 509 | func gm_grow(rgb: *u8, w: i64, h: i64, mask: *u8, m: *i64) -> i64 |
| 548 | func gm_segment_grow(rgb: *u8, w: i64, h: i64, hue: i64, out_mask: *u8, |
| 568 | func gm_segment_sat(rgb: *u8, w: i64, h: i64, hue: i64, sat_min: i64, out_mask: *u8, |