mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-27 11:27:08 +08:00
Added unit tests to skeletonization
This commit is contained in:
@@ -6,6 +6,7 @@ Original author: Neil Yager
|
||||
|
||||
import numpy as np
|
||||
from scipy.ndimage import correlate
|
||||
from .. import util
|
||||
|
||||
def skeletonize(image):
|
||||
"""
|
||||
@@ -26,7 +27,8 @@ def skeletonize(image):
|
||||
|
||||
image: ndarray (2D)
|
||||
A binary image containing the objects to be skeletonized. '1'
|
||||
represents foreground, and '0' represents background.
|
||||
represents foreground, and '0' represents background. It
|
||||
also accepts arrays of boolean values where True is foreground.
|
||||
|
||||
Notes
|
||||
-----
|
||||
@@ -62,15 +64,24 @@ def skeletonize(image):
|
||||
3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
2,3,1,3,0,0,1,3,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
2,3,0,1,0,0,0,1,0,0,0,0,0,0,0,0,3,3,0,1,0,0,0,0,2,2,0,0,2,0,0,0]
|
||||
|
||||
# convert to unsigned int (this should work for boolean values)
|
||||
skeleton = np.array(image).astype(np.uint8)
|
||||
|
||||
# check some properties of the input image:
|
||||
# - 2D
|
||||
# - binary image with only 0's and 1's
|
||||
if skeleton.ndim != 2:
|
||||
raise ValueError('Skeletonize requires a 2D array')
|
||||
for val in np.unique(skeleton):
|
||||
if val not in [0, 1]:
|
||||
raise ValueError('Invalid value in the image: %d'%(val))
|
||||
|
||||
# initialize the skeleton to the original image
|
||||
# TODO: how to handle data types
|
||||
skeleton = image.copy().astype(np.int8)
|
||||
|
||||
# create the mask that will assign a value based on neighbouring pixels
|
||||
# create the mask that will assign a unique value based on the
|
||||
# arrangement of neighbouring pixels
|
||||
mask = np.array([[ 1, 2, 4],
|
||||
[128, 0, 8],
|
||||
[ 64, 32, 16]], np.int8)
|
||||
[ 64, 32, 16]], np.uint8)
|
||||
|
||||
pixelRemoved = True
|
||||
while pixelRemoved:
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
from scikits.image.morphology import skeletonize
|
||||
import numpy.testing
|
||||
from scikits.image.draw import draw
|
||||
from scipy.ndimage import correlate
|
||||
|
||||
class TestSkeletonize(unittest.TestCase):
|
||||
def test_skeletonize_no_foreground(self):
|
||||
im = np.zeros((5,5))
|
||||
result = skeletonize.skeletonize(im)
|
||||
numpy.testing.assert_array_equal(result, np.zeros((5,5)))
|
||||
|
||||
def test_skeletonize_wrong_dim1(self):
|
||||
im = np.zeros((5))
|
||||
self.assertRaises(ValueError, skeletonize.skeletonize, im)
|
||||
|
||||
def test_skeletonize_wrong_dim2(self):
|
||||
im = np.zeros((5, 5, 5))
|
||||
self.assertRaises(ValueError, skeletonize.skeletonize, im)
|
||||
|
||||
def test_skeletonize_not_binary(self):
|
||||
im = np.zeros((5, 5))
|
||||
im[0, 0] = 1
|
||||
im[0, 1] = 2
|
||||
self.assertRaises(ValueError, skeletonize.skeletonize, im)
|
||||
|
||||
def test_skeletonize_unexpected_value(self):
|
||||
im = np.zeros((5, 5))
|
||||
im[0, 0] = 2
|
||||
self.assertRaises(ValueError, skeletonize.skeletonize, im)
|
||||
|
||||
def test_skeletonize_all_foreground(self):
|
||||
im = np.ones((3,4))
|
||||
result = skeletonize.skeletonize(im)
|
||||
|
||||
def test_skeletonize_single_point(self):
|
||||
im = np.zeros((5, 5), np.uint8)
|
||||
im[3, 3] = 1
|
||||
result = skeletonize.skeletonize(im)
|
||||
numpy.testing.assert_array_equal(result, im)
|
||||
|
||||
def test_skeletonize_already_thinned(self):
|
||||
im = np.zeros((5, 5), np.uint8)
|
||||
im[3,1:-1] = 1
|
||||
im[2, -1] = 1
|
||||
im[4, 0] = 1
|
||||
result = skeletonize.skeletonize(im)
|
||||
numpy.testing.assert_array_equal(result, im)
|
||||
|
||||
def test_skeletonize_num_neighbours(self):
|
||||
# an empty image
|
||||
image = np.zeros((300, 300))
|
||||
|
||||
# foreground object 1
|
||||
image[10:-10, 10:100] = 1
|
||||
image[-100:-10, 10:-10] = 1
|
||||
image[10:-10, -100:-10] = 1
|
||||
|
||||
# foreground object 2
|
||||
rs, cs = draw.bresenham(250, 150, 10, 280)
|
||||
for i in range(10): image[rs+i, cs] = 1
|
||||
rs, cs = draw.bresenham(10, 150, 250, 280)
|
||||
for i in range(20): image[rs+i, cs] = 1
|
||||
|
||||
# foreground object 3
|
||||
ir, ic = np.indices(image.shape)
|
||||
circle1 = (ic - 135)**2 + (ir - 150)**2 < 30**2
|
||||
circle2 = (ic - 135)**2 + (ir - 150)**2 < 20**2
|
||||
image[circle1] = 1
|
||||
image[circle2] = 0
|
||||
result = skeletonize.skeletonize(image)
|
||||
|
||||
# there should never be a 2x2 block of foreground pixels
|
||||
# in a skeleton
|
||||
mask = np.array([[1, 1],
|
||||
[1, 1]], np.uint8)
|
||||
blocks = correlate(result, mask, mode='constant')
|
||||
self.assertFalse(numpy.any(blocks == 4))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user