Correctness fixes from the figureextract ecosystem review (2026-07-03).
All are boundary conditions the published algorithms assume away; see the
new vignette("correctness-properties") for the guarantees they restore.
-
thin()now skeletonises shapes that touch the matrix border correctly. The kernels inspect an 8-neighbourhood and so never deleted pixels in the outermost row or column, leaving edge-touching shapes two to three pixels thick;thin()now pads the image with a one-pixel background margin and crops it back, so a shape thins identically whether or not it touches the frame. Applies to all seven methods (#F012). -
thin(method = "opta")now keeps two-pixel-wide strokes connected. The SPTA kernel evaluated all four contour directions against the pre-cycle snapshot and deleted them in one batch, so both sides of a 2px stroke were removed together and the skeleton fragmented (a 2×9 bar collapsed to its four corner pixels). Deletion is now sequential per direction, as Naccache & Shinghal's two-scan formulation requires (#F011). -
distance_transform(metric = "manhattan" | "chessboard")now returnsInffor a fully-foreground image (no background pixel exists), matching the"euclidean"metric andEBImage::distmap(). The two-pass metrics previously seeded foreground with a finite sentinel that leaked out as a plausible-looking but meaningless finite distance (#F015). -
thin(),distance_transform(), andmedial_axis()now rejectNAinput with a clear error at the coercion boundary instead of silently turning it intoNA_integer_(INT_MIN) in the C++ kernels (#F016). -
thin(method = "hilditch")now thins junctions to the published parallel form. The look-ahead conditions 3 and 4 skip deleting a pixel only when a cardinal neighbour has crossing numberA == 1on the current image; the kernel had compared the look-ahead crossing number (computed with the centre already removed) against 1, which is strictly stronger and also spared junction neighbours whereA >= 2, leaving a redundant pixel beside the junction. Skeletons are now equal to or thinner than before, never thicker (verified against a reference implementation of the published form over random images) (#F014). -
Added a connectivity-preservation property test across all seven methods and tightened the Holt straight-line test (#F013).
-
Documented and pinned the isolated-2×2-block behaviour: the default
zhang_suenerases an isolated 2×2 block entirely whileguo_hallkeeps one pixel. Seevignette("choosing-a-method")for guidance on small-blob masks (#F017). -
Removed
thinImage(). Usethin()(Zhang-Suen is the default method).
Initial CRAN release.