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

23 statements  

1''' 

2Contains code from scikit-image v0.18.3 

3''' 

4 

5import numpy as np 

6from .dtype import img_as_ubyte 

7from .arraycrop import crop 

8 

9from ._skeletonize_3d_cy import _compute_thin_image 

10 

11 

12def skeletonize(image, periodic=False): 

13 """Compute the skeleton of a binary image. 

14 

15 Thinning is used to reduce each connected component in a binary image 

16 to a single-pixel wide skeleton. 

17 

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. 

26 

27 Returns 

28 ------- 

29 skeleton : ndarray 

30 The thinned image. 

31 

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. 

40 

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. 

46 

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) 

54 

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) 

61 

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') 

68 

69 # normalize to binary 

70 # maxval = image_o.max() 

71 image_o[image_o != 0] = 1 

72 

73 # do the computation 

74 image_o = np.asarray(_compute_thin_image(image_o, periodic=periodic)) 

75 

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 

81 

82 return image_o