| Title: | Binary Image Thinning Algorithms |
| Version: | 0.3.0 |
| Description: | Thinning (skeletonization) algorithms for binary raster images. Provides seven algorithms behind a single dispatching function: Zhang-Suen (Zhang and Suen 1984) <doi:10.1145/357994.358023>, Guo-Hall (Guo and Hall 1989) <doi:10.1145/62065.62074>, a 2-D adaptation of Lee (Lee, Kashyap, and Chu 1994) <doi:10.1006/cgip.1994.1042>, K3M (Saeed, Tabedzki, Rybnik, and Adamski 2010) <doi:10.2478/v10006-010-0024-4>, the parallel form commonly attributed to Hilditch (1969, in 'Machine Intelligence 4'), OPTA / SPTA (Naccache and Shinghal 1984), and Holt and colleagues (1987) <doi:10.1145/12527.12531>. Also provides the medial axis transform (Blum 1967) and a distance transform implementation following Felzenszwalb and Huttenlocher (2012) <doi:10.4086/toc.2012.v008a019>. The thin() API selects the algorithm by name, defaulting to Zhang-Suen. Complements the morphology in the 'EBImage' package, which does not provide a thinning operator. |
| License: | LGPL-3 |
| Encoding: | UTF-8 |
| Depends: | R (≥ 4.2) |
| LinkingTo: | Rcpp |
| Imports: | Rcpp |
| Suggests: | bench, covr, knitr, lintr, rmarkdown, styler, testthat (≥ 3.0.0) |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| RoxygenNote: | 8.0.0 |
| URL: | https://github.com/humanpred/thinr, https://humanpred.github.io/thinr/ |
| BugReports: | https://github.com/humanpred/thinr/issues |
| NeedsCompilation: | yes |
| Packaged: | 2026-07-26 20:56:14 UTC; bill |
| Author: | Bill Denney |
| Maintainer: | Bill Denney <wdenney@humanpredictions.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-07-26 21:10:02 UTC |
thinr: Binary Image Thinning Algorithms
Description
Thinning (also called skeletonization) reduces a binary image of a
shape to a one-pixel-wide centerline that preserves the shape's
topology. thinr provides seven thinning algorithms behind a
single dispatching function, plus the medial axis transform and a
fast distance transform.
Thinning algorithms (thin(method = ...))
-
zhang_suen— Zhang & Suen (1984) doi:10.1145/357994.358023. Default. -
guo_hall— Guo & Hall (1989) doi:10.1145/62065.62074. Often better corner preservation on diagonal features. -
lee— Lee, Kashyap & Chu (1994) doi:10.1006/cgip.1994.1042, 2-D adaptation. Four directional sub-iterations. -
k3m— Saeed, Tabędzki, Rybnik & Adamski (2010) doi:10.2478/v10006-010-0024-4. Six-phase lookup-table thinning. -
hilditch— parallel form commonly attributed to Hilditch (1969, in Machine Intelligence 4). Single-pass thinning with look-ahead crossing-number check. -
opta— Naccache & Shinghal (1984), "An investigation into the skeletonization approach of Hilditch", Pattern Recognition 17(3):279-284. One-pass safe-point thinning (SPTA). -
holt— Holt, Stewart, Clint & Perrott (1987) doi:10.1145/12527.12531. One-subcycle parallel thinning with edge information about neighbours.
See thin() and vignette("choosing-a-method") for guidance.
Medial axis and distance transform
-
medial_axis()— Medial axis transform (Blum 1967): the locus of foreground pixels that are ridge points of the distance transform. Optionally returns the per-pixel distance. -
distance_transform()— Euclidean (Felzenszwalb-Huttenlocher 2012, linear-time separable), Manhattan, or Chessboard distance from each foreground pixel to the nearest background pixel.
Relationship to EBImage
EBImage, the dominant image-processing package in R/Bioconductor,
supplies binary morphology (dilate(), erode(), distmap(),
watershed()) but no thinning / skeletonization operator. thinr
fills that gap with a small, dependency-light, LGPL-3 package (the
same licence as EBImage).
Author(s)
Maintainer: Bill Denney wdenney@humanpredictions.com (ORCID) (affiliation: Human Predictions, LLC)
Authors:
Bill Denney wdenney@humanpredictions.com (ORCID) (affiliation: Human Predictions, LLC)
See Also
Useful links:
Report bugs at https://github.com/humanpred/thinr/issues
Distance transform of a binary image
Description
Compute the distance from each foreground pixel to the nearest background pixel, under one of three standard metrics.
Usage
distance_transform(image, metric = c("euclidean", "manhattan", "chessboard"))
Arguments
image |
A binary image: a matrix where non-zero values are
foreground and zero values are background. Logical, integer, and
numeric inputs are accepted. |
metric |
Distance metric. One of:
|
Value
A numeric matrix of the same shape as image. Background
pixels are 0; foreground pixels carry their distance to the
nearest background pixel. When the image is entirely foreground
(no background pixel exists) every pixel is Inf, consistently
across all three metrics — the distance to a non-existent nearest
background pixel is unbounded, matching EBImage::distmap(). Only
pixels count as background; the region outside the matrix is not
treated as an implicit background border.
References
Felzenszwalb, P. F., & Huttenlocher, D. P. (2012). Distance transforms of sampled functions. Theory of Computing, 8(19), 415-428. doi:10.4086/toc.2012.v008a019
Rosenfeld, A., & Pfaltz, J. L. (1968). Distance functions on digital pictures. Pattern Recognition, 1(1), 33-61. doi:10.1016/0031-3203(68)90013-7
Examples
# A 5x5 image with a single background pixel in the corner.
m <- matrix(1L, nrow = 5, ncol = 5)
m[1, 1] <- 0L
distance_transform(m, metric = "manhattan")
distance_transform(m, metric = "chessboard")
round(distance_transform(m, metric = "euclidean"), 3)
Medial axis transform
Description
Return the medial axis of a binary image: the locus of foreground pixels that are local maxima of the (squared) Euclidean distance transform in at least one of the four principal directions (horizontal, vertical, NW-SE diagonal, NE-SW diagonal). Each skeleton pixel carries width information via the distance value at that point.
Usage
medial_axis(image, return_distance = FALSE)
Arguments
image |
A binary image: a matrix where non-zero values are
foreground and zero values are background. Logical, integer, and
numeric inputs are accepted; |
return_distance |
Logical. If |
Details
This is different from thin(): classical thinning algorithms
produce a connected, 1-pixel-wide skeleton without width
information. The medial axis transform (Blum 1967) produces a
skeleton with width information, useful for shape analysis
where local thickness matters.
Value
Either a matrix (when return_distance = FALSE) or a
list(skeleton, distance) (when return_distance = TRUE).
References
Blum, H. (1967). A transformation for extracting new descriptors of shape. In Models for the Perception of Speech and Visual Form (pp. 362-380). MIT Press.
Felzenszwalb, P. F., & Huttenlocher, D. P. (2012). Distance transforms of sampled functions. Theory of Computing, 8(19), 415-428. doi:10.4086/toc.2012.v008a019
Examples
# A 7x9 solid rectangle: the medial axis is the middle row.
m <- matrix(0L, nrow = 7, ncol = 9)
m[3:5, 3:7] <- 1L
medial_axis(m)
# Returning width information alongside the skeleton.
result <- medial_axis(m, return_distance = TRUE)
result$skeleton
round(result$distance, 3)
Thin (skeletonize) a binary image
Description
Reduce a binary image to its one-pixel-wide skeleton using one of the supported thinning algorithms.
Usage
thin(
image,
method = c("zhang_suen", "guo_hall", "lee", "k3m", "hilditch", "opta", "holt"),
max_iter = 1000L
)
Arguments
image |
A binary image: a matrix or array where non-zero values
are foreground and zero values are background. Logical, integer, and
numeric inputs are all accepted. |
method |
Algorithm to use. One of |
max_iter |
Maximum number of passes. Default 1000. Real binary images of typical sizes converge well under 50 passes; the limit is a safety bound against pathological inputs. |
Value
A matrix of the same shape and storage mode as image, with
foreground pixels marking the thinned skeleton and the rest set to
background.
Edge handling
Every kernel inspects an 8-neighbourhood, so a naive implementation
can never delete a pixel in the outermost row or column and leaves
shapes that touch the matrix border two or three pixels thick. thin()
therefore surrounds the image with a one-pixel background margin before
thinning and crops it back afterwards, so a shape is skeletonised
identically whether or not it touches the frame. This applies uniformly
to all seven methods.
Connectivity
Thinning only ever deletes foreground pixels, and each method deletes
in an order that keeps 8-connected components connected: an object that
starts as one connected component thins to one connected component. In
particular a two-pixel-wide stroke thins to a connected one-pixel line
rather than fragmenting. See vignette("correctness-properties").
Examples
# A 3x3 solid square thins to a single foreground pixel.
m <- matrix(c(0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 1, 1, 1, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0),
nrow = 5, byrow = TRUE)
thin(m, method = "zhang_suen")
thin(m, method = "guo_hall")
thin(m, method = "hilditch")