From de47332bd2882edc7325830888e753d068633157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 2 Sep 2012 13:25:52 +0200 Subject: [PATCH] Add fast morphological operations for binary images --- skimage/morphology/__init__.py | 2 + skimage/morphology/binary.py | 133 ++++++++++++++++++++++++++ skimage/morphology/tests/test_grey.py | 32 ++++++- 3 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 skimage/morphology/binary.py diff --git a/skimage/morphology/__init__.py b/skimage/morphology/__init__.py index efa2077d..d4c775eb 100644 --- a/skimage/morphology/__init__.py +++ b/skimage/morphology/__init__.py @@ -1,3 +1,5 @@ +from .binary import (binary_erosion, binary_dilation, binary_opening, + binary_closing) from .grey import * from .selem import * from .ccomp import label diff --git a/skimage/morphology/binary.py b/skimage/morphology/binary.py new file mode 100644 index 00000000..768472d3 --- /dev/null +++ b/skimage/morphology/binary.py @@ -0,0 +1,133 @@ +import numpy as np +from scipy import ndimage + + +def binary_erosion(image, selem, out=None): + """Return fast binary morphological erosion of an image. + + This function returns the same result as greyscale erosion but performs + faster for binary images. + + Morphological erosion sets a pixel at (i,j) to the minimum over all pixels + in the neighborhood centered at (i,j). Erosion shrinks bright regions and + enlarges dark regions. + + Parameters + ---------- + image : ndarray + Image array. + selem : ndarray + The neighborhood expressed as a 2-D array of 1's and 0's. + out : ndarray + The array to store the result of the morphology. If None is + passed, a new array will be allocated. + + Returns + ------- + eroded : bool array + The result of the morphological erosion. + + """ + + conv = ndimage.convolve(image > 0, selem, output=out, + mode='constant', cval=1) + return conv == np.sum(selem) + + +def binary_dilation(image, selem, out=None): + """Return fast binary morphological dilation of an image. + + This function returns the same result as greyscale dilation but performs + faster for binary images. + + Morphological dilation sets a pixel at (i,j) to the maximum over all pixels + in the neighborhood centered at (i,j). Dilation enlarges bright regions + and shrinks dark regions. + + Parameters + ---------- + + image : ndarray + Image array. + selem : ndarray + The neighborhood expressed as a 2-D array of 1's and 0's. + out : ndarray + The array to store the result of the morphology. If None, is + passed, a new array will be allocated. + + Returns + ------- + dilated : bool array + The result of the morphological dilation. + + """ + + conv = ndimage.convolve(image > 0, selem, output=out, + mode='constant', cval=1) + return conv != 0 + + +def binary_opening(image, selem, out=None): + """Return fast binary morphological opening of an image. + + This function returns the same result as greyscale opening but performs + faster for binary images. + + The morphological opening on an image is defined as an erosion followed by + a dilation. Opening can remove small bright spots (i.e. "salt") and connect + small dark cracks. This tends to "open" up (dark) gaps between (bright) + features. + + Parameters + ---------- + image : ndarray + Image array. + selem : ndarray + The neighborhood expressed as a 2-D array of 1's and 0's. + out : ndarray + The array to store the result of the morphology. If None + is passed, a new array will be allocated. + + Returns + ------- + opening : bool array + The result of the morphological opening. + + """ + + eroded = binary_erosion(image, selem) + out = binary_dilation(eroded, selem, out=out) + return out + + +def binary_closing(image, selem, out=None): + """Return fast binary morphological closing of an image. + + This function returns the same result as greyscale closing but performs + faster for binary images. + + The morphological closing on an image is defined as a dilation followed by + an erosion. Closing can remove small dark spots (i.e. "pepper") and connect + small bright cracks. This tends to "close" up (dark) gaps between (bright) + features. + + Parameters + ---------- + image : ndarray + Image array. + selem : ndarray + The neighborhood expressed as a 2-D array of 1's and 0's. + out : ndarray + The array to store the result of the morphology. If None, + is passed, a new array will be allocated. + + Returns + ------- + closing : bool array + The result of the morphological closing. + + """ + + dilated = binary_dilation(image, selem) + out = binary_erosion(dilated, selem, out=out) + return out diff --git a/skimage/morphology/tests/test_grey.py b/skimage/morphology/tests/test_grey.py index d7242e8f..5d5b6c53 100644 --- a/skimage/morphology/tests/test_grey.py +++ b/skimage/morphology/tests/test_grey.py @@ -5,11 +5,11 @@ from numpy import testing import skimage from skimage import data_dir -from skimage.morphology import grey -from skimage.morphology import selem +from skimage.morphology import binary, grey, selem lena = np.load(os.path.join(data_dir, 'lena_GRAY_U8.npy')) +bw_lena = lena > 0.4 class TestMorphology(): @@ -154,5 +154,33 @@ class TestDTypes(): self._test_image(image) +def test_binary_erosion(): + strel = selem.square(3) + binary_res = binary.binary_erosion(bw_lena, strel) + grey_res = grey.erosion(bw_lena, strel) + assert np.all(binary_res == grey_res) + + +def test_binary_dilation(): + strel = selem.square(3) + binary_res = binary.binary_dilation(bw_lena, strel) + grey_res = grey.dilation(bw_lena, strel) + assert np.all(binary_res == grey_res) + + +def test_binary_closing(): + strel = selem.square(3) + binary_res = binary.binary_closing(bw_lena, strel) + grey_res = grey.closing(bw_lena, strel) + assert np.all(binary_res == grey_res) + + +def test_binary_opening(): + strel = selem.square(3) + binary_res = binary.binary_opening(bw_lena, strel) + grey_res = grey.opening(bw_lena, strel) + assert np.all(binary_res == grey_res) + + if __name__ == '__main__': testing.run_module_suite()