diff --git a/CHANGELOG.md b/CHANGELOG.md index baad7b0..d8fed48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,20 +9,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added -* Binary thresholding: a tunable fixed threshold and Bradley–Roth adaptive thresholding for uneven lighting — CLI `--threshold` / `--adaptive` (`--adaptive-window`, `--adaptive-t`), also on `Config`, Python, and Node. -* Cutout mode merges neighbouring mosaic regions whose colors are within one gradient step — the flattened tessellation no longer keeps the near-identical faces that stacked gradient layering splits a smooth area into. -* Watershed clustering (`--clustering watershed`): an alternative region-forming frontend — a hierarchical watershed by volume on the pixel graph (Cousty et al., TPAMI 2009; Najman, Cousty & Perret, ISMM 2013), cut at a single `--watershed-detail` dial (0..=255, each +25.5 roughly doubles the region count). Content-adaptive regions with no watershed-line pixels; antialiased boundary pixels snap to the color-midpoint iso-line, so edges come out as calm as the color-cluster frontend's instead of meandering with the pixel noise inside the ramp. With `cutout` the partition reaches the mosaic natively, and near-identical neighbouring faces merge within a detail-derived tolerance (`max(2, (255 − detail) / 8)`: the color-cluster default gradient step at the default detail, and never less than a just-noticeable difference — faces a human cannot tell apart never survive as separate patches); with `stacked` the merge tree itself is the stack — coarse ancestors below, refined regions on top, the same principle as color clustering — so sub-pixel gaps show ancestor colors and overdraw stays seam-free. -* `WatershedHierarchy` is public and split into `build` (expensive, depends only on the image) and `cut` (near-instant): `Session` builds it once and re-cuts on every `watershed_detail`/`filter_speckle` change, making the detail slider fully interactive (~25 ms re-cut vs ~40 ms rebuild on a 1400×775 photo). -* Curve simplification (`--simplify `, `Config::simplify`; off by default): a paper.js-style Schneider re-fit of the fitted splines — each smooth run between corners is re-fitted with the fewest cubics that stay within the tolerance (px), cutting anchor counts and file size (the 1400×775 sample photo: 229 → 138 KB stacked, 103 → 36 KB watershed cutout at tolerance 1). Implemented as a new pipeline stage (`CurvePass`) that runs on fitted geometry *before* composition, so mosaic mode simplifies each shared boundary exactly once and the tessellation stays seam-free; corners survive in place, junction endpoints are pinned bit-for-bit, and pixel/polygon polylines pass through untouched. +* Watershed clustering (`--clustering watershed`): a new region-forming frontend — a hierarchical watershed on the pixel graph (Cousty et al. 2009; Najman et al. 2013), controlled by one dial, `--watershed-detail` (0..=255; each +25.5 roughly doubles the region count). Regions follow image content, with no watershed-line pixels. + * Boundaries come out calm: antialiased pixels snap to the color-midpoint iso-line instead of meandering with the noise inside the ramp. + * `stacked` stacks the merge tree itself (coarse ancestors below, refined regions on top), so overdraw stays seam-free. + * `cutout` gets the partition natively; neighbouring faces closer than `max(2, (255 − detail) / 8)` merge, so faces a human cannot tell apart never survive as separate patches. + * `WatershedHierarchy` is public, split into `build` (expensive, image-only) and `cut` (near-instant); `Session` re-cuts a cached hierarchy on detail changes, making the slider fully interactive (~25 ms vs ~40 ms on a 1400×775 photo). +* Curve simplification (`--simplify `, `Config::simplify`; off by default): a paper.js-style Schneider re-fit — each smooth run between corners is redrawn with the fewest cubics that stay within the tolerance (px). Roughly halves file size (sample photo at tolerance 1: 229 → 138 KB stacked, 103 → 36 KB watershed cutout). Runs on fitted geometry before composition, so cutout simplifies each shared boundary once and stays seam-free; corners and junction endpoints stay pinned. +* Binary thresholding: a tunable fixed threshold (`--threshold`) and Bradley–Roth adaptive thresholding for uneven lighting (`--adaptive`, `--adaptive-window`, `--adaptive-t`) — also on `Config`, Python, and Node. +* Cutout mode merges neighbouring faces whose colors are within one gradient step, rejoining the near-identical faces that stacked gradient layering splits a smooth area into. ### Changed -* `color_mode` is replaced by `clustering` (`color-cluster` | `bw` | `watershed`) across the CLI (`--clustering`), Rust (`Config::clustering`, enum `Clustering`), Python, and Node — the field selects the region-forming algorithm, not a color space. -* The spline fine-tuning flags `--corner-threshold`, `--segment-length`, and `--splice-threshold` are hidden from CLI help (still accepted) and their short forms `-c`/`-l`/`-s` are removed — the defaults serve virtually every conversion, and `--simplify` supersedes them as the knob that actually moves output size. +* `color_mode` is replaced by `clustering` (`color-cluster` | `bw` | `watershed`) across the CLI, Rust, Python, and Node — the field selects the region-forming algorithm, not a color space. +* The spline fine-tuning flags (`--corner-threshold`, `--segment-length`, `--splice-threshold`) are hidden from CLI help — still accepted, but without their `-c`/`-l`/`-s` short forms. The defaults serve virtually every conversion; `--simplify` supersedes them. ### Fixed -* Spline fitting no longer swings far away from the outline around thin strands (a long-standing defect, via visioncortex 0.9.1): a sparse splice slice — a few-pixel jog followed by a long straight leg — could be fitted by a single cubic that interpolated every sample while ballooning up to ~30 px sideways between them, visibly crossing narrow gaps. Slices are now densified before fitting and multi-cubic fits are kept in full, in both stacked mode and the mosaic's shared-boundary fitter. +* Spline fitting no longer swings far away from the outline around thin strands (a long-standing defect, fixed via visioncortex 0.9.1): a sparse splice slice could be fitted by a single cubic that passed through every sample yet ballooned up to ~30 px sideways between them. Slices are now densified before fitting and multi-cubic fits kept in full, in both stacked mode and the mosaic fitter. ## 1.0.0-alpha.1 - 2026-07-24