mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-31 21:48:53 -06:00
An Object / Describe mask is stored as a model's logit grid (288² over the whole photo, ~20 px cells on a 24 MP export) and was enlarged by bilinear sampling alone, so its edge spilled 1–2 px onto the background; raising the mask's Exposure turned that strip into a bright outline in previews and exports (CPU and GPU: the GPU renderer evaluates these shapes with the same CPU `shape_alpha`). `sample_seg` now guided-filters the sampled logits by the photo's log luminance where the grid is coarser than the output: the fast (subsampled) guided filter, a window of 1.5 grid cells, so a preview and an export put the edge in the same place. Filtering logits, not coverage, lets the confident side win (the spill goes to ≈ 0, not to a mean of ≈ 0.1). Pixels whose window is all inside or all outside, and edges the photo has no contrast across, keep the plain sample exactly. Refine Edges still runs afterwards on the combined mask and finds the edges in place: no second halo, no tightening. One implementation: `guided_cross` (Refine Edges, Auto Mask) and the new `guided_cross_fast` share `guided_coeffs`; the subsampled form uses `local::guided_fast_step` and a box `resize`, like `local::guided_fast`. `guided_cross`'s output is unchanged. Existing AI masks become 1–2 px tighter at a subject's edges, on every process; their inside, outside and contrast-less edges are unchanged. This lands in place under the bug-fix rule of docs/process-versions.md (output that is in neither the photo nor the edit), noted there. Cost per AI selection (M2 Pro, 12 cores; one shape_alpha, before → after): 24 MP 25.7 → 48.2 ms, heap peak 96.5 → 108.8 MB; 60 MP 64.1 → 109.9 ms, 239.9 → 256.7 MB; 2.7 MP preview 3.1 → 10.6 ms, 11.2 → 26.5 MB. Tests (a dark disc on a light background, its mask on a 32² grid): ≈ 0 one and two px outside and ≈ 1 inside, all around (1 px outside was 0.66), bit-identical away from the edge; with Refine Edges 50 / 100 (was 0.29 outside) and the edge within 1 px of the unrefined one; the same edge position at 256, 512 and 1024 px; a Prompt mask's window matches the whole render. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>