diff --git a/skimage/morphology/grey.py b/skimage/morphology/grey.py index c82e2585..ee8542dd 100644 --- a/skimage/morphology/grey.py +++ b/skimage/morphology/grey.py @@ -5,11 +5,20 @@ __docformat__ = 'restructuredtext en' +import warnings + import numpy as np -eps = np.finfo(float).eps +import skimage -def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False): + +__all__ = ['erosion', 'dilation', 'opening', 'closing', 'white_tophat', + 'black_tophat', 'greyscale_erode', 'greyscale_dilate', + 'greyscale_open', 'greyscale_close', 'greyscale_white_top_hat', + 'greyscale_black_top_hat'] + + +def erosion(image, selem, out=None, shift_x=False, shift_y=False): """Return greyscale morphological erosion of an image. Morphological erosion sets a pixel at (i,j) to the minimum over all pixels @@ -19,7 +28,7 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - The image as a uint8 ndarray. + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. @@ -34,7 +43,7 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False): Returns ------- - eroded : ndarray + eroded : uint8 array The result of the morphological erosion. Examples @@ -46,7 +55,7 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False): ... [0, 1, 1, 1, 0], ... [0, 1, 1, 1, 0], ... [0, 0, 0, 0, 0]], dtype=np.uint8) - >>> greyscale_erode(bright_square, square(3)) + >>> erosion(bright_square, square(3)) array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], @@ -56,6 +65,8 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False): """ if image is out: raise NotImplementedError("In-place erosion not supported!") + image = skimage.img_as_ubyte(image) + try: import skimage.morphology.cmorph as cmorph out = cmorph.erode(image, selem, out=out, @@ -64,7 +75,8 @@ def greyscale_erode(image, selem, out=None, shift_x=False, shift_y=False): except ImportError: raise ImportError("cmorph extension not available.") -def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False): + +def dilation(image, selem, out=None, shift_x=False, shift_y=False): """Return greyscale morphological dilation of an image. Morphological dilation sets a pixel at (i,j) to the maximum over all pixels @@ -75,7 +87,7 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False): ---------- image : ndarray - The image as a uint8 ndarray. + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. @@ -90,7 +102,7 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False): Returns ------- - dilated : ndarray + dilated : uint8 array The result of the morphological dilation. Examples @@ -102,7 +114,7 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False): ... [0, 0, 1, 0, 0], ... [0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0]], dtype=np.uint8) - >>> greyscale_dilate(bright_pixel, square(3)) + >>> dilation(bright_pixel, square(3)) array([[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], @@ -112,6 +124,8 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False): """ if image is out: raise NotImplementedError("In-place dilation not supported!") + image = skimage.img_as_ubyte(image) + try: from . import cmorph out = cmorph.dilate(image, selem, out=out, @@ -120,7 +134,8 @@ def greyscale_dilate(image, selem, out=None, shift_x=False, shift_y=False): except ImportError: raise ImportError("cmorph extension not available.") -def greyscale_open(image, selem, out=None): + +def opening(image, selem, out=None): """Return greyscale morphological opening of an image. The morphological opening on an image is defined as an erosion followed by @@ -131,7 +146,7 @@ def greyscale_open(image, selem, out=None): Parameters ---------- image : ndarray - The image as a uint8 ndarray. + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. @@ -142,7 +157,7 @@ def greyscale_open(image, selem, out=None): Returns ------- - opening : ndarray + opening : uint8 array The result of the morphological opening. Examples @@ -154,7 +169,7 @@ def greyscale_open(image, selem, out=None): ... [1, 1, 1, 1, 1], ... [1, 1, 0, 1, 1], ... [1, 0, 0, 0, 1]], dtype=np.uint8) - >>> greyscale_open(bad_connection, square(3)) + >>> opening(bad_connection, square(3)) array([[0, 0, 0, 0, 0], [1, 1, 0, 1, 1], [1, 1, 0, 1, 1], @@ -166,12 +181,12 @@ def greyscale_open(image, selem, out=None): shift_x = True if (w % 2) == 0 else False shift_y = True if (h % 2) == 0 else False - eroded = greyscale_erode(image, selem) - out = greyscale_dilate(eroded, selem, out=out, - shift_x=shift_x, shift_y=shift_y) + eroded = erosion(image, selem) + out = dilation(eroded, selem, out=out, shift_x=shift_x, shift_y=shift_y) return out -def greyscale_close(image, selem, out=None): + +def closing(image, selem, out=None): """Return greyscale morphological closing of an image. The morphological closing on an image is defined as a dilation followed by @@ -182,7 +197,7 @@ def greyscale_close(image, selem, out=None): Parameters ---------- image : ndarray - The image as a uint8 ndarray. + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. @@ -193,8 +208,8 @@ def greyscale_close(image, selem, out=None): Returns ------- - opening : ndarray - The result of the morphological opening. + closing : uint8 array + The result of the morphological closing. Examples -------- @@ -205,7 +220,7 @@ def greyscale_close(image, selem, out=None): ... [1, 1, 0, 1, 1], ... [0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0]], dtype=np.uint8) - >>> greyscale_close(broken_line, square(3)) + >>> closing(broken_line, square(3)) array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 1, 1, 1, 1], @@ -217,12 +232,12 @@ def greyscale_close(image, selem, out=None): shift_x = True if (w % 2) == 0 else False shift_y = True if (h % 2) == 0 else False - dilated = greyscale_dilate(image, selem) - out = greyscale_erode(dilated, selem, out=out, - shift_x=shift_x, shift_y=shift_y) + dilated = dilation(image, selem) + out = erosion(dilated, selem, out=out, shift_x=shift_x, shift_y=shift_y) return out -def greyscale_white_top_hat(image, selem, out=None): + +def white_tophat(image, selem, out=None): """Return white top hat of an image. The white top hat of an image is defined as the image minus its @@ -232,7 +247,7 @@ def greyscale_white_top_hat(image, selem, out=None): Parameters ---------- image : ndarray - The image as a uint8 ndarray. + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. @@ -243,7 +258,7 @@ def greyscale_white_top_hat(image, selem, out=None): Returns ------- - opening : ndarray + opening : uint8 array The result of the morphological white top hat. Examples @@ -255,7 +270,7 @@ def greyscale_white_top_hat(image, selem, out=None): ... [3, 5, 9, 5, 3], ... [3, 4, 5, 4, 3], ... [2, 3, 3, 3, 2]], dtype=np.uint8) - >>> greyscale_white_top_hat(bright_on_grey, square(3)) + >>> white_tophat(bright_on_grey, square(3)) array([[0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 1, 5, 1, 0], @@ -265,12 +280,14 @@ def greyscale_white_top_hat(image, selem, out=None): """ if image is out: raise NotImplementedError("Cannot perform white top hat in place.") + image = skimage.img_as_ubyte(image) - out = greyscale_open(image, selem, out=out) + out = opening(image, selem, out=out) out = image - out return out -def greyscale_black_top_hat(image, selem, out=None): + +def black_tophat(image, selem, out=None): """Return black top hat of an image. The black top hat of an image is defined as its morphological closing minus @@ -281,7 +298,7 @@ def greyscale_black_top_hat(image, selem, out=None): Parameters ---------- image : ndarray - The image as a uint8 ndarray. + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. @@ -292,7 +309,7 @@ def greyscale_black_top_hat(image, selem, out=None): Returns ------- - opening : ndarray + opening : uint8 array The result of the black top filter. Examples @@ -304,7 +321,7 @@ def greyscale_black_top_hat(image, selem, out=None): ... [6, 4, 0, 4, 6], ... [6, 5, 4, 5, 6], ... [7, 6, 6, 6, 7]], dtype=np.uint8) - >>> greyscale_black_top_hat(dark_on_grey, square(3)) + >>> black_tophat(dark_on_grey, square(3)) array([[0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 1, 5, 1, 0], @@ -314,7 +331,34 @@ def greyscale_black_top_hat(image, selem, out=None): """ if image is out: raise NotImplementedError("Cannot perform white top hat in place.") - out = greyscale_close(image, selem, out=out) + image = skimage.img_as_ubyte(image) + + out = closing(image, selem, out=out) out = out - image return out + +def greyscale_erode(*args, **kwargs): + warnings.warn("`greyscale_erode` renamed `erosion`.") + return erosion(*args, **kwargs) + +def greyscale_dilate(*args, **kwargs): + warnings.warn("`greyscale_dilate` renamed `dilation`.") + return dilation(*args, **kwargs) + +def greyscale_open(*args, **kwargs): + warnings.warn("`greyscale_open` renamed `opening`.") + return opening(*args, **kwargs) + +def greyscale_close(*args, **kwargs): + warnings.warn("`greyscale_close` renamed `closing`.") + return closing(*args, **kwargs) + +def greyscale_white_top_hat(*args, **kwargs): + warnings.warn("`greyscale_white_top_hat` renamed `white_tophat`.") + return white_tophat(*args, **kwargs) + +def greyscale_black_top_hat(*args, **kwargs): + warnings.warn("`greyscale_black_top_hat` renamed `black_tophat`.") + return black_tophat(*args, **kwargs) + diff --git a/skimage/morphology/tests/test_morphology.py b/skimage/morphology/tests/test_grey.py similarity index 51% rename from skimage/morphology/tests/test_morphology.py rename to skimage/morphology/tests/test_grey.py index 2d089c58..1103b20d 100644 --- a/skimage/morphology/tests/test_morphology.py +++ b/skimage/morphology/tests/test_grey.py @@ -1,12 +1,13 @@ import os.path import numpy as np -from numpy.testing import * +from numpy import testing +import skimage from skimage import data_dir -from skimage.io import imread -from skimage import data_dir -from skimage.morphology import * +from skimage.morphology import grey +from skimage.morphology import selem + lena = np.load(os.path.join(data_dir, 'lena_GRAY_U8.npy')) @@ -19,48 +20,48 @@ class TestMorphology(): expected_result = matlab_results[arrname] mask = strel_func(k) actual_result = morph_func(lena, mask) - assert_equal(expected_result, actual_result) + testing.assert_equal(expected_result, actual_result) k = k + 1 def test_erode_diamond(self): self.morph_worker(lena, "diamond-erode-matlab-output.npz", - greyscale_erode, diamond) + grey.erosion, selem.diamond) def test_dilate_diamond(self): self.morph_worker(lena, "diamond-dilate-matlab-output.npz", - greyscale_dilate, diamond) + grey.dilation, selem.diamond) def test_open_diamond(self): self.morph_worker(lena, "diamond-open-matlab-output.npz", - greyscale_open, diamond) + grey.opening, selem.diamond) def test_close_diamond(self): self.morph_worker(lena, "diamond-close-matlab-output.npz", - greyscale_close, diamond) + grey.closing, selem.diamond) def test_tophat_diamond(self): self.morph_worker(lena, "diamond-tophat-matlab-output.npz", - greyscale_white_top_hat, diamond) + grey.white_tophat, selem.diamond) def test_bothat_diamond(self): self.morph_worker(lena, "diamond-bothat-matlab-output.npz", - greyscale_black_top_hat, diamond) + grey.black_tophat, selem.diamond) def test_erode_disk(self): self.morph_worker(lena, "disk-erode-matlab-output.npz", - greyscale_erode, disk) + grey.erosion, selem.disk) def test_dilate_disk(self): self.morph_worker(lena, "disk-dilate-matlab-output.npz", - greyscale_dilate, disk) + grey.dilation, selem.disk) def test_open_disk(self): self.morph_worker(lena, "disk-open-matlab-output.npz", - greyscale_open, disk) + grey.opening, selem.disk) def test_close_disk(self): self.morph_worker(lena, "disk-close-matlab-output.npz", - greyscale_close, disk) + grey.closing, selem.disk) class TestEccentricStructuringElements(): @@ -69,50 +70,89 @@ class TestEccentricStructuringElements(): 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 = [square(2), rectangle(2, 2), - rectangle(2, 1), rectangle(1, 2)] + 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 = greyscale_erode(self.black_pixel, s) - d = greyscale_dilate(self.white_pixel, s) + 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 = greyscale_open(self.black_pixel, s) + 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 = greyscale_close(self.white_pixel, s) + 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(greyscale_open(self.white_pixel, s) == 0) + assert np.all(grey.opening(self.white_pixel, s) == 0) def test_close_black_pixel(self): for s in self.selems: - assert np.all(greyscale_close(self.black_pixel, s) == 255) + assert np.all(grey.closing(self.black_pixel, s) == 255) def test_white_tophat_white_pixel(self): for s in self.selems: - tophat = greyscale_white_top_hat(self.white_pixel, s) + 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 = greyscale_black_top_hat(self.black_pixel, s) + 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 = greyscale_white_top_hat(self.black_pixel, s) + 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 = greyscale_black_top_hat(self.white_pixel, s) + tophat = grey.black_tophat(self.white_pixel, s) assert np.all(tophat == 0) + +class TestDTypes(): + + def setUp(self): + k = 5 + arrname = '%03i' % k + + self.disk = selem.disk(k) + + fname_opening = os.path.join(data_dir, "disk-open-matlab-output.npz") + self.expected_opening = np.load(fname_opening)[arrname] + + fname_closing = os.path.join(data_dir, "disk-close-matlab-output.npz") + self.expected_closing = np.load(fname_closing)[arrname] + + def _test_image(self, image): + result_opening = grey.opening(image, self.disk) + testing.assert_equal(result_opening, self.expected_opening) + + result_closing = grey.closing(image, self.disk) + testing.assert_equal(result_closing, self.expected_closing) + + def test_float(self): + image = skimage.img_as_float(lena) + self._test_image(image) + + @testing.decorators.skipif(True) + def test_int(self): + image = skimage.img_as_int(lena) + self._test_image(image) + + def test_uint(self): + image = skimage.img_as_uint(lena) + self._test_image(image) + + +if __name__ == '__main__': + testing.run_module_suite() +