Coverage for .tox/py39/lib/python3.9/site-packages/cows/skeletonize.py: 100.00%
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1'''
2Contains code from scikit-image v0.18.3
3'''
5import numpy as np
6from .dtype import img_as_ubyte
7from .arraycrop import crop
9from ._skeletonize_3d_cy import _compute_thin_image
12def skeletonize(image, periodic=False):
13 """Compute the skeleton of a binary image.
15 Thinning is used to reduce each connected component in a binary image
16 to a single-pixel wide skeleton.
18 Parameters
19 ----------
20 image : ndarray, 2D or 3D
21 A binary image containing the objects to be skeletonized. Zeros
22 represent background, nonzero values are foreground.
23 periodic: bool
24 If True, the skeletonization uses periodic boundary conditions
25 for the input array. Input array must be 3D.
27 Returns
28 -------
29 skeleton : ndarray
30 The thinned image.
32 Notes
33 -----
34 The method of [Lee94]_ uses an octree data structure to examine a 3x3x3
35 neighborhood of a pixel. The algorithm proceeds by iteratively sweeping
36 over the image, and removing pixels at each iteration until the image
37 stops changing. Each iteration consists of two steps: first, a list of
38 candidates for removal is assembled; then pixels from this list are
39 rechecked sequentially, to better preserve connectivity of the image.
41 References
42 ----------
43 .. [Lee94] T.-C. Lee, R.L. Kashyap and C.-N. Chu, Building skeleton models
44 via 3-D medial surface/axis thinning algorithms.
45 Computer Vision, Graphics, and Image Processing, 56(6):462-478, 1994.
47 """
48 # make sure the image is 3D or 2D
49 if image.ndim < 2 or image.ndim > 3:
50 raise ValueError("skeletonize can only handle 2D or 3D images; "
51 "got image.ndim = %s instead." % image.ndim)
52 image = np.ascontiguousarray(image)
53 image = img_as_ubyte(image, force_copy=False)
55 if type(periodic) != bool:
56 raise TypeError("keyword argument periodic must of of type bool; "
57 "got type %s instead." % type(periodic))
58 if periodic and image.ndim != 3:
59 raise ValueError("periodic boundaries currently only work for 3D "
60 "data. image.ndim = %s." % image.ndim)
62 # make an in image 3D and pad it w/ zeros to simplify dealing w/ boundaries
63 # NB: careful here to not clobber the original *and* minimize copying
64 image_o = image
65 if image.ndim == 2:
66 image_o = image[np.newaxis, ...]
67 image_o = np.pad(image_o, pad_width=1, mode='constant')
69 # normalize to binary
70 # maxval = image_o.max()
71 image_o[image_o != 0] = 1
73 # do the computation
74 image_o = np.asarray(_compute_thin_image(image_o, periodic=periodic))
76 # crop it back and restore the original intensity range
77 image_o = crop(image_o, crop_width=1)
78 if image.ndim == 2:
79 image_o = image_o[0]
80 # image_o *= maxval
82 return image_o