Fixed database typo and removed unnecessary class identifier.
This commit is contained in:
parent
00ad49a143
commit
45fb349a7d
5098 changed files with 952558 additions and 85 deletions
|
@ -0,0 +1,9 @@
|
|||
from ..._shared.testing import setup_test, teardown_test
|
||||
|
||||
|
||||
def setup():
|
||||
setup_test()
|
||||
|
||||
|
||||
def teardown():
|
||||
teardown_test()
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
178
venv/Lib/site-packages/skimage/morphology/tests/test_binary.py
Normal file
178
venv/Lib/site-packages/skimage/morphology/tests/test_binary.py
Normal file
|
@ -0,0 +1,178 @@
|
|||
import numpy as np
|
||||
from numpy import testing
|
||||
|
||||
from skimage import data, color
|
||||
from skimage.util import img_as_bool
|
||||
from skimage.morphology import binary, grey, selem
|
||||
from scipy import ndimage as ndi
|
||||
|
||||
import pytest
|
||||
|
||||
img = color.rgb2gray(data.astronaut())
|
||||
bw_img = img > 100 / 255.
|
||||
|
||||
|
||||
def test_non_square_image():
|
||||
strel = selem.square(3)
|
||||
binary_res = binary.binary_erosion(bw_img[:100, :200], strel)
|
||||
grey_res = img_as_bool(grey.erosion(bw_img[:100, :200], strel))
|
||||
testing.assert_array_equal(binary_res, grey_res)
|
||||
|
||||
|
||||
def test_binary_erosion():
|
||||
strel = selem.square(3)
|
||||
binary_res = binary.binary_erosion(bw_img, strel)
|
||||
grey_res = img_as_bool(grey.erosion(bw_img, strel))
|
||||
testing.assert_array_equal(binary_res, grey_res)
|
||||
|
||||
|
||||
def test_binary_dilation():
|
||||
strel = selem.square(3)
|
||||
binary_res = binary.binary_dilation(bw_img, strel)
|
||||
grey_res = img_as_bool(grey.dilation(bw_img, strel))
|
||||
testing.assert_array_equal(binary_res, grey_res)
|
||||
|
||||
|
||||
def test_binary_closing():
|
||||
strel = selem.square(3)
|
||||
binary_res = binary.binary_closing(bw_img, strel)
|
||||
grey_res = img_as_bool(grey.closing(bw_img, strel))
|
||||
testing.assert_array_equal(binary_res, grey_res)
|
||||
|
||||
|
||||
def test_binary_opening():
|
||||
strel = selem.square(3)
|
||||
binary_res = binary.binary_opening(bw_img, strel)
|
||||
grey_res = img_as_bool(grey.opening(bw_img, strel))
|
||||
testing.assert_array_equal(binary_res, grey_res)
|
||||
|
||||
|
||||
def test_selem_overflow():
|
||||
strel = np.ones((17, 17), dtype=np.uint8)
|
||||
img = np.zeros((20, 20), dtype=bool)
|
||||
img[2:19, 2:19] = True
|
||||
binary_res = binary.binary_erosion(img, strel)
|
||||
grey_res = img_as_bool(grey.erosion(img, strel))
|
||||
testing.assert_array_equal(binary_res, grey_res)
|
||||
|
||||
|
||||
def test_out_argument():
|
||||
for func in (binary.binary_erosion, binary.binary_dilation):
|
||||
strel = np.ones((3, 3), dtype=np.uint8)
|
||||
img = np.ones((10, 10))
|
||||
out = np.zeros_like(img)
|
||||
out_saved = out.copy()
|
||||
func(img, strel, out=out)
|
||||
testing.assert_(np.any(out != out_saved))
|
||||
testing.assert_array_equal(out, func(img, strel))
|
||||
|
||||
|
||||
binary_functions = [binary.binary_erosion, binary.binary_dilation,
|
||||
binary.binary_opening, binary.binary_closing]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("function", binary_functions)
|
||||
def test_default_selem(function):
|
||||
strel = selem.diamond(radius=1)
|
||||
image = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], np.uint8)
|
||||
im_expected = function(image, strel)
|
||||
im_test = function(image)
|
||||
testing.assert_array_equal(im_expected, im_test)
|
||||
|
||||
def test_3d_fallback_default_selem():
|
||||
# 3x3x3 cube inside a 7x7x7 image:
|
||||
image = np.zeros((7, 7, 7), np.bool)
|
||||
image[2:-2, 2:-2, 2:-2] = 1
|
||||
|
||||
opened = binary.binary_opening(image)
|
||||
|
||||
# expect a "hyper-cross" centered in the 5x5x5:
|
||||
image_expected = np.zeros((7, 7, 7), dtype=bool)
|
||||
image_expected[2:5, 2:5, 2:5] = ndi.generate_binary_structure(3, 1)
|
||||
testing.assert_array_equal(opened, image_expected)
|
||||
|
||||
|
||||
binary_3d_fallback_functions = [binary.binary_opening, binary.binary_closing]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("function", binary_3d_fallback_functions)
|
||||
def test_3d_fallback_cube_selem(function):
|
||||
# 3x3x3 cube inside a 7x7x7 image:
|
||||
image = np.zeros((7, 7, 7), np.bool)
|
||||
image[2:-2, 2:-2, 2:-2] = 1
|
||||
|
||||
cube = np.ones((3, 3, 3), dtype=np.uint8)
|
||||
|
||||
new_image = function(image, cube)
|
||||
testing.assert_array_equal(new_image, image)
|
||||
|
||||
def test_2d_ndimage_equivalence():
|
||||
image = np.zeros((9, 9), np.uint16)
|
||||
image[2:-2, 2:-2] = 2**14
|
||||
image[3:-3, 3:-3] = 2**15
|
||||
image[4, 4] = 2**16-1
|
||||
|
||||
bin_opened = binary.binary_opening(image)
|
||||
bin_closed = binary.binary_closing(image)
|
||||
|
||||
selem = ndi.generate_binary_structure(2, 1)
|
||||
ndimage_opened = ndi.binary_opening(image, structure=selem)
|
||||
ndimage_closed = ndi.binary_closing(image, structure=selem)
|
||||
|
||||
testing.assert_array_equal(bin_opened, ndimage_opened)
|
||||
testing.assert_array_equal(bin_closed, ndimage_closed)
|
||||
|
||||
def test_binary_output_2d():
|
||||
image = np.zeros((9, 9), np.uint16)
|
||||
image[2:-2, 2:-2] = 2**14
|
||||
image[3:-3, 3:-3] = 2**15
|
||||
image[4, 4] = 2**16-1
|
||||
|
||||
bin_opened = binary.binary_opening(image)
|
||||
bin_closed = binary.binary_closing(image)
|
||||
|
||||
int_opened = np.empty_like(image, dtype=np.uint8)
|
||||
int_closed = np.empty_like(image, dtype=np.uint8)
|
||||
binary.binary_opening(image, out=int_opened)
|
||||
binary.binary_closing(image, out=int_closed)
|
||||
|
||||
testing.assert_equal(bin_opened.dtype, np.bool)
|
||||
testing.assert_equal(bin_closed.dtype, np.bool)
|
||||
|
||||
testing.assert_equal(int_opened.dtype, np.uint8)
|
||||
testing.assert_equal(int_closed.dtype, np.uint8)
|
||||
|
||||
def test_binary_output_3d():
|
||||
image = np.zeros((9, 9, 9), np.uint16)
|
||||
image[2:-2, 2:-2, 2:-2] = 2**14
|
||||
image[3:-3, 3:-3, 3:-3] = 2**15
|
||||
image[4, 4, 4] = 2**16-1
|
||||
|
||||
bin_opened = binary.binary_opening(image)
|
||||
bin_closed = binary.binary_closing(image)
|
||||
|
||||
int_opened = np.empty_like(image, dtype=np.uint8)
|
||||
int_closed = np.empty_like(image, dtype=np.uint8)
|
||||
binary.binary_opening(image, out=int_opened)
|
||||
binary.binary_closing(image, out=int_closed)
|
||||
|
||||
testing.assert_equal(bin_opened.dtype, np.bool)
|
||||
testing.assert_equal(bin_closed.dtype, np.bool)
|
||||
|
||||
testing.assert_equal(int_opened.dtype, np.uint8)
|
||||
testing.assert_equal(int_closed.dtype, np.uint8)
|
||||
|
||||
if __name__ == '__main__':
|
||||
testing.run_module_suite()
|
313
venv/Lib/site-packages/skimage/morphology/tests/test_ccomp.py
Normal file
313
venv/Lib/site-packages/skimage/morphology/tests/test_ccomp.py
Normal file
|
@ -0,0 +1,313 @@
|
|||
import numpy as np
|
||||
|
||||
from skimage.measure import label
|
||||
import skimage.measure._ccomp as ccomp
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_array_equal
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
|
||||
|
||||
BG = 0 # background value
|
||||
|
||||
|
||||
class TestConnectedComponents:
|
||||
def setup(self):
|
||||
self.x = np.array([
|
||||
[0, 0, 3, 2, 1, 9],
|
||||
[0, 1, 1, 9, 2, 9],
|
||||
[0, 0, 1, 9, 9, 9],
|
||||
[3, 1, 1, 5, 3, 0]])
|
||||
|
||||
self.labels = np.array([
|
||||
[0, 0, 1, 2, 3, 4],
|
||||
[0, 5, 5, 4, 2, 4],
|
||||
[0, 0, 5, 4, 4, 4],
|
||||
[6, 5, 5, 7, 8, 0]])
|
||||
|
||||
# No background - there is no label 0, instead, labelling starts with 1
|
||||
# and all labels are incremented by 1.
|
||||
self.labels_nobg = self.labels + 1
|
||||
# The 0 at lower right corner is isolated, so it should get a new label
|
||||
self.labels_nobg[-1, -1] = 10
|
||||
|
||||
# We say that background value is 9 (and bg label is 0)
|
||||
self.labels_bg_9 = self.labels_nobg.copy()
|
||||
self.labels_bg_9[self.x == 9] = 0
|
||||
# Then, where there was the label 5, we now expect 4 etc.
|
||||
# (we assume that the label of value 9 would normally be 5)
|
||||
self.labels_bg_9[self.labels_bg_9 > 5] -= 1
|
||||
|
||||
def test_basic(self):
|
||||
assert_array_equal(label(self.x), self.labels)
|
||||
|
||||
# Make sure data wasn't modified
|
||||
assert self.x[0, 2] == 3
|
||||
|
||||
# Check that everything works if there is no background
|
||||
assert_array_equal(label(self.x, background=99), self.labels_nobg)
|
||||
# Check that everything works if background value != 0
|
||||
assert_array_equal(label(self.x, background=9), self.labels_bg_9)
|
||||
|
||||
def test_random(self):
|
||||
x = (np.random.rand(20, 30) * 5).astype(np.int)
|
||||
labels = label(x)
|
||||
|
||||
n = labels.max()
|
||||
for i in range(n):
|
||||
values = x[labels == i]
|
||||
assert np.all(values == values[0])
|
||||
|
||||
def test_diag(self):
|
||||
x = np.array([[0, 0, 1],
|
||||
[0, 1, 0],
|
||||
[1, 0, 0]])
|
||||
assert_array_equal(label(x), x)
|
||||
|
||||
def test_4_vs_8(self):
|
||||
x = np.array([[0, 1],
|
||||
[1, 0]], dtype=int)
|
||||
with expected_warnings(["use 'connectivity'"]):
|
||||
assert_array_equal(label(x, 4),
|
||||
[[0, 1],
|
||||
[2, 0]])
|
||||
assert_array_equal(label(x, 8),
|
||||
[[0, 1],
|
||||
[1, 0]])
|
||||
|
||||
assert_array_equal(label(x, connectivity=1),
|
||||
[[0, 1],
|
||||
[2, 0]])
|
||||
assert_array_equal(label(x, connectivity=2),
|
||||
[[0, 1],
|
||||
[1, 0]])
|
||||
|
||||
def test_background(self):
|
||||
x = np.array([[1, 0, 0],
|
||||
[1, 1, 5],
|
||||
[0, 0, 0]])
|
||||
|
||||
assert_array_equal(label(x), [[1, 0, 0],
|
||||
[1, 1, 2],
|
||||
[0, 0, 0]])
|
||||
|
||||
assert_array_equal(label(x, background=0),
|
||||
[[1, 0, 0],
|
||||
[1, 1, 2],
|
||||
[0, 0, 0]])
|
||||
|
||||
def test_background_two_regions(self):
|
||||
x = np.array([[0, 0, 6],
|
||||
[0, 0, 6],
|
||||
[5, 5, 5]])
|
||||
|
||||
res = label(x, background=0)
|
||||
assert_array_equal(res,
|
||||
[[0, 0, 1],
|
||||
[0, 0, 1],
|
||||
[2, 2, 2]])
|
||||
|
||||
def test_background_one_region_center(self):
|
||||
x = np.array([[0, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, 0]])
|
||||
|
||||
with expected_warnings(["use 'connectivity'"]):
|
||||
assert_array_equal(label(x, neighbors=4, background=0),
|
||||
[[0, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, 0]])
|
||||
assert_array_equal(label(x, connectivity=1, background=0),
|
||||
[[0, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, 0]])
|
||||
|
||||
|
||||
def test_return_num(self):
|
||||
x = np.array([[1, 0, 6],
|
||||
[0, 0, 6],
|
||||
[5, 5, 5]])
|
||||
|
||||
assert_array_equal(label(x, return_num=True)[1], 3)
|
||||
|
||||
assert_array_equal(label(x, background=-1, return_num=True)[1], 4)
|
||||
|
||||
|
||||
class TestConnectedComponents3d:
|
||||
def setup(self):
|
||||
self.x = np.zeros((3, 4, 5), int)
|
||||
self.x[0] = np.array([[0, 3, 2, 1, 9],
|
||||
[0, 1, 9, 2, 9],
|
||||
[0, 1, 9, 9, 9],
|
||||
[3, 1, 5, 3, 0]])
|
||||
|
||||
self.x[1] = np.array([[3, 3, 2, 1, 9],
|
||||
[0, 3, 9, 2, 1],
|
||||
[0, 3, 3, 1, 1],
|
||||
[3, 1, 3, 3, 0]])
|
||||
|
||||
self.x[2] = np.array([[3, 3, 8, 8, 0],
|
||||
[2, 3, 9, 8, 8],
|
||||
[2, 3, 0, 8, 0],
|
||||
[2, 1, 0, 0, 0]])
|
||||
|
||||
self.labels = np.zeros((3, 4, 5), int)
|
||||
|
||||
self.labels[0] = np.array([[0, 1, 2, 3, 4],
|
||||
[0, 5, 4, 2, 4],
|
||||
[0, 5, 4, 4, 4],
|
||||
[1, 5, 6, 1, 0]])
|
||||
|
||||
self.labels[1] = np.array([[1, 1, 2, 3, 4],
|
||||
[0, 1, 4, 2, 3],
|
||||
[0, 1, 1, 3, 3],
|
||||
[1, 5, 1, 1, 0]])
|
||||
|
||||
self.labels[2] = np.array([[1, 1, 7, 7, 0],
|
||||
[8, 1, 4, 7, 7],
|
||||
[8, 1, 0, 7, 0],
|
||||
[8, 5, 0, 0, 0]])
|
||||
|
||||
def test_basic(self):
|
||||
labels = label(self.x)
|
||||
assert_array_equal(labels, self.labels)
|
||||
|
||||
assert self.x[0, 0, 2] == 2, \
|
||||
"Data was modified!"
|
||||
|
||||
def test_random(self):
|
||||
x = (np.random.rand(20, 30) * 5).astype(np.int)
|
||||
labels = label(x)
|
||||
|
||||
n = labels.max()
|
||||
for i in range(n):
|
||||
values = x[labels == i]
|
||||
assert np.all(values == values[0])
|
||||
|
||||
def test_diag(self):
|
||||
x = np.zeros((3, 3, 3), int)
|
||||
x[0, 2, 2] = 1
|
||||
x[1, 1, 1] = 1
|
||||
x[2, 0, 0] = 1
|
||||
assert_array_equal(label(x), x)
|
||||
|
||||
def test_4_vs_8(self):
|
||||
x = np.zeros((2, 2, 2), int)
|
||||
x[0, 1, 1] = 1
|
||||
x[1, 0, 0] = 1
|
||||
label4 = x.copy()
|
||||
label4[1, 0, 0] = 2
|
||||
with expected_warnings(["use 'connectivity'"]):
|
||||
assert_array_equal(label(x, 4), label4)
|
||||
assert_array_equal(label(x, 8), x)
|
||||
|
||||
def test_connectivity_1_vs_2(self):
|
||||
x = np.zeros((2, 2, 2), int)
|
||||
x[0, 1, 1] = 1
|
||||
x[1, 0, 0] = 1
|
||||
label1 = x.copy()
|
||||
label1[1, 0, 0] = 2
|
||||
assert_array_equal(label(x, connectivity=1), label1)
|
||||
assert_array_equal(label(x, connectivity=3), x)
|
||||
|
||||
def test_background(self):
|
||||
x = np.zeros((2, 3, 3), int)
|
||||
x[0] = np.array([[1, 0, 0],
|
||||
[1, 0, 0],
|
||||
[0, 0, 0]])
|
||||
x[1] = np.array([[0, 0, 0],
|
||||
[0, 1, 5],
|
||||
[0, 0, 0]])
|
||||
|
||||
lnb = x.copy()
|
||||
lnb[0] = np.array([[1, 2, 2],
|
||||
[1, 2, 2],
|
||||
[2, 2, 2]])
|
||||
lnb[1] = np.array([[2, 2, 2],
|
||||
[2, 1, 3],
|
||||
[2, 2, 2]])
|
||||
lb = x.copy()
|
||||
lb[0] = np.array([[1, BG, BG],
|
||||
[1, BG, BG],
|
||||
[BG, BG, BG]])
|
||||
lb[1] = np.array([[BG, BG, BG],
|
||||
[BG, 1, 2],
|
||||
[BG, BG, BG]])
|
||||
|
||||
assert_array_equal(label(x), lb)
|
||||
assert_array_equal(label(x, background=-1), lnb)
|
||||
|
||||
def test_background_two_regions(self):
|
||||
x = np.zeros((2, 3, 3), int)
|
||||
x[0] = np.array([[0, 0, 6],
|
||||
[0, 0, 6],
|
||||
[5, 5, 5]])
|
||||
x[1] = np.array([[6, 6, 0],
|
||||
[5, 0, 0],
|
||||
[0, 0, 0]])
|
||||
lb = x.copy()
|
||||
lb[0] = np.array([[BG, BG, 1],
|
||||
[BG, BG, 1],
|
||||
[2, 2, 2]])
|
||||
lb[1] = np.array([[1, 1, BG],
|
||||
[2, BG, BG],
|
||||
[BG, BG, BG]])
|
||||
|
||||
res = label(x, background=0)
|
||||
assert_array_equal(res, lb)
|
||||
|
||||
def test_background_one_region_center(self):
|
||||
x = np.zeros((3, 3, 3), int)
|
||||
x[1, 1, 1] = 1
|
||||
|
||||
lb = np.ones_like(x) * BG
|
||||
lb[1, 1, 1] = 1
|
||||
|
||||
with expected_warnings(["use 'connectivity'"]):
|
||||
assert_array_equal(label(x, neighbors=4, background=0), lb)
|
||||
|
||||
assert_array_equal(label(x, connectivity=1, background=0), lb)
|
||||
|
||||
def test_return_num(self):
|
||||
x = np.array([[1, 0, 6],
|
||||
[0, 0, 6],
|
||||
[5, 5, 5]])
|
||||
|
||||
assert_array_equal(label(x, return_num=True)[1], 3)
|
||||
assert_array_equal(label(x, background=-1, return_num=True)[1], 4)
|
||||
|
||||
def test_1D(self):
|
||||
x = np.array((0, 1, 2, 2, 1, 1, 0, 0))
|
||||
xlen = len(x)
|
||||
y = np.array((0, 1, 2, 2, 3, 3, 0, 0))
|
||||
reshapes = ((xlen,),
|
||||
(1, xlen), (xlen, 1),
|
||||
(1, xlen, 1), (xlen, 1, 1), (1, 1, xlen))
|
||||
for reshape in reshapes:
|
||||
x2 = x.reshape(reshape)
|
||||
labelled = label(x2)
|
||||
assert_array_equal(y, labelled.flatten())
|
||||
|
||||
def test_nd(self):
|
||||
x = np.ones((1, 2, 3, 4))
|
||||
with testing.raises(NotImplementedError):
|
||||
label(x)
|
||||
|
||||
|
||||
class TestSupport:
|
||||
def test_reshape(self):
|
||||
shapes_in = ((3, 1, 2), (1, 4, 5), (3, 1, 1), (2, 1), (1,))
|
||||
for shape in shapes_in:
|
||||
shape = np.array(shape)
|
||||
numones = sum(shape == 1)
|
||||
inp = np.random.random(shape)
|
||||
|
||||
fixed, swaps = ccomp.reshape_array(inp)
|
||||
shape2 = fixed.shape
|
||||
# now check that all ones are at the beginning
|
||||
for i in range(numones):
|
||||
assert shape2[i] == 1
|
||||
|
||||
back = ccomp.undo_reshape_array(fixed, swaps)
|
||||
# check that the undo works as expected
|
||||
assert_array_equal(inp, back)
|
|
@ -0,0 +1,171 @@
|
|||
import numpy as np
|
||||
from skimage.morphology import convex_hull_image, convex_hull_object
|
||||
from skimage.morphology._convex_hull import possible_hull
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_array_equal
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
|
||||
|
||||
def test_basic():
|
||||
image = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 1, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool)
|
||||
|
||||
expected = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 1, 1, 0, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool)
|
||||
|
||||
assert_array_equal(convex_hull_image(image), expected)
|
||||
|
||||
|
||||
def test_empty_image():
|
||||
image = np.zeros((6, 6), dtype=bool)
|
||||
with expected_warnings(['entirely zero']):
|
||||
assert_array_equal(convex_hull_image(image), image)
|
||||
|
||||
|
||||
def test_qhull_offset_example():
|
||||
nonzeros = (([1367, 1368, 1368, 1368, 1369, 1369, 1369, 1369, 1369, 1370,
|
||||
1370, 1370, 1370, 1370, 1370, 1370, 1371, 1371, 1371, 1371,
|
||||
1371, 1371, 1371, 1371, 1371, 1372, 1372, 1372, 1372, 1372,
|
||||
1372, 1372, 1372, 1372, 1373, 1373, 1373, 1373, 1373, 1373,
|
||||
1373, 1373, 1373, 1374, 1374, 1374, 1374, 1374, 1374, 1374,
|
||||
1375, 1375, 1375, 1375, 1375, 1376, 1376, 1376, 1377]),
|
||||
([151, 150, 151, 152, 149, 150, 151, 152, 153, 148, 149, 150,
|
||||
151, 152, 153, 154, 147, 148, 149, 150, 151, 152, 153, 154,
|
||||
155, 146, 147, 148, 149, 150, 151, 152, 153, 154, 146, 147,
|
||||
148, 149, 150, 151, 152, 153, 154, 147, 148, 149, 150, 151,
|
||||
152, 153, 148, 149, 150, 151, 152, 149, 150, 151, 150]))
|
||||
image = np.zeros((1392, 1040), dtype=bool)
|
||||
image[nonzeros] = True
|
||||
expected = image.copy()
|
||||
assert_array_equal(convex_hull_image(image), expected)
|
||||
|
||||
|
||||
def test_pathological_qhull_example():
|
||||
image = np.array(
|
||||
[[0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 0, 0, 0, 0]], dtype=bool)
|
||||
expected = np.array(
|
||||
[[0, 0, 0, 1, 1, 1, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 0, 0, 0]], dtype=bool)
|
||||
assert_array_equal(convex_hull_image(image), expected)
|
||||
|
||||
|
||||
def test_possible_hull():
|
||||
image = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
|
||||
expected = np.array([[1, 4],
|
||||
[2, 3],
|
||||
[3, 2],
|
||||
[4, 1],
|
||||
[4, 1],
|
||||
[3, 2],
|
||||
[2, 3],
|
||||
[1, 4],
|
||||
[2, 5],
|
||||
[3, 6],
|
||||
[4, 7],
|
||||
[2, 5],
|
||||
[3, 6],
|
||||
[4, 7],
|
||||
[4, 2],
|
||||
[4, 3],
|
||||
[4, 4],
|
||||
[4, 5],
|
||||
[4, 6]])
|
||||
|
||||
ph = possible_hull(image)
|
||||
assert_array_equal(ph, expected)
|
||||
|
||||
|
||||
def test_object():
|
||||
image = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 0, 0, 1, 0, 1],
|
||||
[1, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[1, 0, 0, 0, 0, 0, 1, 0, 1],
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool)
|
||||
|
||||
expected_conn_1 = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 0, 0, 1, 0, 1],
|
||||
[1, 1, 1, 0, 0, 0, 0, 1, 0],
|
||||
[1, 1, 0, 0, 0, 0, 1, 0, 1],
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool)
|
||||
|
||||
assert_array_equal(convex_hull_object(image, connectivity=1),
|
||||
expected_conn_1)
|
||||
|
||||
expected_conn_2 = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 0, 0, 1, 1, 1],
|
||||
[1, 1, 1, 0, 0, 0, 1, 1, 1],
|
||||
[1, 1, 0, 0, 0, 0, 1, 1, 1],
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool)
|
||||
|
||||
assert_array_equal(convex_hull_object(image, connectivity=2),
|
||||
expected_conn_2)
|
||||
|
||||
with testing.raises(ValueError):
|
||||
convex_hull_object(image, connectivity=3)
|
||||
|
||||
with expected_warnings(['`neighbors` is deprecated']):
|
||||
out = convex_hull_object(image, neighbors=4)
|
||||
assert_array_equal(out, expected_conn_1)
|
||||
|
||||
|
||||
def test_non_c_contiguous():
|
||||
# 2D Fortran-contiguous
|
||||
image = np.ones((2, 2), order='F', dtype=bool)
|
||||
assert_array_equal(convex_hull_image(image), image)
|
||||
# 3D Fortran-contiguous
|
||||
image = np.ones((2, 2, 2), order='F', dtype=bool)
|
||||
assert_array_equal(convex_hull_image(image), image)
|
||||
# 3D non-contiguous
|
||||
image = np.transpose(np.ones((2, 2, 2), dtype=bool), [0, 2, 1])
|
||||
assert_array_equal(convex_hull_image(image), image)
|
||||
|
||||
|
||||
@testing.fixture
|
||||
def images2d3d():
|
||||
from ...measure.tests.test_regionprops import SAMPLE as image
|
||||
image3d = np.stack((image, image, image))
|
||||
return image, image3d
|
||||
|
||||
|
||||
def test_consistent_2d_3d_hulls(images2d3d):
|
||||
image, image3d = images2d3d
|
||||
chimage = convex_hull_image(image)
|
||||
chimage[8, 0] = True # correct for single point exactly on hull edge
|
||||
chimage3d = convex_hull_image(image3d)
|
||||
assert_array_equal(chimage3d[1], chimage)
|
623
venv/Lib/site-packages/skimage/morphology/tests/test_extrema.py
Normal file
623
venv/Lib/site-packages/skimage/morphology/tests/test_extrema.py
Normal file
|
@ -0,0 +1,623 @@
|
|||
import math
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_equal
|
||||
from pytest import raises, warns
|
||||
|
||||
from skimage.morphology import extrema
|
||||
|
||||
eps = 1e-12
|
||||
|
||||
|
||||
def diff(a, b):
|
||||
a = np.asarray(a, dtype=np.float64)
|
||||
b = np.asarray(b, dtype=np.float64)
|
||||
t = ((a - b) ** 2).sum()
|
||||
return math.sqrt(t)
|
||||
|
||||
|
||||
class TestExtrema(unittest.TestCase):
|
||||
|
||||
def test_saturated_arithmetic(self):
|
||||
"""Adding/subtracting a constant and clipping"""
|
||||
# Test for unsigned integer
|
||||
data = np.array([[250, 251, 5, 5],
|
||||
[100, 200, 253, 252],
|
||||
[4, 10, 1, 3]],
|
||||
dtype=np.uint8)
|
||||
# adding the constant
|
||||
img_constant_added = extrema._add_constant_clip(data, 4)
|
||||
expected = np.array([[254, 255, 9, 9],
|
||||
[104, 204, 255, 255],
|
||||
[8, 14, 5, 7]],
|
||||
dtype=np.uint8)
|
||||
error = diff(img_constant_added, expected)
|
||||
assert error < eps
|
||||
img_constant_subtracted = extrema._subtract_constant_clip(data, 4)
|
||||
expected = np.array([[246, 247, 1, 1],
|
||||
[96, 196, 249, 248],
|
||||
[0, 6, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
error = diff(img_constant_subtracted, expected)
|
||||
assert error < eps
|
||||
|
||||
# Test for signed integer
|
||||
data = np.array([[32767, 32766],
|
||||
[-32768, -32767]],
|
||||
dtype=np.int16)
|
||||
img_constant_added = extrema._add_constant_clip(data, 1)
|
||||
expected = np.array([[32767, 32767],
|
||||
[-32767, -32766]],
|
||||
dtype=np.int16)
|
||||
error = diff(img_constant_added, expected)
|
||||
assert error < eps
|
||||
img_constant_subtracted = extrema._subtract_constant_clip(data, 1)
|
||||
expected = np.array([[32766, 32765],
|
||||
[-32768, -32768]],
|
||||
dtype=np.int16)
|
||||
error = diff(img_constant_subtracted, expected)
|
||||
assert error < eps
|
||||
|
||||
def test_h_maxima(self):
|
||||
"""h-maxima for various data types"""
|
||||
|
||||
data = np.array([[10, 11, 13, 14, 14, 15, 14, 14, 13, 11],
|
||||
[11, 13, 15, 16, 16, 16, 16, 16, 15, 13],
|
||||
[13, 15, 40, 40, 18, 18, 18, 60, 60, 15],
|
||||
[14, 16, 40, 40, 19, 19, 19, 60, 60, 16],
|
||||
[14, 16, 18, 19, 19, 19, 19, 19, 18, 16],
|
||||
[15, 16, 18, 19, 19, 20, 19, 19, 18, 16],
|
||||
[14, 16, 18, 19, 19, 19, 19, 19, 18, 16],
|
||||
[14, 16, 80, 80, 19, 19, 19, 100, 100, 16],
|
||||
[13, 15, 80, 80, 18, 18, 18, 100, 100, 15],
|
||||
[11, 13, 15, 16, 16, 16, 16, 16, 15, 13]],
|
||||
dtype=np.uint8)
|
||||
|
||||
expected_result = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
for dtype in [np.uint8, np.uint64, np.int8, np.int64]:
|
||||
data = data.astype(dtype)
|
||||
out = extrema.h_maxima(data, 40)
|
||||
|
||||
error = diff(expected_result, out)
|
||||
assert error < eps
|
||||
|
||||
def test_h_minima(self):
|
||||
"""h-minima for various data types"""
|
||||
|
||||
data = np.array([[10, 11, 13, 14, 14, 15, 14, 14, 13, 11],
|
||||
[11, 13, 15, 16, 16, 16, 16, 16, 15, 13],
|
||||
[13, 15, 40, 40, 18, 18, 18, 60, 60, 15],
|
||||
[14, 16, 40, 40, 19, 19, 19, 60, 60, 16],
|
||||
[14, 16, 18, 19, 19, 19, 19, 19, 18, 16],
|
||||
[15, 16, 18, 19, 19, 20, 19, 19, 18, 16],
|
||||
[14, 16, 18, 19, 19, 19, 19, 19, 18, 16],
|
||||
[14, 16, 80, 80, 19, 19, 19, 100, 100, 16],
|
||||
[13, 15, 80, 80, 18, 18, 18, 100, 100, 15],
|
||||
[11, 13, 15, 16, 16, 16, 16, 16, 15, 13]],
|
||||
dtype=np.uint8)
|
||||
data = 100 - data
|
||||
expected_result = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
for dtype in [np.uint8, np.uint64, np.int8, np.int64]:
|
||||
data = data.astype(dtype)
|
||||
out = extrema.h_minima(data, 40)
|
||||
|
||||
error = diff(expected_result, out)
|
||||
assert error < eps
|
||||
assert out.dtype == expected_result.dtype
|
||||
|
||||
def test_extrema_float(self):
|
||||
"""specific tests for float type"""
|
||||
data = np.array([[0.10, 0.11, 0.13, 0.14, 0.14, 0.15, 0.14,
|
||||
0.14, 0.13, 0.11],
|
||||
[0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16,
|
||||
0.16, 0.15, 0.13],
|
||||
[0.13, 0.15, 0.40, 0.40, 0.18, 0.18, 0.18,
|
||||
0.60, 0.60, 0.15],
|
||||
[0.14, 0.16, 0.40, 0.40, 0.19, 0.19, 0.19,
|
||||
0.60, 0.60, 0.16],
|
||||
[0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19,
|
||||
0.19, 0.18, 0.16],
|
||||
[0.15, 0.182, 0.18, 0.19, 0.204, 0.20, 0.19,
|
||||
0.19, 0.18, 0.16],
|
||||
[0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19,
|
||||
0.19, 0.18, 0.16],
|
||||
[0.14, 0.16, 0.80, 0.80, 0.19, 0.19, 0.19,
|
||||
1.0, 1.0, 0.16],
|
||||
[0.13, 0.15, 0.80, 0.80, 0.18, 0.18, 0.18,
|
||||
1.0, 1.0, 0.15],
|
||||
[0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16,
|
||||
0.16, 0.15, 0.13]],
|
||||
dtype=np.float32)
|
||||
inverted_data = 1.0 - data
|
||||
|
||||
out = extrema.h_maxima(data, 0.003)
|
||||
expected_result = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
|
||||
error = diff(expected_result, out)
|
||||
assert error < eps
|
||||
|
||||
out = extrema.h_minima(inverted_data, 0.003)
|
||||
error = diff(expected_result, out)
|
||||
assert error < eps
|
||||
|
||||
def test_h_maxima_float_image(self):
|
||||
"""specific tests for h-maxima float image type"""
|
||||
w = 10
|
||||
x, y = np.mgrid[0:w, 0:w]
|
||||
data = 20 - 0.2 * ((x - w / 2) ** 2 + (y - w / 2) ** 2)
|
||||
data[2:4, 2:4] = 40
|
||||
data[2:4, 7:9] = 60
|
||||
data[7:9, 2:4] = 80
|
||||
data[7:9, 7:9] = 100
|
||||
data = data.astype(np.float32)
|
||||
|
||||
expected_result = np.zeros_like(data)
|
||||
expected_result[(data > 19.9)] = 1.0
|
||||
|
||||
for h in [1.0e-12, 1.0e-6, 1.0e-3, 1.0e-2, 1.0e-1, 0.1]:
|
||||
out = extrema.h_maxima(data, h)
|
||||
error = diff(expected_result, out)
|
||||
assert error < eps
|
||||
|
||||
def test_h_maxima_float_h(self):
|
||||
"""specific tests for h-maxima float h parameter"""
|
||||
data = np.array([[0, 0, 0, 0, 0],
|
||||
[0, 3, 3, 3, 0],
|
||||
[0, 3, 4, 3, 0],
|
||||
[0, 3, 3, 3, 0],
|
||||
[0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
|
||||
h_vals = np.linspace(1.0, 2.0, 100)
|
||||
failures = 0
|
||||
for i in range(h_vals.size):
|
||||
maxima = extrema.h_maxima(data, h_vals[i])
|
||||
|
||||
if (maxima[2, 2] == 0):
|
||||
failures += 1
|
||||
|
||||
assert (failures == 0)
|
||||
|
||||
def test_h_maxima_large_h(self):
|
||||
"""test that h-maxima works correctly for large h"""
|
||||
data = np.array([[10, 10, 10, 10, 10],
|
||||
[10, 13, 13, 13, 10],
|
||||
[10, 13, 14, 13, 10],
|
||||
[10, 13, 13, 13, 10],
|
||||
[10, 10, 10, 10, 10]], dtype=np.uint8)
|
||||
|
||||
maxima = extrema.h_maxima(data, 5)
|
||||
assert (np.sum(maxima) == 0)
|
||||
|
||||
data = np.array([[10, 10, 10, 10, 10],
|
||||
[10, 13, 13, 13, 10],
|
||||
[10, 13, 14, 13, 10],
|
||||
[10, 13, 13, 13, 10],
|
||||
[10, 10, 10, 10, 10]], dtype=np.float32)
|
||||
|
||||
maxima = extrema.h_maxima(data, 5.0)
|
||||
assert (np.sum(maxima) == 0)
|
||||
|
||||
def test_h_minima_float_image(self):
|
||||
"""specific tests for h-minima float image type"""
|
||||
w = 10
|
||||
x, y = np.mgrid[0:w, 0:w]
|
||||
data = 180 + 0.2 * ((x - w / 2) ** 2 + (y - w / 2) ** 2)
|
||||
data[2:4, 2:4] = 160
|
||||
data[2:4, 7:9] = 140
|
||||
data[7:9, 2:4] = 120
|
||||
data[7:9, 7:9] = 100
|
||||
data = data.astype(np.float32)
|
||||
|
||||
expected_result = np.zeros_like(data)
|
||||
expected_result[(data < 180.1)] = 1.0
|
||||
|
||||
for h in [1.0e-12, 1.0e-6, 1.0e-3, 1.0e-2, 1.0e-1, 0.1]:
|
||||
out = extrema.h_minima(data, h)
|
||||
error = diff(expected_result, out)
|
||||
assert error < eps
|
||||
|
||||
def test_h_minima_float_h(self):
|
||||
"""specific tests for h-minima float h parameter"""
|
||||
data = np.array([[4, 4, 4, 4, 4],
|
||||
[4, 1, 1, 1, 4],
|
||||
[4, 1, 0, 1, 4],
|
||||
[4, 1, 1, 1, 4],
|
||||
[4, 4, 4, 4, 4]], dtype=np.uint8)
|
||||
|
||||
h_vals = np.linspace(1.0, 2.0, 100)
|
||||
failures = 0
|
||||
for i in range(h_vals.size):
|
||||
minima = extrema.h_minima(data, h_vals[i])
|
||||
|
||||
if (minima[2, 2] == 0):
|
||||
failures += 1
|
||||
|
||||
assert (failures == 0)
|
||||
|
||||
def test_h_minima_large_h(self):
|
||||
"""test that h-minima works correctly for large h"""
|
||||
data = np.array([[14, 14, 14, 14, 14],
|
||||
[14, 11, 11, 11, 14],
|
||||
[14, 11, 10, 11, 14],
|
||||
[14, 11, 11, 11, 14],
|
||||
[14, 14, 14, 14, 14]], dtype=np.uint8)
|
||||
|
||||
maxima = extrema.h_minima(data, 5)
|
||||
assert (np.sum(maxima) == 0)
|
||||
|
||||
data = np.array([[14, 14, 14, 14, 14],
|
||||
[14, 11, 11, 11, 14],
|
||||
[14, 11, 10, 11, 14],
|
||||
[14, 11, 11, 11, 14],
|
||||
[14, 14, 14, 14, 14]], dtype=np.float32)
|
||||
|
||||
maxima = extrema.h_minima(data, 5.0)
|
||||
assert (np.sum(maxima) == 0)
|
||||
|
||||
|
||||
class TestLocalMaxima(unittest.TestCase):
|
||||
"""Some tests for local_minima are included as well."""
|
||||
|
||||
supported_dtypes = [
|
||||
np.uint8, np.uint16, np.uint32, np.uint64,
|
||||
np.int8, np.int16, np.int32, np.int64,
|
||||
np.float32, np.float64
|
||||
]
|
||||
image = np.array(
|
||||
[[1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 2, 0, 0, 3, 3, 0, 0, 4, 0, 2, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 4, 4, 0, 3, 0, 0, 0],
|
||||
[0, 2, 0, 1, 0, 2, 1, 0, 0, 0, 0, 3, 0, 0, 0],
|
||||
[0, 0, 2, 0, 2, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint8
|
||||
)
|
||||
# Connectivity 2, maxima can touch border, returned with default values
|
||||
expected_default = np.array(
|
||||
[[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.bool
|
||||
)
|
||||
# Connectivity 1 (cross), maxima can touch border
|
||||
expected_cross = np.array(
|
||||
[[1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0],
|
||||
[0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.bool
|
||||
)
|
||||
|
||||
def test_empty(self):
|
||||
"""Test result with empty image."""
|
||||
result = extrema.local_maxima(np.array([[]]), indices=False)
|
||||
assert result.size == 0
|
||||
assert result.dtype == np.bool
|
||||
assert result.shape == (1, 0)
|
||||
|
||||
result = extrema.local_maxima(np.array([]), indices=True)
|
||||
assert isinstance(result, tuple)
|
||||
assert len(result) == 1
|
||||
assert result[0].size == 0
|
||||
assert result[0].dtype == np.intp
|
||||
|
||||
result = extrema.local_maxima(np.array([[]]), indices=True)
|
||||
assert isinstance(result, tuple)
|
||||
assert len(result) == 2
|
||||
assert result[0].size == 0
|
||||
assert result[0].dtype == np.intp
|
||||
assert result[1].size == 0
|
||||
assert result[1].dtype == np.intp
|
||||
|
||||
def test_dtypes(self):
|
||||
"""Test results with default configuration for all supported dtypes."""
|
||||
for dtype in self.supported_dtypes:
|
||||
result = extrema.local_maxima(self.image.astype(dtype))
|
||||
assert result.dtype == np.bool
|
||||
assert_equal(result, self.expected_default)
|
||||
|
||||
def test_dtypes_old(self):
|
||||
"""
|
||||
Test results with default configuration and data copied from old unit
|
||||
tests for all supported dtypes.
|
||||
"""
|
||||
data = np.array(
|
||||
[[10, 11, 13, 14, 14, 15, 14, 14, 13, 11],
|
||||
[11, 13, 15, 16, 16, 16, 16, 16, 15, 13],
|
||||
[13, 15, 40, 40, 18, 18, 18, 60, 60, 15],
|
||||
[14, 16, 40, 40, 19, 19, 19, 60, 60, 16],
|
||||
[14, 16, 18, 19, 19, 19, 19, 19, 18, 16],
|
||||
[15, 16, 18, 19, 19, 20, 19, 19, 18, 16],
|
||||
[14, 16, 18, 19, 19, 19, 19, 19, 18, 16],
|
||||
[14, 16, 80, 80, 19, 19, 19, 100, 100, 16],
|
||||
[13, 15, 80, 80, 18, 18, 18, 100, 100, 15],
|
||||
[11, 13, 15, 16, 16, 16, 16, 16, 15, 13]],
|
||||
dtype=np.uint8
|
||||
)
|
||||
expected = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.bool
|
||||
)
|
||||
for dtype in self.supported_dtypes:
|
||||
image = data.astype(dtype)
|
||||
result = extrema.local_maxima(image)
|
||||
assert result.dtype == np.bool
|
||||
assert_equal(result, expected)
|
||||
|
||||
def test_connectivity(self):
|
||||
"""Test results if selem is a scalar."""
|
||||
# Connectivity 1: generates cross shaped structuring element
|
||||
result_conn1 = extrema.local_maxima(self.image, connectivity=1)
|
||||
assert result_conn1.dtype == np.bool
|
||||
assert_equal(result_conn1, self.expected_cross)
|
||||
|
||||
# Connectivity 2: generates square shaped structuring element
|
||||
result_conn2 = extrema.local_maxima(self.image, connectivity=2)
|
||||
assert result_conn2.dtype == np.bool
|
||||
assert_equal(result_conn2, self.expected_default)
|
||||
|
||||
# Connectivity 3: generates square shaped structuring element
|
||||
result_conn3 = extrema.local_maxima(self.image, connectivity=3)
|
||||
assert result_conn3.dtype == np.bool
|
||||
assert_equal(result_conn3, self.expected_default)
|
||||
|
||||
def test_selem(self):
|
||||
"""Test results if selem is given."""
|
||||
selem_cross = np.array(
|
||||
[[0, 1, 0], [1, 1, 1], [0, 1, 0]], dtype=np.bool)
|
||||
result_selem_cross = extrema.local_maxima(
|
||||
self.image, selem=selem_cross)
|
||||
assert result_selem_cross.dtype == np.bool
|
||||
assert_equal(result_selem_cross, self.expected_cross)
|
||||
|
||||
for selem in [
|
||||
((True,) * 3,) * 3,
|
||||
np.ones((3, 3), dtype=np.float64),
|
||||
np.ones((3, 3), dtype=np.uint8),
|
||||
np.ones((3, 3), dtype=np.bool),
|
||||
]:
|
||||
# Test different dtypes for selem which expects a boolean array but
|
||||
# will accept and convert other types if possible
|
||||
result_selem_square = extrema.local_maxima(self.image, selem=selem)
|
||||
assert result_selem_square.dtype == np.bool
|
||||
assert_equal(result_selem_square, self.expected_default)
|
||||
|
||||
selem_x = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]], dtype=np.bool)
|
||||
expected_selem_x = np.array(
|
||||
[[1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0]],
|
||||
dtype=np.bool
|
||||
)
|
||||
result_selem_x = extrema.local_maxima(self.image, selem=selem_x)
|
||||
assert result_selem_x.dtype == np.bool
|
||||
assert_equal(result_selem_x, expected_selem_x)
|
||||
|
||||
def test_indices(self):
|
||||
"""Test output if indices of peaks are desired."""
|
||||
# Connectivity 1
|
||||
expected_conn1 = np.nonzero(self.expected_cross)
|
||||
result_conn1 = extrema.local_maxima(self.image, connectivity=1,
|
||||
indices=True)
|
||||
assert_equal(result_conn1, expected_conn1)
|
||||
|
||||
# Connectivity 2
|
||||
expected_conn2 = np.nonzero(self.expected_default)
|
||||
result_conn2 = extrema.local_maxima(self.image, connectivity=2,
|
||||
indices=True)
|
||||
assert_equal(result_conn2, expected_conn2)
|
||||
|
||||
def test_allow_borders(self):
|
||||
"""Test maxima detection at the image border."""
|
||||
# Use connectivity 1 to allow many maxima, only filtering at border is
|
||||
# of interest
|
||||
result_with_boder = extrema.local_maxima(
|
||||
self.image, connectivity=1, allow_borders=True)
|
||||
assert result_with_boder.dtype == np.bool
|
||||
assert_equal(result_with_boder, self.expected_cross)
|
||||
|
||||
expected_without_border = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0],
|
||||
[0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.bool
|
||||
)
|
||||
result_without_border = extrema.local_maxima(
|
||||
self.image, connectivity=1, allow_borders=False)
|
||||
assert result_with_boder.dtype == np.bool
|
||||
assert_equal(result_without_border, expected_without_border)
|
||||
|
||||
def test_nd(self):
|
||||
"""Test one- and three-dimensional case."""
|
||||
# One-dimension
|
||||
x_1d = np.array([1, 1, 0, 1, 2, 3, 0, 2, 1, 2, 0])
|
||||
expected_1d = np.array([1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0],
|
||||
dtype=np.bool)
|
||||
result_1d = extrema.local_maxima(x_1d)
|
||||
assert result_1d.dtype == np.bool
|
||||
assert_equal(result_1d, expected_1d)
|
||||
|
||||
# 3-dimensions (adapted from old unit test)
|
||||
x_3d = np.zeros((8, 8, 8), dtype=np.uint8)
|
||||
expected_3d = np.zeros((8, 8, 8), dtype=np.bool)
|
||||
# first maximum: only one pixel
|
||||
x_3d[1, 1:3, 1:3] = 100
|
||||
x_3d[2, 2, 2] = 200
|
||||
x_3d[3, 1:3, 1:3] = 100
|
||||
expected_3d[2, 2, 2] = 1
|
||||
# second maximum: three pixels in z-direction
|
||||
x_3d[5:8, 1, 1] = 200
|
||||
expected_3d[5:8, 1, 1] = 1
|
||||
# third: two maxima in 0 and 3.
|
||||
x_3d[0, 5:8, 5:8] = 200
|
||||
x_3d[1, 6, 6] = 100
|
||||
x_3d[2, 5:7, 5:7] = 200
|
||||
x_3d[0:3, 5:8, 5:8] += 50
|
||||
expected_3d[0, 5:8, 5:8] = 1
|
||||
expected_3d[2, 5:7, 5:7] = 1
|
||||
# four : one maximum in the corner of the square
|
||||
x_3d[6:8, 6:8, 6:8] = 200
|
||||
x_3d[7, 7, 7] = 255
|
||||
expected_3d[7, 7, 7] = 1
|
||||
result_3d = extrema.local_maxima(x_3d)
|
||||
assert result_3d.dtype == np.bool
|
||||
assert_equal(result_3d, expected_3d)
|
||||
|
||||
def test_constant(self):
|
||||
"""Test behaviour for 'flat' images."""
|
||||
const_image = np.full((7, 6), 42, dtype=np.uint8)
|
||||
expected = np.zeros((7, 6), dtype=np.uint8)
|
||||
for dtype in self.supported_dtypes:
|
||||
const_image = const_image.astype(dtype)
|
||||
# test for local maxima
|
||||
result = extrema.local_maxima(const_image)
|
||||
assert result.dtype == np.bool
|
||||
assert_equal(result, expected)
|
||||
# test for local minima
|
||||
result = extrema.local_minima(const_image)
|
||||
assert result.dtype == np.bool
|
||||
assert_equal(result, expected)
|
||||
|
||||
def test_extrema_float(self):
|
||||
"""Specific tests for float type."""
|
||||
# Copied from old unit test for local_maxma
|
||||
image = np.array(
|
||||
[[0.10, 0.11, 0.13, 0.14, 0.14, 0.15, 0.14, 0.14, 0.13, 0.11],
|
||||
[0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13],
|
||||
[0.13, 0.15, 0.40, 0.40, 0.18, 0.18, 0.18, 0.60, 0.60, 0.15],
|
||||
[0.14, 0.16, 0.40, 0.40, 0.19, 0.19, 0.19, 0.60, 0.60, 0.16],
|
||||
[0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16],
|
||||
[0.15, 0.182, 0.18, 0.19, 0.204, 0.20, 0.19, 0.19, 0.18, 0.16],
|
||||
[0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19, 0.19, 0.18, 0.16],
|
||||
[0.14, 0.16, 0.80, 0.80, 0.19, 0.19, 0.19, 1.0, 1.0, 0.16],
|
||||
[0.13, 0.15, 0.80, 0.80, 0.18, 0.18, 0.18, 1.0, 1.0, 0.15],
|
||||
[0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.13]],
|
||||
dtype=np.float32
|
||||
)
|
||||
inverted_image = 1.0 - image
|
||||
expected_result = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.bool
|
||||
)
|
||||
|
||||
# Test for local maxima with automatic step calculation
|
||||
result = extrema.local_maxima(image)
|
||||
assert result.dtype == np.bool
|
||||
assert_equal(result, expected_result)
|
||||
|
||||
# Test for local minima with automatic step calculation
|
||||
result = extrema.local_minima(inverted_image)
|
||||
assert result.dtype == np.bool
|
||||
assert_equal(result, expected_result)
|
||||
|
||||
def test_exceptions(self):
|
||||
"""Test if input validation triggers correct exceptions."""
|
||||
# Mismatching number of dimensions
|
||||
with raises(ValueError, match="number of dimensions"):
|
||||
extrema.local_maxima(
|
||||
self.image, selem=np.ones((3, 3, 3), dtype=np.bool))
|
||||
with raises(ValueError, match="number of dimensions"):
|
||||
extrema.local_maxima(
|
||||
self.image, selem=np.ones((3,), dtype=np.bool))
|
||||
|
||||
# All dimensions in selem must be of size 3
|
||||
with raises(ValueError, match="dimension size"):
|
||||
extrema.local_maxima(
|
||||
self.image, selem=np.ones((2, 3), dtype=np.bool))
|
||||
with raises(ValueError, match="dimension size"):
|
||||
extrema.local_maxima(
|
||||
self.image, selem=np.ones((5, 5), dtype=np.bool))
|
||||
|
||||
with raises(TypeError, match="float16 which is not supported"):
|
||||
extrema.local_maxima(np.empty(1, dtype=np.float16))
|
||||
|
||||
def test_small_array(self):
|
||||
"""Test output for arrays with dimension smaller 3.
|
||||
|
||||
If any dimension of an array is smaller than 3 and `allow_borders` is
|
||||
false a structuring element, which has at least 3 elements in each
|
||||
dimension, can't be applied. This is an implementation detail so
|
||||
`local_maxima` should still return valid output (see gh-3261).
|
||||
|
||||
If `allow_borders` is true the array is padded internally and there is
|
||||
no problem.
|
||||
"""
|
||||
warning_msg = "maxima can't exist .* any dimension smaller 3 .*"
|
||||
x = np.array([0, 1])
|
||||
extrema.local_maxima(x, allow_borders=True) # no warning
|
||||
with warns(UserWarning, match=warning_msg):
|
||||
result = extrema.local_maxima(x, allow_borders=False)
|
||||
assert_equal(result, [0, 0])
|
||||
assert result.dtype == np.bool
|
||||
|
||||
x = np.array([[1, 2], [2, 2]])
|
||||
extrema.local_maxima(x, allow_borders=True, indices=True) # no warning
|
||||
with warns(UserWarning, match=warning_msg):
|
||||
result = extrema.local_maxima(x, allow_borders=False, indices=True)
|
||||
assert_equal(result, np.zeros((2, 0), dtype=np.intp))
|
||||
assert result[0].dtype == np.intp
|
||||
assert result[1].dtype == np.intp
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
np.testing.run_module_suite()
|
|
@ -0,0 +1,279 @@
|
|||
import numpy as np
|
||||
import pytest
|
||||
from pytest import raises
|
||||
|
||||
from skimage.morphology import flood, flood_fill
|
||||
from skimage._shared.testing import expected_warnings
|
||||
|
||||
eps = 1e-12
|
||||
|
||||
|
||||
def test_empty_input():
|
||||
# Test shortcut
|
||||
output = flood_fill(np.empty(0), (), 2)
|
||||
assert output.size == 0
|
||||
|
||||
# Boolean output type
|
||||
assert flood(np.empty(0), ()).dtype == np.bool
|
||||
|
||||
# Maintain shape, even with zero size present
|
||||
assert flood(np.empty((20, 0, 4)), ()).shape == (20, 0, 4)
|
||||
|
||||
|
||||
def test_float16():
|
||||
image = np.array([9., 0.1, 42], dtype=np.float16)
|
||||
with raises(TypeError, match="dtype of `image` is float16"):
|
||||
flood_fill(image, 0, 1)
|
||||
|
||||
|
||||
def test_overrange_tolerance_int():
|
||||
image = np.arange(256, dtype=np.uint8).reshape((8, 8, 4))
|
||||
expected = np.zeros_like(image)
|
||||
|
||||
output = flood_fill(image, (7, 7, 3), 0, tolerance=379)
|
||||
|
||||
np.testing.assert_equal(output, expected)
|
||||
|
||||
|
||||
def test_overrange_tolerance_float():
|
||||
max_value = np.finfo(np.float32).max
|
||||
min_value = np.finfo(np.float32).min
|
||||
|
||||
image = np.random.uniform(size=(64, 64), low=-1., high=1.).astype(
|
||||
np.float32)
|
||||
image *= max_value
|
||||
|
||||
expected = np.ones_like(image)
|
||||
output = flood_fill(image, (0, 1), 1., tolerance=max_value * 10)
|
||||
|
||||
np.testing.assert_equal(output, expected)
|
||||
|
||||
|
||||
def test_inplace_int():
|
||||
image = np.array([[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[1, 0, 0, 0, 0, 0, 3],
|
||||
[0, 1, 1, 1, 3, 3, 4]])
|
||||
|
||||
flood_fill(image, (0, 0), 5, in_place=True)
|
||||
|
||||
expected = np.array([[5, 5, 5, 5, 5, 5, 5],
|
||||
[5, 1, 1, 5, 2, 2, 5],
|
||||
[5, 1, 1, 5, 2, 2, 5],
|
||||
[1, 5, 5, 5, 5, 5, 3],
|
||||
[5, 1, 1, 1, 3, 3, 4]])
|
||||
|
||||
np.testing.assert_array_equal(image, expected)
|
||||
|
||||
|
||||
def test_inplace_float():
|
||||
image = np.array([[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[1, 0, 0, 0, 0, 0, 3],
|
||||
[0, 1, 1, 1, 3, 3, 4]], dtype=np.float32)
|
||||
|
||||
flood_fill(image, (0, 0), 5, in_place=True)
|
||||
|
||||
expected = np.array([[5., 5., 5., 5., 5., 5., 5.],
|
||||
[5., 1., 1., 5., 2., 2., 5.],
|
||||
[5., 1., 1., 5., 2., 2., 5.],
|
||||
[1., 5., 5., 5., 5., 5., 3.],
|
||||
[5., 1., 1., 1., 3., 3., 4.]], dtype=np.float32)
|
||||
|
||||
np.testing.assert_allclose(image, expected)
|
||||
|
||||
|
||||
def test_inplace_noncontiguous():
|
||||
image = np.array([[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[1, 0, 0, 0, 0, 0, 3],
|
||||
[0, 1, 1, 1, 3, 3, 4]])
|
||||
|
||||
# Transpose is noncontiguous
|
||||
image2 = image[::2, ::2]
|
||||
|
||||
flood_fill(image2, (0, 0), 5, in_place=True)
|
||||
|
||||
# The inplace modified result
|
||||
expected2 = np.array([[5, 5, 5, 5],
|
||||
[5, 1, 2, 5],
|
||||
[5, 1, 3, 4]])
|
||||
|
||||
np.testing.assert_allclose(image2, expected2)
|
||||
|
||||
# Projected back through the view, `image` also modified
|
||||
expected = np.array([[5, 0, 5, 0, 5, 0, 5],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[5, 1, 1, 0, 2, 2, 5],
|
||||
[1, 0, 0, 0, 0, 0, 3],
|
||||
[5, 1, 1, 1, 3, 3, 4]])
|
||||
|
||||
np.testing.assert_allclose(image, expected)
|
||||
|
||||
|
||||
def test_inplace_int_deprecated():
|
||||
"""This test is deprecated and will be removed in
|
||||
version 0.19.0. See #4248.
|
||||
"""
|
||||
image = np.array([[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[1, 0, 0, 0, 0, 0, 3],
|
||||
[0, 1, 1, 1, 3, 3, 4]])
|
||||
|
||||
with expected_warnings(['The `inplace`']):
|
||||
flood_fill(image, (0, 0), 5, inplace=True)
|
||||
|
||||
expected = np.array([[5, 5, 5, 5, 5, 5, 5],
|
||||
[5, 1, 1, 5, 2, 2, 5],
|
||||
[5, 1, 1, 5, 2, 2, 5],
|
||||
[1, 5, 5, 5, 5, 5, 3],
|
||||
[5, 1, 1, 1, 3, 3, 4]])
|
||||
|
||||
np.testing.assert_array_equal(image, expected)
|
||||
|
||||
|
||||
def test_inplace_float_deprecated():
|
||||
"""This test is deprecated and will be removed in
|
||||
version 0.19.0. See #4248.
|
||||
"""
|
||||
image = np.array([[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[0, 1, 1, 0, 2, 2, 0],
|
||||
[1, 0, 0, 0, 0, 0, 3],
|
||||
[0, 1, 1, 1, 3, 3, 4]], dtype=np.float32)
|
||||
|
||||
with expected_warnings(['The `inplace`']):
|
||||
flood_fill(image, (0, 0), 5, inplace=True)
|
||||
|
||||
expected = np.array([[5., 5., 5., 5., 5., 5., 5.],
|
||||
[5., 1., 1., 5., 2., 2., 5.],
|
||||
[5., 1., 1., 5., 2., 2., 5.],
|
||||
[1., 5., 5., 5., 5., 5., 3.],
|
||||
[5., 1., 1., 1., 3., 3., 4.]], dtype=np.float32)
|
||||
|
||||
np.testing.assert_allclose(image, expected)
|
||||
|
||||
|
||||
def test_1d():
|
||||
image = np.arange(11)
|
||||
expected = np.array([0, 1, -20, -20, -20, -20, -20, -20, -20, 9, 10])
|
||||
|
||||
output = flood_fill(image, 5, -20, tolerance=3)
|
||||
output2 = flood_fill(image, (5,), -20, tolerance=3)
|
||||
|
||||
np.testing.assert_equal(output, expected)
|
||||
np.testing.assert_equal(output, output2)
|
||||
|
||||
|
||||
def test_wraparound():
|
||||
# If the borders (or neighbors) aren't correctly accounted for, this fails,
|
||||
# because the algorithm uses an ravelled array.
|
||||
test = np.zeros((5, 7), dtype=np.float64)
|
||||
test[:, 3] = 100
|
||||
|
||||
expected = np.array([[-1., -1., -1., 100., 0., 0., 0.],
|
||||
[-1., -1., -1., 100., 0., 0., 0.],
|
||||
[-1., -1., -1., 100., 0., 0., 0.],
|
||||
[-1., -1., -1., 100., 0., 0., 0.],
|
||||
[-1., -1., -1., 100., 0., 0., 0.]])
|
||||
|
||||
np.testing.assert_equal(flood_fill(test, (0, 0), -1), expected)
|
||||
|
||||
|
||||
def test_neighbors():
|
||||
# This test will only pass if the neighbors are exactly correct
|
||||
test = np.zeros((5, 7), dtype=np.float64)
|
||||
test[:, 3] = 100
|
||||
|
||||
expected = np.array([[0, 0, 0, 255, 0, 0, 0],
|
||||
[0, 0, 0, 255, 0, 0, 0],
|
||||
[0, 0, 0, 255, 0, 0, 0],
|
||||
[0, 0, 0, 255, 0, 0, 0],
|
||||
[0, 0, 0, 255, 0, 0, 0]])
|
||||
output = flood_fill(test, (0, 3), 255)
|
||||
|
||||
np.testing.assert_equal(output, expected)
|
||||
|
||||
test[2] = 100
|
||||
expected[2] = 255
|
||||
|
||||
output2 = flood_fill(test, (2, 3), 255)
|
||||
|
||||
np.testing.assert_equal(output2, expected)
|
||||
|
||||
|
||||
def test_selem():
|
||||
# Basic tests for nonstandard structuring elements
|
||||
selem = np.array([[0, 1, 1],
|
||||
[0, 1, 1],
|
||||
[0, 0, 0]]) # Cannot grow left or down
|
||||
|
||||
output = flood_fill(np.zeros((5, 6), dtype=np.uint8), (3, 1), 255,
|
||||
selem=selem)
|
||||
|
||||
expected = np.array([[0, 255, 255, 255, 255, 255],
|
||||
[0, 255, 255, 255, 255, 255],
|
||||
[0, 255, 255, 255, 255, 255],
|
||||
[0, 255, 255, 255, 255, 255],
|
||||
[0, 0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
|
||||
np.testing.assert_equal(output, expected)
|
||||
|
||||
selem = np.array([[0, 0, 0],
|
||||
[1, 1, 0],
|
||||
[1, 1, 0]]) # Cannot grow right or up
|
||||
|
||||
output = flood_fill(np.zeros((5, 6), dtype=np.uint8), (1, 4), 255,
|
||||
selem=selem)
|
||||
|
||||
expected = np.array([[ 0, 0, 0, 0, 0, 0],
|
||||
[255, 255, 255, 255, 255, 0],
|
||||
[255, 255, 255, 255, 255, 0],
|
||||
[255, 255, 255, 255, 255, 0],
|
||||
[255, 255, 255, 255, 255, 0]], dtype=np.uint8)
|
||||
|
||||
np.testing.assert_equal(output, expected)
|
||||
|
||||
|
||||
def test_basic_nd():
|
||||
for dimension in (3, 4, 5):
|
||||
shape = (5,) * dimension
|
||||
hypercube = np.zeros(shape)
|
||||
slice_mid = tuple(slice(1, -1, None) for dim in range(dimension))
|
||||
hypercube[slice_mid] = 1 # sum is 3**dimension
|
||||
filled = flood_fill(hypercube, (2,)*dimension, 2)
|
||||
|
||||
# Test that the middle sum is correct
|
||||
assert filled.sum() == 3**dimension * 2
|
||||
|
||||
# Test that the entire array is as expected
|
||||
np.testing.assert_equal(
|
||||
filled, np.pad(np.ones((3,)*dimension) * 2, 1, 'constant'))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tolerance", [None, 0])
|
||||
def test_f_order(tolerance):
|
||||
image = np.array([
|
||||
[0, 0, 0, 0],
|
||||
[1, 0, 0, 0],
|
||||
[0, 1, 0, 0],
|
||||
], order="F")
|
||||
expected = np.array([
|
||||
[0, 0, 0, 0],
|
||||
[1, 0, 0, 0],
|
||||
[0, 1, 0, 0],
|
||||
], dtype=bool)
|
||||
|
||||
mask = flood(image, seed_point=(1, 0), tolerance=tolerance)
|
||||
np.testing.assert_array_equal(expected, mask)
|
||||
|
||||
mask = flood(image, seed_point=(2, 1), tolerance=tolerance)
|
||||
np.testing.assert_array_equal(expected, mask)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
np.testing.run_module_suite()
|
276
venv/Lib/site-packages/skimage/morphology/tests/test_grey.py
Normal file
276
venv/Lib/site-packages/skimage/morphology/tests/test_grey.py
Normal file
|
@ -0,0 +1,276 @@
|
|||
import numpy as np
|
||||
from scipy import ndimage as ndi
|
||||
|
||||
from skimage import color, data, transform
|
||||
from skimage.util import img_as_uint, img_as_ubyte
|
||||
from skimage.morphology import grey, selem
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import (assert_array_equal, assert_equal,
|
||||
TestCase, parametrize, fetch)
|
||||
|
||||
|
||||
class TestMorphology(TestCase):
|
||||
|
||||
# These expected outputs were generated with skimage v0.12.1
|
||||
# using:
|
||||
#
|
||||
# from skimage.morphology.tests.test_grey import TestMorphology
|
||||
# import numpy as np
|
||||
# output = TestMorphology()._build_expected_output()
|
||||
# np.savez_compressed('gray_morph_output.npz', **output)
|
||||
|
||||
def _build_expected_output(self):
|
||||
funcs = (grey.erosion, grey.dilation, grey.opening, grey.closing,
|
||||
grey.white_tophat, grey.black_tophat)
|
||||
selems_2D = (selem.square, selem.diamond,
|
||||
selem.disk, selem.star)
|
||||
|
||||
image = img_as_ubyte(transform.downscale_local_mean(
|
||||
color.rgb2gray(data.coffee()), (20, 20)))
|
||||
|
||||
output = {}
|
||||
for n in range(1, 4):
|
||||
for strel in selems_2D:
|
||||
for func in funcs:
|
||||
key = '{0}_{1}_{2}'.format(
|
||||
strel.__name__, n, func.__name__)
|
||||
output[key] = func(image, strel(n))
|
||||
|
||||
return output
|
||||
|
||||
def test_gray_morphology(self):
|
||||
expected = dict(np.load(fetch('data/gray_morph_output.npz')))
|
||||
calculated = self._build_expected_output()
|
||||
assert_equal(expected, calculated)
|
||||
|
||||
|
||||
class TestEccentricStructuringElements(TestCase):
|
||||
def setUp(self):
|
||||
self.black_pixel = 255 * np.ones((4, 4), dtype=np.uint8)
|
||||
self.black_pixel[1, 1] = 0
|
||||
self.white_pixel = 255 - self.black_pixel
|
||||
self.selems = [selem.square(2), selem.rectangle(2, 2),
|
||||
selem.rectangle(2, 1), selem.rectangle(1, 2)]
|
||||
|
||||
def test_dilate_erode_symmetry(self):
|
||||
for s in self.selems:
|
||||
c = grey.erosion(self.black_pixel, s)
|
||||
d = grey.dilation(self.white_pixel, s)
|
||||
assert np.all(c == (255 - d))
|
||||
|
||||
def test_open_black_pixel(self):
|
||||
for s in self.selems:
|
||||
grey_open = grey.opening(self.black_pixel, s)
|
||||
assert np.all(grey_open == self.black_pixel)
|
||||
|
||||
def test_close_white_pixel(self):
|
||||
for s in self.selems:
|
||||
grey_close = grey.closing(self.white_pixel, s)
|
||||
assert np.all(grey_close == self.white_pixel)
|
||||
|
||||
def test_open_white_pixel(self):
|
||||
for s in self.selems:
|
||||
assert np.all(grey.opening(self.white_pixel, s) == 0)
|
||||
|
||||
def test_close_black_pixel(self):
|
||||
for s in self.selems:
|
||||
assert np.all(grey.closing(self.black_pixel, s) == 255)
|
||||
|
||||
def test_white_tophat_white_pixel(self):
|
||||
for s in self.selems:
|
||||
tophat = grey.white_tophat(self.white_pixel, s)
|
||||
assert np.all(tophat == self.white_pixel)
|
||||
|
||||
def test_black_tophat_black_pixel(self):
|
||||
for s in self.selems:
|
||||
tophat = grey.black_tophat(self.black_pixel, s)
|
||||
assert np.all(tophat == (255 - self.black_pixel))
|
||||
|
||||
def test_white_tophat_black_pixel(self):
|
||||
for s in self.selems:
|
||||
tophat = grey.white_tophat(self.black_pixel, s)
|
||||
assert np.all(tophat == 0)
|
||||
|
||||
def test_black_tophat_white_pixel(self):
|
||||
for s in self.selems:
|
||||
tophat = grey.black_tophat(self.white_pixel, s)
|
||||
assert np.all(tophat == 0)
|
||||
|
||||
|
||||
grey_functions = [grey.erosion, grey.dilation,
|
||||
grey.opening, grey.closing,
|
||||
grey.white_tophat, grey.black_tophat]
|
||||
|
||||
|
||||
@parametrize("function", grey_functions)
|
||||
def test_default_selem(function):
|
||||
strel = selem.diamond(radius=1)
|
||||
image = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], np.uint8)
|
||||
im_expected = function(image, strel)
|
||||
im_test = function(image)
|
||||
testing.assert_array_equal(im_expected, im_test)
|
||||
|
||||
|
||||
def test_3d_fallback_default_selem():
|
||||
# 3x3x3 cube inside a 7x7x7 image:
|
||||
image = np.zeros((7, 7, 7), np.bool)
|
||||
image[2:-2, 2:-2, 2:-2] = 1
|
||||
|
||||
opened = grey.opening(image)
|
||||
|
||||
# expect a "hyper-cross" centered in the 5x5x5:
|
||||
image_expected = np.zeros((7, 7, 7), dtype=bool)
|
||||
image_expected[2:5, 2:5, 2:5] = ndi.generate_binary_structure(3, 1)
|
||||
assert_array_equal(opened, image_expected)
|
||||
|
||||
|
||||
grey_3d_fallback_functions = [grey.closing, grey.opening]
|
||||
|
||||
|
||||
@parametrize("function", grey_3d_fallback_functions)
|
||||
def test_3d_fallback_cube_selem(function):
|
||||
# 3x3x3 cube inside a 7x7x7 image:
|
||||
image = np.zeros((7, 7, 7), np.bool)
|
||||
image[2:-2, 2:-2, 2:-2] = 1
|
||||
|
||||
cube = np.ones((3, 3, 3), dtype=np.uint8)
|
||||
|
||||
new_image = function(image, cube)
|
||||
testing.assert_array_equal(new_image, image)
|
||||
|
||||
|
||||
def test_3d_fallback_white_tophat():
|
||||
image = np.zeros((7, 7, 7), dtype=bool)
|
||||
image[2, 2:4, 2:4] = 1
|
||||
image[3, 2:5, 2:5] = 1
|
||||
image[4, 3:5, 3:5] = 1
|
||||
|
||||
with expected_warnings([r'operator.*deprecated|\A\Z']):
|
||||
new_image = grey.white_tophat(image)
|
||||
footprint = ndi.generate_binary_structure(3, 1)
|
||||
with expected_warnings([r'operator.*deprecated|\A\Z']):
|
||||
image_expected = ndi.white_tophat(
|
||||
image.view(dtype=np.uint8), footprint=footprint)
|
||||
assert_array_equal(new_image, image_expected)
|
||||
|
||||
|
||||
def test_3d_fallback_black_tophat():
|
||||
image = np.ones((7, 7, 7), dtype=bool)
|
||||
image[2, 2:4, 2:4] = 0
|
||||
image[3, 2:5, 2:5] = 0
|
||||
image[4, 3:5, 3:5] = 0
|
||||
|
||||
with expected_warnings([r'operator.*deprecated|\A\Z']):
|
||||
new_image = grey.black_tophat(image)
|
||||
footprint = ndi.generate_binary_structure(3, 1)
|
||||
with expected_warnings([r'operator.*deprecated|\A\Z']):
|
||||
image_expected = ndi.black_tophat(
|
||||
image.view(dtype=np.uint8), footprint=footprint)
|
||||
assert_array_equal(new_image, image_expected)
|
||||
|
||||
|
||||
def test_2d_ndimage_equivalence():
|
||||
image = np.zeros((9, 9), np.uint8)
|
||||
image[2:-2, 2:-2] = 128
|
||||
image[3:-3, 3:-3] = 196
|
||||
image[4, 4] = 255
|
||||
|
||||
opened = grey.opening(image)
|
||||
closed = grey.closing(image)
|
||||
|
||||
selem = ndi.generate_binary_structure(2, 1)
|
||||
ndimage_opened = ndi.grey_opening(image, footprint=selem)
|
||||
ndimage_closed = ndi.grey_closing(image, footprint=selem)
|
||||
|
||||
assert_array_equal(opened, ndimage_opened)
|
||||
assert_array_equal(closed, ndimage_closed)
|
||||
|
||||
|
||||
# float test images
|
||||
im = np.array([[ 0.55, 0.72, 0.6 , 0.54, 0.42],
|
||||
[ 0.65, 0.44, 0.89, 0.96, 0.38],
|
||||
[ 0.79, 0.53, 0.57, 0.93, 0.07],
|
||||
[ 0.09, 0.02, 0.83, 0.78, 0.87],
|
||||
[ 0.98, 0.8 , 0.46, 0.78, 0.12]])
|
||||
|
||||
eroded = np.array([[ 0.55, 0.44, 0.54, 0.42, 0.38],
|
||||
[ 0.44, 0.44, 0.44, 0.38, 0.07],
|
||||
[ 0.09, 0.02, 0.53, 0.07, 0.07],
|
||||
[ 0.02, 0.02, 0.02, 0.78, 0.07],
|
||||
[ 0.09, 0.02, 0.46, 0.12, 0.12]])
|
||||
|
||||
dilated = np.array([[ 0.72, 0.72, 0.89, 0.96, 0.54],
|
||||
[ 0.79, 0.89, 0.96, 0.96, 0.96],
|
||||
[ 0.79, 0.79, 0.93, 0.96, 0.93],
|
||||
[ 0.98, 0.83, 0.83, 0.93, 0.87],
|
||||
[ 0.98, 0.98, 0.83, 0.78, 0.87]])
|
||||
|
||||
opened = np.array([[ 0.55, 0.55, 0.54, 0.54, 0.42],
|
||||
[ 0.55, 0.44, 0.54, 0.44, 0.38],
|
||||
[ 0.44, 0.53, 0.53, 0.78, 0.07],
|
||||
[ 0.09, 0.02, 0.78, 0.78, 0.78],
|
||||
[ 0.09, 0.46, 0.46, 0.78, 0.12]])
|
||||
|
||||
closed = np.array([[ 0.72, 0.72, 0.72, 0.54, 0.54],
|
||||
[ 0.72, 0.72, 0.89, 0.96, 0.54],
|
||||
[ 0.79, 0.79, 0.79, 0.93, 0.87],
|
||||
[ 0.79, 0.79, 0.83, 0.78, 0.87],
|
||||
[ 0.98, 0.83, 0.78, 0.78, 0.78]])
|
||||
|
||||
|
||||
def test_float():
|
||||
np.testing.assert_allclose(grey.erosion(im), eroded)
|
||||
np.testing.assert_allclose(grey.dilation(im), dilated)
|
||||
np.testing.assert_allclose(grey.opening(im), opened)
|
||||
np.testing.assert_allclose(grey.closing(im), closed)
|
||||
|
||||
|
||||
def test_uint16():
|
||||
im16, eroded16, dilated16, opened16, closed16 = (
|
||||
map(img_as_uint, [im, eroded, dilated, opened, closed]))
|
||||
np.testing.assert_allclose(grey.erosion(im16), eroded16)
|
||||
np.testing.assert_allclose(grey.dilation(im16), dilated16)
|
||||
np.testing.assert_allclose(grey.opening(im16), opened16)
|
||||
np.testing.assert_allclose(grey.closing(im16), closed16)
|
||||
|
||||
|
||||
def test_discontiguous_out_array():
|
||||
image = np.array([[5, 6, 2],
|
||||
[7, 2, 2],
|
||||
[3, 5, 1]], np.uint8)
|
||||
out_array_big = np.zeros((5, 5), np.uint8)
|
||||
out_array = out_array_big[::2, ::2]
|
||||
expected_dilation = np.array([[7, 0, 6, 0, 6],
|
||||
[0, 0, 0, 0, 0],
|
||||
[7, 0, 7, 0, 2],
|
||||
[0, 0, 0, 0, 0],
|
||||
[7, 0, 5, 0, 5]], np.uint8)
|
||||
expected_erosion = np.array([[5, 0, 2, 0, 2],
|
||||
[0, 0, 0, 0, 0],
|
||||
[2, 0, 2, 0, 1],
|
||||
[0, 0, 0, 0, 0],
|
||||
[3, 0, 1, 0, 1]], np.uint8)
|
||||
grey.dilation(image, out=out_array)
|
||||
assert_array_equal(out_array_big, expected_dilation)
|
||||
grey.erosion(image, out=out_array)
|
||||
testing.assert_array_equal(out_array_big, expected_erosion)
|
||||
|
||||
|
||||
def test_1d_erosion():
|
||||
image = np.array([1, 2, 3, 2, 1])
|
||||
expected = np.array([1, 1, 2, 1, 1])
|
||||
eroded = grey.erosion(image)
|
||||
testing.assert_array_equal(eroded, expected)
|
457
venv/Lib/site-packages/skimage/morphology/tests/test_max_tree.py
Normal file
457
venv/Lib/site-packages/skimage/morphology/tests/test_max_tree.py
Normal file
|
@ -0,0 +1,457 @@
|
|||
import numpy as np
|
||||
from skimage.morphology import max_tree, area_closing, area_opening
|
||||
from skimage.morphology import max_tree_local_maxima, diameter_opening
|
||||
from skimage.morphology import diameter_closing
|
||||
from skimage.util import invert
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_array_equal, TestCase
|
||||
|
||||
eps = 1e-12
|
||||
|
||||
|
||||
def _full_type_test(img, param, expected, func, param_scale=False,
|
||||
**keywords):
|
||||
|
||||
# images as they are
|
||||
out = func(img, param, **keywords)
|
||||
assert_array_equal(out, expected)
|
||||
|
||||
# unsigned int
|
||||
for dt in [np.uint32, np.uint64]:
|
||||
img_cast = img.astype(dt)
|
||||
out = func(img_cast, param, **keywords)
|
||||
exp_cast = expected.astype(dt)
|
||||
assert_array_equal(out, exp_cast)
|
||||
|
||||
# float
|
||||
data_float = img.astype(np.float64)
|
||||
data_float = data_float / 255.0
|
||||
expected_float = expected.astype(np.float64)
|
||||
expected_float = expected_float / 255.0
|
||||
if param_scale:
|
||||
param_cast = param / 255.0
|
||||
else:
|
||||
param_cast = param
|
||||
for dt in [np.float32, np.float64]:
|
||||
data_cast = data_float.astype(dt)
|
||||
out = func(data_cast, param_cast, **keywords)
|
||||
exp_cast = expected_float.astype(dt)
|
||||
error_img = 255.0 * exp_cast - 255.0 * out
|
||||
error = (error_img >= 1.0).sum()
|
||||
assert error < eps
|
||||
|
||||
# signed images
|
||||
img_signed = img.astype(np.int16)
|
||||
img_signed = img_signed - 128
|
||||
exp_signed = expected.astype(np.int16)
|
||||
exp_signed = exp_signed - 128
|
||||
for dt in [np.int8, np.int16, np.int32, np.int64]:
|
||||
img_s = img_signed.astype(dt)
|
||||
out = func(img_s, param, **keywords)
|
||||
exp_s = exp_signed.astype(dt)
|
||||
assert_array_equal(out, exp_s)
|
||||
|
||||
|
||||
class TestMaxtree(TestCase):
|
||||
|
||||
def test_max_tree(self):
|
||||
"Test for max tree"
|
||||
img_type = np.uint8
|
||||
img = np.array([[10, 8, 8, 9],
|
||||
[7, 7, 9, 9],
|
||||
[8, 7, 10, 10],
|
||||
[9, 9, 10, 10]], dtype=img_type)
|
||||
|
||||
P_exp = np.array([[1, 4, 1, 1],
|
||||
[4, 4, 3, 3],
|
||||
[1, 4, 3, 10],
|
||||
[3, 3, 10, 10]], dtype=np.int64)
|
||||
|
||||
S_exp = np.array([4, 5, 9, 1, 2, 8, 3, 6, 7,
|
||||
12, 13, 0, 10, 11, 14, 15],
|
||||
dtype=np.int64)
|
||||
|
||||
for img_type in [np.uint8, np.uint16, np.uint32, np.uint64]:
|
||||
img = img.astype(img_type)
|
||||
P, S = max_tree(img, connectivity=2)
|
||||
assert_array_equal(P, P_exp)
|
||||
assert_array_equal(S, S_exp)
|
||||
|
||||
for img_type in [np.int8, np.int16, np.int32, np.int64]:
|
||||
img = img.astype(img_type)
|
||||
img_shifted = img - 9
|
||||
P, S = max_tree(img_shifted, connectivity=2)
|
||||
assert_array_equal(P, P_exp)
|
||||
assert_array_equal(S, S_exp)
|
||||
|
||||
img_float = img.astype(np.float)
|
||||
img_float = (img_float - 8) / 2.0
|
||||
for img_type in [np.float32, np.float64]:
|
||||
img_float = img_float.astype(img_type)
|
||||
P, S = max_tree(img_float, connectivity=2)
|
||||
assert_array_equal(P, P_exp)
|
||||
assert_array_equal(S, S_exp)
|
||||
|
||||
return
|
||||
|
||||
def test_area_closing(self):
|
||||
"Test for Area Closing (2 thresholds, all types)"
|
||||
|
||||
# original image
|
||||
img = np.array(
|
||||
[[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240],
|
||||
[240, 200, 200, 240, 200, 240, 200, 200, 240, 240, 200, 240],
|
||||
[240, 200, 40, 240, 240, 240, 240, 240, 240, 240, 40, 240],
|
||||
[240, 240, 240, 240, 100, 240, 100, 100, 240, 240, 200, 240],
|
||||
[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240],
|
||||
[200, 200, 200, 200, 200, 200, 200, 240, 200, 200, 255, 255],
|
||||
[200, 255, 200, 200, 200, 255, 200, 240, 255, 255, 255, 40],
|
||||
[200, 200, 200, 100, 200, 200, 200, 240, 255, 255, 255, 255],
|
||||
[200, 200, 200, 100, 200, 200, 200, 240, 200, 200, 255, 255],
|
||||
[200, 200, 200, 200, 200, 40, 200, 240, 240, 100, 255, 255],
|
||||
[200, 40, 255, 255, 255, 40, 200, 255, 200, 200, 255, 255],
|
||||
[200, 200, 200, 200, 200, 200, 200, 255, 255, 255, 255, 255]],
|
||||
dtype=np.uint8)
|
||||
|
||||
# expected area closing with area 2
|
||||
expected_2 = np.array(
|
||||
[[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240],
|
||||
[240, 200, 200, 240, 240, 240, 200, 200, 240, 240, 200, 240],
|
||||
[240, 200, 200, 240, 240, 240, 240, 240, 240, 240, 200, 240],
|
||||
[240, 240, 240, 240, 240, 240, 100, 100, 240, 240, 200, 240],
|
||||
[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240],
|
||||
[200, 200, 200, 200, 200, 200, 200, 240, 200, 200, 255, 255],
|
||||
[200, 255, 200, 200, 200, 255, 200, 240, 255, 255, 255, 255],
|
||||
[200, 200, 200, 100, 200, 200, 200, 240, 255, 255, 255, 255],
|
||||
[200, 200, 200, 100, 200, 200, 200, 240, 200, 200, 255, 255],
|
||||
[200, 200, 200, 200, 200, 40, 200, 240, 240, 200, 255, 255],
|
||||
[200, 200, 255, 255, 255, 40, 200, 255, 200, 200, 255, 255],
|
||||
[200, 200, 200, 200, 200, 200, 200, 255, 255, 255, 255, 255]],
|
||||
dtype=np.uint8)
|
||||
|
||||
# expected diameter closing with diameter 4
|
||||
expected_4 = np.array(
|
||||
[[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240],
|
||||
[240, 200, 200, 240, 240, 240, 240, 240, 240, 240, 240, 240],
|
||||
[240, 200, 200, 240, 240, 240, 240, 240, 240, 240, 240, 240],
|
||||
[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240],
|
||||
[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240],
|
||||
[200, 200, 200, 200, 200, 200, 200, 240, 240, 240, 255, 255],
|
||||
[200, 255, 200, 200, 200, 255, 200, 240, 255, 255, 255, 255],
|
||||
[200, 200, 200, 200, 200, 200, 200, 240, 255, 255, 255, 255],
|
||||
[200, 200, 200, 200, 200, 200, 200, 240, 200, 200, 255, 255],
|
||||
[200, 200, 200, 200, 200, 200, 200, 240, 240, 200, 255, 255],
|
||||
[200, 200, 255, 255, 255, 200, 200, 255, 200, 200, 255, 255],
|
||||
[200, 200, 200, 200, 200, 200, 200, 255, 255, 255, 255, 255]],
|
||||
dtype=np.uint8)
|
||||
|
||||
# _full_type_test makes a test with many image types.
|
||||
_full_type_test(img, 2, expected_2, area_closing, connectivity=2)
|
||||
_full_type_test(img, 4, expected_4, area_closing, connectivity=2)
|
||||
|
||||
P, S = max_tree(invert(img), connectivity=2)
|
||||
_full_type_test(img, 4, expected_4, area_closing,
|
||||
parent=P, tree_traverser=S)
|
||||
|
||||
def test_area_opening(self):
|
||||
"Test for Area Opening (2 thresholds, all types)"
|
||||
|
||||
# original image
|
||||
img = np.array([[15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15],
|
||||
[15, 55, 55, 15, 55, 15, 55, 55, 15, 15, 55, 15],
|
||||
[15, 55, 215, 15, 15, 15, 15, 15, 15, 15, 215, 15],
|
||||
[15, 15, 15, 15, 155, 15, 155, 155, 15, 15, 55, 15],
|
||||
[15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15],
|
||||
[55, 55, 55, 55, 55, 55, 55, 15, 55, 55, 0, 0],
|
||||
[55, 0, 55, 55, 55, 0, 55, 15, 0, 0, 0, 215],
|
||||
[55, 55, 55, 155, 55, 55, 55, 15, 0, 0, 0, 0],
|
||||
[55, 55, 55, 155, 55, 55, 55, 15, 55, 55, 0, 0],
|
||||
[55, 55, 55, 55, 55, 215, 55, 15, 15, 155, 0, 0],
|
||||
[55, 215, 0, 0, 0, 215, 55, 0, 55, 55, 0, 0],
|
||||
[55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
|
||||
# expected area closing with area 2
|
||||
expected_2 = np.array([[15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15],
|
||||
[15, 55, 55, 15, 15, 15, 55, 55, 15,
|
||||
15, 55, 15],
|
||||
[15, 55, 55, 15, 15, 15, 15, 15, 15,
|
||||
15, 55, 15],
|
||||
[15, 15, 15, 15, 15, 15, 155, 155, 15,
|
||||
15, 55, 15],
|
||||
[15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15],
|
||||
[55, 55, 55, 55, 55, 55, 55, 15, 55,
|
||||
55, 0, 0],
|
||||
[55, 0, 55, 55, 55, 0, 55, 15, 0,
|
||||
0, 0, 0],
|
||||
[55, 55, 55, 155, 55, 55, 55, 15, 0,
|
||||
0, 0, 0],
|
||||
[55, 55, 55, 155, 55, 55, 55, 15, 55,
|
||||
55, 0, 0],
|
||||
[55, 55, 55, 55, 55, 215, 55, 15, 15,
|
||||
55, 0, 0],
|
||||
[55, 55, 0, 0, 0, 215, 55, 0, 55,
|
||||
55, 0, 0],
|
||||
[55, 55, 55, 55, 55, 55, 55, 0, 0,
|
||||
0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
|
||||
# expected diameter closing with diameter 4
|
||||
expected_4 = np.array([[15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15],
|
||||
[15, 55, 55, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15],
|
||||
[15, 55, 55, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15],
|
||||
[15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15],
|
||||
[15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15],
|
||||
[55, 55, 55, 55, 55, 55, 55, 15, 15,
|
||||
15, 0, 0],
|
||||
[55, 0, 55, 55, 55, 0, 55, 15, 0,
|
||||
0, 0, 0],
|
||||
[55, 55, 55, 55, 55, 55, 55, 15, 0,
|
||||
0, 0, 0],
|
||||
[55, 55, 55, 55, 55, 55, 55, 15, 55,
|
||||
55, 0, 0],
|
||||
[55, 55, 55, 55, 55, 55, 55, 15, 15,
|
||||
55, 0, 0],
|
||||
[55, 55, 0, 0, 0, 55, 55, 0, 55,
|
||||
55, 0, 0],
|
||||
[55, 55, 55, 55, 55, 55, 55, 0, 0,
|
||||
0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
|
||||
# _full_type_test makes a test with many image types.
|
||||
_full_type_test(img, 2, expected_2, area_opening, connectivity=2)
|
||||
_full_type_test(img, 4, expected_4, area_opening, connectivity=2)
|
||||
|
||||
P, S = max_tree(img, connectivity=2)
|
||||
_full_type_test(img, 4, expected_4, area_opening,
|
||||
parent=P, tree_traverser=S)
|
||||
|
||||
def test_diameter_closing(self):
|
||||
"Test for Diameter Opening (2 thresholds, all types)"
|
||||
img = np.array([[97, 95, 93, 92, 91, 90, 90, 90, 91, 92, 93, 95],
|
||||
[95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93],
|
||||
[93, 63, 63, 63, 63, 86, 86, 86, 87, 43, 43, 91],
|
||||
[92, 89, 88, 86, 85, 85, 84, 85, 85, 43, 43, 89],
|
||||
[91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88],
|
||||
[90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88],
|
||||
[90, 88, 86, 84, 83, 83, 82, 83, 83, 84, 86, 88],
|
||||
[90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88],
|
||||
[91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88],
|
||||
[92, 89, 23, 23, 85, 85, 84, 85, 85, 3, 3, 89],
|
||||
[93, 91, 23, 23, 87, 86, 86, 86, 87, 88, 3, 91],
|
||||
[95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93]],
|
||||
dtype=np.uint8)
|
||||
|
||||
ex2 = np.array([[97, 95, 93, 92, 91, 90, 90, 90, 91, 92, 93, 95],
|
||||
[95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93],
|
||||
[93, 63, 63, 63, 63, 86, 86, 86, 87, 43, 43, 91],
|
||||
[92, 89, 88, 86, 85, 85, 84, 85, 85, 43, 43, 89],
|
||||
[91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88],
|
||||
[90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88],
|
||||
[90, 88, 86, 84, 83, 83, 83, 83, 83, 84, 86, 88],
|
||||
[90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88],
|
||||
[91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88],
|
||||
[92, 89, 23, 23, 85, 85, 84, 85, 85, 3, 3, 89],
|
||||
[93, 91, 23, 23, 87, 86, 86, 86, 87, 88, 3, 91],
|
||||
[95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93]],
|
||||
dtype=np.uint8)
|
||||
|
||||
ex4 = np.array([[97, 95, 93, 92, 91, 90, 90, 90, 91, 92, 93, 95],
|
||||
[95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93],
|
||||
[93, 63, 63, 63, 63, 86, 86, 86, 87, 84, 84, 91],
|
||||
[92, 89, 88, 86, 85, 85, 84, 85, 85, 84, 84, 89],
|
||||
[91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88],
|
||||
[90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88],
|
||||
[90, 88, 86, 84, 83, 83, 83, 83, 83, 84, 86, 88],
|
||||
[90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88],
|
||||
[91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88],
|
||||
[92, 89, 84, 84, 85, 85, 84, 85, 85, 84, 84, 89],
|
||||
[93, 91, 84, 84, 87, 86, 86, 86, 87, 88, 84, 91],
|
||||
[95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93]],
|
||||
dtype=np.uint8)
|
||||
|
||||
# _full_type_test makes a test with many image types.
|
||||
_full_type_test(img, 2, ex2, diameter_closing, connectivity=2)
|
||||
_full_type_test(img, 4, ex4, diameter_closing, connectivity=2)
|
||||
|
||||
P, S = max_tree(invert(img), connectivity=2)
|
||||
_full_type_test(img, 4, ex4, diameter_opening,
|
||||
parent=P, tree_traverser=S)
|
||||
|
||||
def test_diameter_opening(self):
|
||||
"Test for Diameter Opening (2 thresholds, all types)"
|
||||
img = np.array([[5, 7, 9, 11, 12, 12, 12, 12, 12, 11, 9, 7],
|
||||
[7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10],
|
||||
[9, 40, 40, 40, 40, 16, 16, 16, 16, 60, 60, 11],
|
||||
[11, 13, 15, 16, 17, 18, 18, 18, 17, 60, 60, 13],
|
||||
[12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14],
|
||||
[12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14],
|
||||
[12, 15, 16, 18, 19, 19, 20, 19, 19, 18, 16, 15],
|
||||
[12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14],
|
||||
[12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14],
|
||||
[11, 13, 80, 80, 17, 18, 18, 18, 17, 100, 100, 13],
|
||||
[9, 11, 80, 80, 16, 16, 16, 16, 16, 15, 100, 11],
|
||||
[7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10]])
|
||||
|
||||
ex2 = np.array([[5, 7, 9, 11, 12, 12, 12, 12, 12, 11, 9, 7],
|
||||
[7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10],
|
||||
[9, 40, 40, 40, 40, 16, 16, 16, 16, 60, 60, 11],
|
||||
[11, 13, 15, 16, 17, 18, 18, 18, 17, 60, 60, 13],
|
||||
[12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14],
|
||||
[12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14],
|
||||
[12, 15, 16, 18, 19, 19, 19, 19, 19, 18, 16, 15],
|
||||
[12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14],
|
||||
[12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14],
|
||||
[11, 13, 80, 80, 17, 18, 18, 18, 17, 100, 100, 13],
|
||||
[9, 11, 80, 80, 16, 16, 16, 16, 16, 15, 100, 11],
|
||||
[7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10]])
|
||||
|
||||
ex4 = np.array([[5, 7, 9, 11, 12, 12, 12, 12, 12, 11, 9, 7],
|
||||
[7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10],
|
||||
[9, 40, 40, 40, 40, 16, 16, 16, 16, 18, 18, 11],
|
||||
[11, 13, 15, 16, 17, 18, 18, 18, 17, 18, 18, 13],
|
||||
[12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14],
|
||||
[12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14],
|
||||
[12, 15, 16, 18, 19, 19, 19, 19, 19, 18, 16, 15],
|
||||
[12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14],
|
||||
[12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14],
|
||||
[11, 13, 18, 18, 17, 18, 18, 18, 17, 18, 18, 13],
|
||||
[9, 11, 18, 18, 16, 16, 16, 16, 16, 15, 18, 11],
|
||||
[7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10]])
|
||||
|
||||
# _full_type_test makes a test with many image types.
|
||||
_full_type_test(img, 2, ex2, diameter_opening, connectivity=2)
|
||||
_full_type_test(img, 4, ex4, diameter_opening, connectivity=2)
|
||||
|
||||
P, S = max_tree(img, connectivity=2)
|
||||
_full_type_test(img, 4, ex4, diameter_opening,
|
||||
parent=P, tree_traverser=S)
|
||||
|
||||
def test_local_maxima(self):
|
||||
"local maxima for various data types"
|
||||
data = np.array([[10, 11, 13, 14, 14, 15, 14, 14, 13, 11],
|
||||
[11, 13, 15, 16, 16, 16, 16, 16, 15, 13],
|
||||
[13, 15, 40, 40, 18, 18, 18, 60, 60, 15],
|
||||
[14, 16, 40, 40, 19, 19, 19, 60, 60, 16],
|
||||
[14, 16, 18, 19, 19, 19, 19, 19, 18, 16],
|
||||
[15, 16, 18, 19, 19, 20, 19, 19, 18, 16],
|
||||
[14, 16, 18, 19, 19, 19, 19, 19, 18, 16],
|
||||
[14, 16, 80, 80, 19, 19, 19, 100, 100, 16],
|
||||
[13, 15, 80, 80, 18, 18, 18, 100, 100, 15],
|
||||
[11, 13, 15, 16, 16, 16, 16, 16, 15, 13]],
|
||||
dtype=np.uint8)
|
||||
expected_result = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint64)
|
||||
for dtype in [np.uint8, np.uint64, np.int8, np.int64]:
|
||||
|
||||
test_data = data.astype(dtype)
|
||||
out = max_tree_local_maxima(test_data, connectivity=1)
|
||||
out_bin = out > 0
|
||||
assert_array_equal(expected_result, out_bin)
|
||||
assert out.dtype == expected_result.dtype
|
||||
assert np.max(out) == 5
|
||||
|
||||
P, S = max_tree(test_data)
|
||||
out = max_tree_local_maxima(test_data,
|
||||
parent=P,
|
||||
tree_traverser=S)
|
||||
|
||||
assert_array_equal(expected_result, out_bin)
|
||||
|
||||
assert out.dtype == expected_result.dtype
|
||||
assert np.max(out) == 5
|
||||
|
||||
def test_extrema_float(self):
|
||||
"specific tests for float type"
|
||||
data = np.array([[0.10, 0.11, 0.13, 0.14, 0.14, 0.15, 0.14,
|
||||
0.14, 0.13, 0.11],
|
||||
[0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16,
|
||||
0.16, 0.15, 0.13],
|
||||
[0.13, 0.15, 0.40, 0.40, 0.18, 0.18, 0.18,
|
||||
0.60, 0.60, 0.15],
|
||||
[0.14, 0.16, 0.40, 0.40, 0.19, 0.19, 0.19,
|
||||
0.60, 0.60, 0.16],
|
||||
[0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19,
|
||||
0.19, 0.18, 0.16],
|
||||
[0.15, 0.182, 0.18, 0.19, 0.204, 0.20, 0.19,
|
||||
0.19, 0.18, 0.16],
|
||||
[0.14, 0.16, 0.18, 0.19, 0.19, 0.19, 0.19,
|
||||
0.19, 0.18, 0.16],
|
||||
[0.14, 0.16, 0.80, 0.80, 0.19, 0.19, 0.19,
|
||||
4.0, 1.0, 0.16],
|
||||
[0.13, 0.15, 0.80, 0.80, 0.18, 0.18, 0.18,
|
||||
1.0, 1.0, 0.15],
|
||||
[0.11, 0.13, 0.15, 0.16, 0.16, 0.16, 0.16,
|
||||
0.16, 0.15, 0.13]],
|
||||
dtype=np.float32)
|
||||
|
||||
expected_result = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
|
||||
# test for local maxima
|
||||
out = max_tree_local_maxima(data, connectivity=1)
|
||||
out_bin = out > 0
|
||||
assert_array_equal(expected_result, out_bin)
|
||||
assert np.max(out) == 6
|
||||
|
||||
def test_3d(self):
|
||||
"""tests the detection of maxima in 3D."""
|
||||
img = np.zeros((8, 8, 8), dtype=np.uint8)
|
||||
local_maxima = np.zeros((8, 8, 8), dtype=np.uint64)
|
||||
|
||||
# first maximum: only one pixel
|
||||
img[1, 1:3, 1:3] = 100
|
||||
img[2, 2, 2] = 200
|
||||
img[3, 1:3, 1:3] = 100
|
||||
local_maxima[2, 2, 2] = 1
|
||||
|
||||
# second maximum: three pixels in z-direction
|
||||
img[5:8, 1, 1] = 200
|
||||
local_maxima[5:8, 1, 1] = 1
|
||||
|
||||
# third: two maxima in 0 and 3.
|
||||
img[0, 5:8, 5:8] = 200
|
||||
img[1, 6, 6] = 100
|
||||
img[2, 5:7, 5:7] = 200
|
||||
img[0:3, 5:8, 5:8] += 50
|
||||
local_maxima[0, 5:8, 5:8] = 1
|
||||
local_maxima[2, 5:7, 5:7] = 1
|
||||
|
||||
# four : one maximum in the corner of the square
|
||||
img[6:8, 6:8, 6:8] = 200
|
||||
img[7, 7, 7] = 255
|
||||
local_maxima[7, 7, 7] = 1
|
||||
|
||||
out = max_tree_local_maxima(img)
|
||||
out_bin = out > 0
|
||||
assert_array_equal(local_maxima, out_bin)
|
||||
assert np.max(out) == 5
|
||||
|
||||
if __name__ == "__main__":
|
||||
np.testing.run_module_suite()
|
191
venv/Lib/site-packages/skimage/morphology/tests/test_misc.py
Normal file
191
venv/Lib/site-packages/skimage/morphology/tests/test_misc.py
Normal file
|
@ -0,0 +1,191 @@
|
|||
import numpy as np
|
||||
from skimage.morphology import remove_small_objects, remove_small_holes
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_array_equal, assert_equal
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
|
||||
|
||||
test_image = np.array([[0, 0, 0, 1, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 1]], bool)
|
||||
|
||||
|
||||
def test_one_connectivity():
|
||||
expected = np.array([[0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 0]], bool)
|
||||
observed = remove_small_objects(test_image, min_size=6)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_two_connectivity():
|
||||
expected = np.array([[0, 0, 0, 1, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 0]], bool)
|
||||
observed = remove_small_objects(test_image, min_size=7, connectivity=2)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_in_place():
|
||||
image = test_image.copy()
|
||||
observed = remove_small_objects(image, min_size=6, in_place=True)
|
||||
assert_equal(observed is image, True,
|
||||
"remove_small_objects in_place argument failed.")
|
||||
|
||||
|
||||
def test_labeled_image():
|
||||
labeled_image = np.array([[2, 2, 2, 0, 1],
|
||||
[2, 2, 2, 0, 1],
|
||||
[2, 0, 0, 0, 0],
|
||||
[0, 0, 3, 3, 3]], dtype=int)
|
||||
expected = np.array([[2, 2, 2, 0, 0],
|
||||
[2, 2, 2, 0, 0],
|
||||
[2, 0, 0, 0, 0],
|
||||
[0, 0, 3, 3, 3]], dtype=int)
|
||||
observed = remove_small_objects(labeled_image, min_size=3)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_uint_image():
|
||||
labeled_image = np.array([[2, 2, 2, 0, 1],
|
||||
[2, 2, 2, 0, 1],
|
||||
[2, 0, 0, 0, 0],
|
||||
[0, 0, 3, 3, 3]], dtype=np.uint8)
|
||||
expected = np.array([[2, 2, 2, 0, 0],
|
||||
[2, 2, 2, 0, 0],
|
||||
[2, 0, 0, 0, 0],
|
||||
[0, 0, 3, 3, 3]], dtype=np.uint8)
|
||||
observed = remove_small_objects(labeled_image, min_size=3)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_single_label_warning():
|
||||
image = np.array([[0, 0, 0, 1, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 0]], int)
|
||||
with expected_warnings(['use a boolean array?']):
|
||||
remove_small_objects(image, min_size=6)
|
||||
|
||||
|
||||
def test_float_input():
|
||||
float_test = np.random.rand(5, 5)
|
||||
with testing.raises(TypeError):
|
||||
remove_small_objects(float_test)
|
||||
|
||||
|
||||
def test_negative_input():
|
||||
negative_int = np.random.randint(-4, -1, size=(5, 5))
|
||||
with testing.raises(ValueError):
|
||||
remove_small_objects(negative_int)
|
||||
|
||||
|
||||
test_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 0, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], np.bool_)
|
||||
|
||||
|
||||
def test_one_connectivity_holes():
|
||||
expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], np.bool_)
|
||||
observed = remove_small_holes(test_holes_image, area_threshold=3)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_two_connectivity_holes():
|
||||
expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 0, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], np.bool_)
|
||||
observed = remove_small_holes(test_holes_image, area_threshold=3,
|
||||
connectivity=2)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_in_place_holes():
|
||||
image = test_holes_image.copy()
|
||||
observed = remove_small_holes(image, area_threshold=3, in_place=True)
|
||||
assert_equal(observed is image, True,
|
||||
"remove_small_holes in_place argument failed.")
|
||||
|
||||
|
||||
def test_labeled_image_holes():
|
||||
labeled_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 0, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 2, 2],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 0, 2],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 2, 2]],
|
||||
dtype=np.int_)
|
||||
expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], dtype=np.bool_)
|
||||
with expected_warnings(['returned as a boolean array']):
|
||||
observed = remove_small_holes(labeled_holes_image, area_threshold=3)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_uint_image_holes():
|
||||
labeled_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 0, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 2, 2],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 0, 2],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 2, 2]],
|
||||
dtype=np.uint8)
|
||||
expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], dtype=np.bool_)
|
||||
with expected_warnings(['returned as a boolean array']):
|
||||
observed = remove_small_holes(labeled_holes_image, area_threshold=3)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_label_warning_holes():
|
||||
labeled_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 1, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 0, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 2, 2],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 0, 2],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 2, 2]],
|
||||
dtype=np.int_)
|
||||
with expected_warnings(['use a boolean array?']):
|
||||
remove_small_holes(labeled_holes_image, area_threshold=3)
|
||||
remove_small_holes(labeled_holes_image.astype(bool), area_threshold=3)
|
||||
|
||||
|
||||
def test_float_input_holes():
|
||||
float_test = np.random.rand(5, 5)
|
||||
with testing.raises(TypeError):
|
||||
remove_small_holes(float_test)
|
|
@ -0,0 +1,141 @@
|
|||
"""
|
||||
These tests are originally part of CellProfiler, code licensed under both GPL and BSD licenses.
|
||||
|
||||
Website: http://www.cellprofiler.org
|
||||
Copyright (c) 2003-2009 Massachusetts Institute of Technology
|
||||
Copyright (c) 2009-2011 Broad Institute
|
||||
All rights reserved.
|
||||
Original author: Lee Kamentsky
|
||||
"""
|
||||
import numpy as np
|
||||
|
||||
from skimage.morphology.greyreconstruct import reconstruction
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_array_almost_equal
|
||||
|
||||
|
||||
def test_zeros():
|
||||
"""Test reconstruction with image and mask of zeros"""
|
||||
assert_array_almost_equal(
|
||||
reconstruction(np.zeros((5, 7)), np.zeros((5, 7))), 0)
|
||||
|
||||
|
||||
def test_image_equals_mask():
|
||||
"""Test reconstruction where the image and mask are the same"""
|
||||
assert_array_almost_equal(
|
||||
reconstruction(np.ones((7, 5)), np.ones((7, 5))), 1)
|
||||
|
||||
|
||||
def test_image_less_than_mask():
|
||||
"""Test reconstruction where the image is uniform and less than mask"""
|
||||
image = np.ones((5, 5))
|
||||
mask = np.ones((5, 5)) * 2
|
||||
assert_array_almost_equal(reconstruction(image, mask), 1)
|
||||
|
||||
|
||||
def test_one_image_peak():
|
||||
"""Test reconstruction with one peak pixel"""
|
||||
image = np.ones((5, 5))
|
||||
image[2, 2] = 2
|
||||
mask = np.ones((5, 5)) * 3
|
||||
assert_array_almost_equal(reconstruction(image, mask), 2)
|
||||
|
||||
|
||||
def test_two_image_peaks():
|
||||
"""Test reconstruction with two peak pixels isolated by the mask"""
|
||||
image = np.array([[1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 2, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 3, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1]])
|
||||
|
||||
mask = np.array([[4, 4, 4, 1, 1, 1, 1, 1],
|
||||
[4, 4, 4, 1, 1, 1, 1, 1],
|
||||
[4, 4, 4, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 4, 4, 4],
|
||||
[1, 1, 1, 1, 1, 4, 4, 4],
|
||||
[1, 1, 1, 1, 1, 4, 4, 4]])
|
||||
|
||||
expected = np.array([[2, 2, 2, 1, 1, 1, 1, 1],
|
||||
[2, 2, 2, 1, 1, 1, 1, 1],
|
||||
[2, 2, 2, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 3, 3, 3],
|
||||
[1, 1, 1, 1, 1, 3, 3, 3],
|
||||
[1, 1, 1, 1, 1, 3, 3, 3]])
|
||||
assert_array_almost_equal(reconstruction(image, mask), expected)
|
||||
|
||||
|
||||
def test_zero_image_one_mask():
|
||||
"""Test reconstruction with an image of all zeros and a mask that's not"""
|
||||
result = reconstruction(np.zeros((10, 10)), np.ones((10, 10)))
|
||||
assert_array_almost_equal(result, 0)
|
||||
|
||||
|
||||
def test_fill_hole():
|
||||
"""Test reconstruction by erosion, which should fill holes in mask."""
|
||||
seed = np.array([0, 8, 8, 8, 8, 8, 8, 8, 8, 0])
|
||||
mask = np.array([0, 3, 6, 2, 1, 1, 1, 4, 2, 0])
|
||||
result = reconstruction(seed, mask, method='erosion')
|
||||
assert_array_almost_equal(result, np.array([0, 3, 6, 4, 4, 4, 4, 4, 2, 0]))
|
||||
|
||||
|
||||
def test_invalid_seed():
|
||||
seed = np.ones((5, 5))
|
||||
mask = np.ones((5, 5))
|
||||
with testing.raises(ValueError):
|
||||
reconstruction(seed * 2, mask,
|
||||
method='dilation')
|
||||
with testing.raises(ValueError):
|
||||
reconstruction(seed * 0.5, mask,
|
||||
method='erosion')
|
||||
|
||||
|
||||
def test_invalid_selem():
|
||||
seed = np.ones((5, 5))
|
||||
mask = np.ones((5, 5))
|
||||
with testing.raises(ValueError):
|
||||
reconstruction(seed, mask,
|
||||
selem=np.ones((4, 4)))
|
||||
with testing.raises(ValueError):
|
||||
reconstruction(seed, mask,
|
||||
selem=np.ones((3, 4)))
|
||||
reconstruction(seed, mask, selem=np.ones((3, 3)))
|
||||
|
||||
|
||||
def test_invalid_method():
|
||||
seed = np.array([0, 8, 8, 8, 8, 8, 8, 8, 8, 0])
|
||||
mask = np.array([0, 3, 6, 2, 1, 1, 1, 4, 2, 0])
|
||||
with testing.raises(ValueError):
|
||||
reconstruction(seed, mask, method='foo')
|
||||
|
||||
|
||||
def test_invalid_offset_not_none():
|
||||
"""Test reconstruction with invalid not None offset parameter"""
|
||||
image = np.array([[1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 2, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 3, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1]])
|
||||
|
||||
mask = np.array([[4, 4, 4, 1, 1, 1, 1, 1],
|
||||
[4, 4, 4, 1, 1, 1, 1, 1],
|
||||
[4, 4, 4, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 4, 4, 4],
|
||||
[1, 1, 1, 1, 1, 4, 4, 4],
|
||||
[1, 1, 1, 1, 1, 4, 4, 4]])
|
||||
with testing.raises(ValueError):
|
||||
reconstruction(image, mask, method='dilation',
|
||||
selem=np.ones((3, 3)), offset=np.array([3, 0]))
|
||||
|
||||
|
||||
def test_offset_not_none():
|
||||
"""Test reconstruction with valid offset parameter"""
|
||||
seed = np.array([0, 3, 6, 2, 1, 1, 1, 4, 2, 0])
|
||||
mask = np.array([0, 8, 6, 8, 8, 8, 8, 4, 4, 0])
|
||||
expected = np.array([0, 3, 6, 6, 6, 6, 6, 4, 4, 0])
|
||||
|
||||
assert_array_almost_equal(
|
||||
reconstruction(seed, mask, method='dilation',
|
||||
selem=np.ones(3), offset=np.array([0])), expected)
|
148
venv/Lib/site-packages/skimage/morphology/tests/test_selem.py
Normal file
148
venv/Lib/site-packages/skimage/morphology/tests/test_selem.py
Normal file
|
@ -0,0 +1,148 @@
|
|||
"""
|
||||
Tests for Morphological structuring elements
|
||||
(skimage.morphology.selem)
|
||||
|
||||
Author: Damian Eads
|
||||
"""
|
||||
import numpy as np
|
||||
|
||||
from skimage import data
|
||||
from skimage.morphology import selem
|
||||
|
||||
from skimage._shared.testing import assert_equal, fetch
|
||||
from skimage._shared import testing
|
||||
|
||||
|
||||
class TestSElem():
|
||||
|
||||
def test_square_selem(self):
|
||||
"""Test square structuring elements"""
|
||||
for k in range(0, 5):
|
||||
actual_mask = selem.square(k)
|
||||
expected_mask = np.ones((k, k), dtype='uint8')
|
||||
assert_equal(expected_mask, actual_mask)
|
||||
|
||||
def test_rectangle_selem(self):
|
||||
"""Test rectangle structuring elements"""
|
||||
for i in range(0, 5):
|
||||
for j in range(0, 5):
|
||||
actual_mask = selem.rectangle(i, j)
|
||||
expected_mask = np.ones((i, j), dtype='uint8')
|
||||
assert_equal(expected_mask, actual_mask)
|
||||
|
||||
def test_cube_selem(self):
|
||||
"""Test cube structuring elements"""
|
||||
for k in range(0, 5):
|
||||
actual_mask = selem.cube(k)
|
||||
expected_mask = np.ones((k, k, k), dtype='uint8')
|
||||
assert_equal(expected_mask, actual_mask)
|
||||
|
||||
def strel_worker(self, fn, func):
|
||||
matlab_masks = np.load(fetch(fn))
|
||||
k = 0
|
||||
for arrname in sorted(matlab_masks):
|
||||
expected_mask = matlab_masks[arrname]
|
||||
actual_mask = func(k)
|
||||
if expected_mask.shape == (1,):
|
||||
expected_mask = expected_mask[:, np.newaxis]
|
||||
assert_equal(expected_mask, actual_mask)
|
||||
k = k + 1
|
||||
|
||||
def strel_worker_3d(self, fn, func):
|
||||
matlab_masks = np.load(fetch(fn))
|
||||
k = 0
|
||||
for arrname in sorted(matlab_masks):
|
||||
expected_mask = matlab_masks[arrname]
|
||||
actual_mask = func(k)
|
||||
if expected_mask.shape == (1,):
|
||||
expected_mask = expected_mask[:, np.newaxis]
|
||||
# Test center slice for each dimension. This gives a good
|
||||
# indication of validity without the need for a 3D reference
|
||||
# mask.
|
||||
c = int(expected_mask.shape[0]/2)
|
||||
assert_equal(expected_mask, actual_mask[c, :, :])
|
||||
assert_equal(expected_mask, actual_mask[:, c, :])
|
||||
assert_equal(expected_mask, actual_mask[:, :, c])
|
||||
k = k + 1
|
||||
|
||||
def test_selem_disk(self):
|
||||
"""Test disk structuring elements"""
|
||||
self.strel_worker("data/disk-matlab-output.npz", selem.disk)
|
||||
|
||||
def test_selem_diamond(self):
|
||||
"""Test diamond structuring elements"""
|
||||
self.strel_worker("data/diamond-matlab-output.npz", selem.diamond)
|
||||
|
||||
def test_selem_ball(self):
|
||||
"""Test ball structuring elements"""
|
||||
self.strel_worker_3d("data/disk-matlab-output.npz", selem.ball)
|
||||
|
||||
def test_selem_octahedron(self):
|
||||
"""Test octahedron structuring elements"""
|
||||
self.strel_worker_3d("data/diamond-matlab-output.npz",
|
||||
selem.octahedron)
|
||||
|
||||
def test_selem_octagon(self):
|
||||
"""Test octagon structuring elements"""
|
||||
expected_mask1 = np.array([[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
actual_mask1 = selem.octagon(5, 3)
|
||||
expected_mask2 = np.array([[0, 1, 0],
|
||||
[1, 1, 1],
|
||||
[0, 1, 0]], dtype=np.uint8)
|
||||
actual_mask2 = selem.octagon(1, 1)
|
||||
assert_equal(expected_mask1, actual_mask1)
|
||||
assert_equal(expected_mask2, actual_mask2)
|
||||
|
||||
def test_selem_ellipse(self):
|
||||
"""Test ellipse structuring elements"""
|
||||
expected_mask1 = np.array([[0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]], dtype=np.uint8)
|
||||
actual_mask1 = selem.ellipse(5, 3)
|
||||
expected_mask2 = np.array([[1, 1, 1],
|
||||
[1, 1, 1],
|
||||
[1, 1, 1]], dtype=np.uint8)
|
||||
actual_mask2 = selem.ellipse(1, 1)
|
||||
assert_equal(expected_mask1, actual_mask1)
|
||||
assert_equal(expected_mask2, actual_mask2)
|
||||
assert_equal(expected_mask1, selem.ellipse(3, 5).T)
|
||||
assert_equal(expected_mask2, selem.ellipse(1, 1).T)
|
||||
|
||||
def test_selem_star(self):
|
||||
"""Test star structuring elements"""
|
||||
expected_mask1 = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
actual_mask1 = selem.star(4)
|
||||
expected_mask2 = np.array([[1, 1, 1],
|
||||
[1, 1, 1],
|
||||
[1, 1, 1]], dtype=np.uint8)
|
||||
actual_mask2 = selem.star(1)
|
||||
assert_equal(expected_mask1, actual_mask1)
|
||||
assert_equal(expected_mask2, actual_mask2)
|
|
@ -0,0 +1,242 @@
|
|||
import numpy as np
|
||||
from skimage.morphology import skeletonize, medial_axis, thin
|
||||
from skimage.morphology._skeletonize import (_generate_thin_luts,
|
||||
G123_LUT, G123P_LUT)
|
||||
from skimage import draw
|
||||
from scipy.ndimage import correlate
|
||||
from skimage.io import imread
|
||||
from skimage import data
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_array_equal, fetch
|
||||
|
||||
|
||||
class TestSkeletonize():
|
||||
def test_skeletonize_no_foreground(self):
|
||||
im = np.zeros((5, 5))
|
||||
result = skeletonize(im)
|
||||
assert_array_equal(result, np.zeros((5, 5)))
|
||||
|
||||
def test_skeletonize_wrong_dim1(self):
|
||||
im = np.zeros((5))
|
||||
with testing.raises(ValueError):
|
||||
skeletonize(im)
|
||||
|
||||
def test_skeletonize_wrong_dim2(self):
|
||||
im = np.zeros((5, 5, 5))
|
||||
with testing.raises(ValueError):
|
||||
skeletonize(im, method='zhang')
|
||||
|
||||
def test_skeletonize_not_binary(self):
|
||||
im = np.zeros((5, 5))
|
||||
im[0, 0] = 1
|
||||
im[0, 1] = 2
|
||||
with testing.raises(ValueError):
|
||||
skeletonize(im)
|
||||
|
||||
def test_skeletonize_unexpected_value(self):
|
||||
im = np.zeros((5, 5))
|
||||
im[0, 0] = 2
|
||||
with testing.raises(ValueError):
|
||||
skeletonize(im)
|
||||
|
||||
def test_skeletonize_all_foreground(self):
|
||||
im = np.ones((3, 4))
|
||||
skeletonize(im)
|
||||
|
||||
def test_skeletonize_single_point(self):
|
||||
im = np.zeros((5, 5), np.uint8)
|
||||
im[3, 3] = 1
|
||||
result = skeletonize(im)
|
||||
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(im)
|
||||
assert_array_equal(result, im)
|
||||
|
||||
def test_skeletonize_output(self):
|
||||
im = imread(fetch("data/bw_text.png"), as_gray=True)
|
||||
|
||||
# make black the foreground
|
||||
im = (im == 0)
|
||||
result = skeletonize(im)
|
||||
|
||||
expected = np.load(fetch("data/bw_text_skeleton.npy"))
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
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.line(250, 150, 10, 280)
|
||||
for i in range(10):
|
||||
image[rs + i, cs] = 1
|
||||
rs, cs = draw.line(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(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')
|
||||
assert not np.any(blocks == 4)
|
||||
|
||||
def test_lut_fix(self):
|
||||
im = np.zeros((6, 6), np.uint8)
|
||||
im[1, 2] = 1
|
||||
im[2, 2] = 1
|
||||
im[2, 3] = 1
|
||||
im[3, 3] = 1
|
||||
im[3, 4] = 1
|
||||
im[4, 4] = 1
|
||||
im[4, 5] = 1
|
||||
result = skeletonize(im)
|
||||
expected = np.array([[0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
assert np.all(result == expected)
|
||||
|
||||
|
||||
class TestThin():
|
||||
@property
|
||||
def input_image(self):
|
||||
"""image to test thinning with"""
|
||||
ii = np.array([[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0],
|
||||
[0, 1, 0, 1, 1, 1, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0],
|
||||
[0, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
return ii
|
||||
|
||||
def test_zeros(self):
|
||||
assert np.all(thin(np.zeros((10, 10))) == False)
|
||||
|
||||
def test_iter_1(self):
|
||||
result = thin(self.input_image, 1).astype(np.uint8)
|
||||
expected = np.array([[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
def test_noiter(self):
|
||||
result = thin(self.input_image).astype(np.uint8)
|
||||
expected = np.array([[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
def test_baddim(self):
|
||||
for ii in [np.zeros((3)), np.zeros((3, 3, 3))]:
|
||||
with testing.raises(ValueError):
|
||||
thin(ii)
|
||||
|
||||
def test_lut_generation(self):
|
||||
g123, g123p = _generate_thin_luts()
|
||||
|
||||
assert_array_equal(g123, G123_LUT)
|
||||
assert_array_equal(g123p, G123P_LUT)
|
||||
|
||||
|
||||
class TestMedialAxis():
|
||||
def test_00_00_zeros(self):
|
||||
'''Test skeletonize on an array of all zeros'''
|
||||
result = medial_axis(np.zeros((10, 10), bool))
|
||||
assert np.all(result == False)
|
||||
|
||||
def test_00_01_zeros_masked(self):
|
||||
'''Test skeletonize on an array that is completely masked'''
|
||||
result = medial_axis(np.zeros((10, 10), bool),
|
||||
np.zeros((10, 10), bool))
|
||||
assert np.all(result == False)
|
||||
|
||||
def test_vertical_line(self):
|
||||
'''Test a thick vertical line, issue #3861'''
|
||||
img = np.zeros((9, 9))
|
||||
img[:, 2] = 1
|
||||
img[:, 3] = 1
|
||||
img[:, 4] = 1
|
||||
|
||||
expected = np.full(img.shape, False)
|
||||
expected[:, 3] = True
|
||||
|
||||
result = medial_axis(img)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
def test_01_01_rectangle(self):
|
||||
'''Test skeletonize on a rectangle'''
|
||||
image = np.zeros((9, 15), bool)
|
||||
image[1:-1, 1:-1] = True
|
||||
#
|
||||
# The result should be four diagonals from the
|
||||
# corners, meeting in a horizontal line
|
||||
#
|
||||
expected = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.bool_)
|
||||
result = medial_axis(image)
|
||||
assert np.all(result == expected)
|
||||
result, distance = medial_axis(image, return_distance=True)
|
||||
assert distance.max() == 4
|
||||
|
||||
def test_01_02_hole(self):
|
||||
'''Test skeletonize on a rectangle with a hole in the middle'''
|
||||
image = np.zeros((9, 15), bool)
|
||||
image[1:-1, 1:-1] = True
|
||||
image[4, 4:-4] = False
|
||||
expected = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.bool_)
|
||||
result = medial_axis(image)
|
||||
assert np.all(result == expected)
|
||||
|
||||
def test_narrow_image(self):
|
||||
"""Test skeletonize on a 1-pixel thin strip"""
|
||||
image = np.zeros((1, 5), bool)
|
||||
image[:, 1:-1] = True
|
||||
result = medial_axis(image)
|
||||
assert np.all(result == image)
|
|
@ -0,0 +1,188 @@
|
|||
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
import scipy.ndimage as ndi
|
||||
|
||||
from skimage import io, draw, data
|
||||
from skimage.data import binary_blobs
|
||||
from skimage.util import img_as_ubyte
|
||||
from skimage.morphology import skeletonize, skeletonize_3d
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_equal, assert_, parametrize, fetch
|
||||
|
||||
# basic behavior tests (mostly copied over from 2D skeletonize)
|
||||
|
||||
def test_skeletonize_wrong_dim():
|
||||
im = np.zeros(5, dtype=np.uint8)
|
||||
with testing.raises(ValueError):
|
||||
skeletonize(im, method='lee')
|
||||
|
||||
im = np.zeros((5, 5, 5, 5), dtype=np.uint8)
|
||||
with testing.raises(ValueError):
|
||||
skeletonize(im, method='lee')
|
||||
|
||||
|
||||
def test_skeletonize_1D_old_api():
|
||||
# a corner case of an image of a shape(1, N)
|
||||
im = np.ones((5, 1), dtype=np.uint8)
|
||||
res = skeletonize_3d(im)
|
||||
assert_equal(res, im)
|
||||
|
||||
|
||||
def test_skeletonize_1D():
|
||||
# a corner case of an image of a shape(1, N)
|
||||
im = np.ones((5, 1), dtype=np.uint8)
|
||||
res = skeletonize(im, method='lee')
|
||||
assert_equal(res, im)
|
||||
|
||||
|
||||
def test_skeletonize_no_foreground():
|
||||
im = np.zeros((5, 5), dtype=np.uint8)
|
||||
result = skeletonize(im, method='lee')
|
||||
assert_equal(result, im)
|
||||
|
||||
|
||||
def test_skeletonize_all_foreground():
|
||||
im = np.ones((3, 4), dtype=np.uint8)
|
||||
assert_equal(skeletonize(im, method='lee'),
|
||||
np.array([[0, 0, 0, 0],
|
||||
[1, 1, 1, 1],
|
||||
[0, 0, 0, 0]], dtype=np.uint8))
|
||||
|
||||
|
||||
def test_skeletonize_single_point():
|
||||
im = np.zeros((5, 5), dtype=np.uint8)
|
||||
im[3, 3] = 1
|
||||
result = skeletonize(im, method='lee')
|
||||
assert_equal(result, im)
|
||||
|
||||
|
||||
def test_skeletonize_already_thinned():
|
||||
im = np.zeros((5, 5), dtype=np.uint8)
|
||||
im[3, 1:-1] = 1
|
||||
im[2, -1] = 1
|
||||
im[4, 0] = 1
|
||||
result = skeletonize(im, method='lee')
|
||||
assert_equal(result, im)
|
||||
|
||||
|
||||
def test_dtype_conv():
|
||||
# check that the operation does the right thing with floats etc
|
||||
# also check non-contiguous input
|
||||
img = np.random.random((16, 16))[::2, ::2]
|
||||
img[img < 0.5] = 0
|
||||
|
||||
orig = img.copy()
|
||||
res = skeletonize(img, method='lee')
|
||||
img_max = img_as_ubyte(img).max()
|
||||
|
||||
assert_equal(res.dtype, np.uint8)
|
||||
assert_equal(img, orig) # operation does not clobber the original
|
||||
assert_equal(res.max(), img_max) # the intensity range is preserved
|
||||
|
||||
|
||||
@parametrize("img", [
|
||||
np.ones((8, 8), dtype=float), np.ones((4, 8, 8), dtype=float)
|
||||
])
|
||||
def test_input_with_warning(img):
|
||||
# check that the input is not clobbered
|
||||
# for 2D and 3D images of varying dtypes
|
||||
check_input(img)
|
||||
|
||||
|
||||
@parametrize("img", [
|
||||
np.ones((8, 8), dtype=np.uint8), np.ones((4, 8, 8), dtype=np.uint8),
|
||||
np.ones((8, 8), dtype=bool), np.ones((4, 8, 8), dtype=bool)
|
||||
])
|
||||
def test_input_without_warning(img):
|
||||
# check that the input is not clobbered
|
||||
# for 2D and 3D images of varying dtypes
|
||||
check_input(img)
|
||||
|
||||
|
||||
def check_input(img):
|
||||
orig = img.copy()
|
||||
skeletonize(img, method='lee')
|
||||
assert_equal(img, orig)
|
||||
|
||||
|
||||
def test_skeletonize_num_neighbours():
|
||||
# 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.line(250, 150, 10, 280)
|
||||
for i in range(10):
|
||||
image[rs + i, cs] = 1
|
||||
rs, cs = draw.line(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(image, method='lee')
|
||||
|
||||
# there should never be a 2x2 block of foreground pixels in a skeleton
|
||||
mask = np.array([[1, 1],
|
||||
[1, 1]], np.uint8)
|
||||
blocks = ndi.correlate(result, mask, mode='constant')
|
||||
assert_(not np.any(blocks == 4))
|
||||
|
||||
|
||||
def test_two_hole_image():
|
||||
# test a simple 2D image against FIJI
|
||||
img_o = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
|
||||
[0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
|
||||
[0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
|
||||
[0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
|
||||
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
img_f = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
dtype=np.uint8)
|
||||
res = skeletonize(img_o, method='lee')
|
||||
assert_equal(res, img_f)
|
||||
|
||||
|
||||
def test_3d_vs_fiji():
|
||||
# generate an image with blobs and compate its skeleton to
|
||||
# the skeleton generated by FIJI
|
||||
img = binary_blobs(32, 0.05, n_dim=3, seed=1234)
|
||||
img = img[:-2, ...]
|
||||
img = img.astype(np.uint8)*255
|
||||
|
||||
img_s = skeletonize(img)
|
||||
img_f = io.imread(fetch("data/_blobs_3d_fiji_skeleton.tif"))
|
||||
assert_equal(img_s, img_f)
|
127
venv/Lib/site-packages/skimage/morphology/tests/test_util.py
Normal file
127
venv/Lib/site-packages/skimage/morphology/tests/test_util.py
Normal file
|
@ -0,0 +1,127 @@
|
|||
"""Tests for `_util`."""
|
||||
|
||||
|
||||
import pytest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_equal
|
||||
|
||||
from skimage.morphology import _util
|
||||
|
||||
|
||||
@pytest.mark.parametrize("image_shape", [
|
||||
(111,), (33, 44), (22, 55, 11), (6, 5, 4, 3)
|
||||
])
|
||||
@pytest.mark.parametrize("order", ["C", "F"])
|
||||
def test_offsets_to_raveled_neighbors_highest_connectivity(image_shape, order):
|
||||
"""
|
||||
Check scenarios where selem is always of the highest connectivity
|
||||
and all dimensions are > 2.
|
||||
"""
|
||||
selem = np.ones((3,) * len(image_shape), dtype=bool)
|
||||
center = (1,) * len(image_shape)
|
||||
offsets = _util._offsets_to_raveled_neighbors(
|
||||
image_shape, selem, center, order
|
||||
)
|
||||
|
||||
# Assert only neighbors are present, center was removed
|
||||
assert len(offsets) == selem.sum() - 1
|
||||
assert 0 not in offsets
|
||||
# Assert uniqueness
|
||||
assert len(set(offsets)) == offsets.size
|
||||
# offsets form pairs of with same value but different signs
|
||||
# if selem is symmetric around center
|
||||
assert all(-x in offsets for x in offsets)
|
||||
|
||||
# Construct image whose values are the Manhattan distance to its center
|
||||
image_center = tuple(s // 2 for s in image_shape)
|
||||
coords = [
|
||||
np.abs(np.arange(s, dtype=np.intp) - c)
|
||||
for s, c in zip(image_shape, image_center)
|
||||
]
|
||||
grid = np.meshgrid(*coords, indexing="ij")
|
||||
image = np.sum(grid, axis=0)
|
||||
|
||||
image_raveled = image.ravel(order)
|
||||
image_center_raveled = np.ravel_multi_index(
|
||||
image_center, image_shape, order=order
|
||||
)
|
||||
|
||||
# Sample raveled image around its center
|
||||
samples = []
|
||||
for offset in offsets:
|
||||
index = image_center_raveled + offset
|
||||
samples.append(image_raveled[index])
|
||||
|
||||
# Assert that center with value 0 wasn't selected
|
||||
assert np.min(samples) == 1
|
||||
# Assert that only neighbors where selected
|
||||
# (highest value == connectivity)
|
||||
assert np.max(samples) == len(image_shape)
|
||||
# Assert that nearest neighbors are selected first
|
||||
assert list(sorted(samples)) == samples
|
||||
|
||||
|
||||
@pytest.mark.parametrize("image_shape", [
|
||||
(2,), (2, 2), (2, 1, 2), (2, 2, 1, 2), (0, 2, 1, 2)
|
||||
])
|
||||
@pytest.mark.parametrize("order", ["C", "F"])
|
||||
def test_offsets_to_raveled_neighbors_selem_smaller_image(image_shape, order):
|
||||
"""
|
||||
Test if a dimension indicated by `image_shape` is smaller than in
|
||||
`selem`.
|
||||
"""
|
||||
selem = np.ones((3,) * len(image_shape), dtype=bool)
|
||||
center = (1,) * len(image_shape)
|
||||
offsets = _util._offsets_to_raveled_neighbors(
|
||||
image_shape, selem, center, order
|
||||
)
|
||||
|
||||
# Assert only neighbors are present, center and duplicates (possible
|
||||
# for this scenario) where removed
|
||||
assert len(offsets) <= selem.sum() - 1
|
||||
assert 0 not in offsets
|
||||
# Assert uniqueness
|
||||
assert len(set(offsets)) == offsets.size
|
||||
# offsets form pairs of with same value but different signs
|
||||
# if selem is symmetric around center
|
||||
assert all(-x in offsets for x in offsets)
|
||||
|
||||
|
||||
def test_offsets_to_raveled_neighbors_explicit_0():
|
||||
"""Check reviewed example."""
|
||||
image_shape = (100, 200, 3)
|
||||
selem = np.ones((3, 3, 3), dtype=bool)
|
||||
center = (1, 1, 1)
|
||||
offsets = _util._offsets_to_raveled_neighbors(
|
||||
image_shape, selem, center
|
||||
)
|
||||
|
||||
desired = np.array([
|
||||
3, -600, 1, -1, 600, -3, 4, 2, 603, -2, -4,
|
||||
-597, 601, -599, -601, -603, 599, 597, 602, -604, 596, -596,
|
||||
-598, -602, 598, 604
|
||||
])
|
||||
assert_array_equal(offsets, desired)
|
||||
|
||||
|
||||
def test_offsets_to_raveled_neighbors_explicit_1():
|
||||
"""Check reviewed example where selem is larger in last dimension."""
|
||||
image_shape = (10, 9, 8, 3)
|
||||
selem = np.ones((3, 3, 3, 4), dtype=bool)
|
||||
center = (1, 1, 1, 1)
|
||||
offsets = _util._offsets_to_raveled_neighbors(
|
||||
image_shape, selem, center
|
||||
)
|
||||
|
||||
desired = np.array([
|
||||
24, 3, 1, -1, -3, -24, -216, 216, -192, 215, -2,
|
||||
-21, -23, 2, -25, -27, 4, 217, 21, 219, -4, 23,
|
||||
25, -240, 240, 192, 27, -213, -219, 213, -215, -217, -243,
|
||||
191, -241, 195, 189, 212, 26, 5, 20, 28, 22, 214,
|
||||
243, -237, -22, 241, -214, -212, 237, -218, -195, -20, 220,
|
||||
-193, -191, 218, -189, -28, -26, 193, -239, -220, 239, 196,
|
||||
221, 242, 236, 238, 194, -244, -188, -238, -211, -196, -194,
|
||||
-190, -236, -19, 244, 29, 188, -242, 190, -187, 197, -235,
|
||||
245
|
||||
])
|
||||
assert_array_equal(offsets, desired)
|
Loading…
Add table
Add a link
Reference in a new issue