Add default structuring element to morphology

This commit is contained in:
Nelson Brown
2014-07-11 13:50:55 -07:00
parent 1c27a97d26
commit bb732c9225
5 changed files with 124 additions and 13 deletions
+15 -4
View File
@@ -1,9 +1,10 @@
import warnings
import numpy as np
from scipy import ndimage
from .selem import _default_selem
def binary_erosion(image, selem, out=None):
def binary_erosion(image, selem=None, out=None):
"""Return fast binary morphological erosion of an image.
This function returns the same result as greyscale erosion but performs
@@ -29,6 +30,11 @@ def binary_erosion(image, selem, out=None):
The result of the morphological erosion with values in ``[0, 1]``.
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
selem = (selem != 0)
selem_sum = np.sum(selem)
@@ -45,7 +51,7 @@ def binary_erosion(image, selem, out=None):
return np.equal(conv, selem_sum, out=out)
def binary_dilation(image, selem, out=None):
def binary_dilation(image, selem=None, out=None):
"""Return fast binary morphological dilation of an image.
This function returns the same result as greyscale dilation but performs
@@ -72,6 +78,11 @@ def binary_dilation(image, selem, out=None):
The result of the morphological dilation with values in ``[0, 1]``.
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
selem = (selem != 0)
if np.sum(selem) <= 255:
@@ -87,7 +98,7 @@ def binary_dilation(image, selem, out=None):
return np.not_equal(conv, 0, out=out)
def binary_opening(image, selem, out=None):
def binary_opening(image, selem=None, out=None):
"""Return fast binary morphological opening of an image.
This function returns the same result as greyscale opening but performs
@@ -119,7 +130,7 @@ def binary_opening(image, selem, out=None):
return out
def binary_closing(image, selem, out=None):
def binary_closing(image, selem=None, out=None):
"""Return fast binary morphological closing of an image.
This function returns the same result as greyscale closing but performs
+37 -9
View File
@@ -1,5 +1,8 @@
import warnings
from skimage import img_as_ubyte
from scipy import ndimage
from .selem import _default_selem
from . import cmorph
@@ -8,7 +11,7 @@ __all__ = ['erosion', 'dilation', 'opening', 'closing', 'white_tophat',
'black_tophat']
def erosion(image, selem, out=None, shift_x=False, shift_y=False):
def erosion(image, selem=None, 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
@@ -21,7 +24,7 @@ def erosion(image, selem, out=None, shift_x=False, shift_y=False):
Image array.
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
out : ndarrays
The array to store the result of the morphology. If None is
passed, a new array will be allocated.
shift_x, shift_y : bool
@@ -52,6 +55,10 @@ def erosion(image, selem, out=None, shift_x=False, shift_y=False):
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
if image is out:
raise NotImplementedError("In-place erosion not supported!")
image = img_as_ubyte(image)
@@ -60,7 +67,7 @@ def erosion(image, selem, out=None, shift_x=False, shift_y=False):
shift_x=shift_x, shift_y=shift_y)
def dilation(image, selem, out=None, shift_x=False, shift_y=False):
def dilation(image, selem=None, 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
@@ -105,6 +112,10 @@ def dilation(image, selem, out=None, shift_x=False, shift_y=False):
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
if image is out:
raise NotImplementedError("In-place dilation not supported!")
image = img_as_ubyte(image)
@@ -113,7 +124,7 @@ def dilation(image, selem, out=None, shift_x=False, shift_y=False):
shift_x=shift_x, shift_y=shift_y)
def opening(image, selem, out=None):
def opening(image, selem=None, out=None):
"""Return greyscale morphological opening of an image.
The morphological opening on an image is defined as an erosion followed by
@@ -154,7 +165,11 @@ def opening(image, selem, out=None):
[0, 0, 0, 0, 0]], dtype=uint8)
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
h, w = selem.shape
shift_x = True if (w % 2) == 0 else False
shift_y = True if (h % 2) == 0 else False
@@ -164,7 +179,7 @@ def opening(image, selem, out=None):
return out
def closing(image, selem, out=None):
def closing(image, selem=None, out=None):
"""Return greyscale morphological closing of an image.
The morphological closing on an image is defined as a dilation followed by
@@ -206,6 +221,10 @@ def closing(image, selem, out=None):
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
h, w = selem.shape
shift_x = True if (w % 2) == 0 else False
shift_y = True if (h % 2) == 0 else False
@@ -215,7 +234,7 @@ def closing(image, selem, out=None):
return out
def white_tophat(image, selem, out=None):
def white_tophat(image, selem=None, out=None):
"""Return white top hat of an image.
The white top hat of an image is defined as the image minus its
@@ -254,7 +273,12 @@ def white_tophat(image, selem, out=None):
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]], dtype=uint8)
"""
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
if image is out:
raise NotImplementedError("Cannot perform white top hat in place.")
@@ -263,7 +287,7 @@ def white_tophat(image, selem, out=None):
return out
def black_tophat(image, selem, out=None):
def black_tophat(image, selem=None, out=None):
"""Return black top hat of an image.
The black top hat of an image is defined as its morphological closing minus
@@ -305,6 +329,10 @@ def black_tophat(image, selem, out=None):
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
if image is out:
raise NotImplementedError("Cannot perform white top hat in place.")
+21
View File
@@ -4,6 +4,7 @@
"""
import numpy as np
from scipy import ndimage
def square(width, dtype=np.uint8):
@@ -290,3 +291,23 @@ def star(a, dtype=np.uint8):
selem = selem_square + selem_rotated
selem[selem > 0] = 1
return selem.astype(dtype)
def _default_selem(ndim):
"""
Generates a cross-shaped structuring element (connectivity=1). This is the
default structuring element (selem) if no selem was specified.
Parameters
----------
ndim : int
Number of dimensions of the image.
Returns
-------
selem : ndarray
The structuring element where elements of the neighborhood
are 1 and 0 otherwise.
"""
return ndimage.morphology.generate_binary_structure(ndim, 1)
+25
View File
@@ -64,5 +64,30 @@ def test_out_argument():
testing.assert_(np.any(out != out_saved))
testing.assert_array_equal(out, func(img, strel))
def test_default_selem():
functions = [binary.binary_erosion, binary.binary_dilation,
binary.binary_opening, binary.binary_closing]
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)
for function in functions:
im_expected = function(image, strel)
im_test = function(image)
yield testing.assert_array_equal, im_expected, im_test
if __name__ == '__main__':
testing.run_module_suite()
+26
View File
@@ -119,7 +119,33 @@ class TestEccentricStructuringElements():
tophat = grey.black_tophat(self.white_pixel, s)
assert np.all(tophat == 0)
def test_default_selem():
functions = [grey.erosion, grey.dilation,
grey.opening, grey.closing,
grey.white_tophat, grey.black_tophat]
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)
for function in functions:
im_expected = function(image, strel)
im_test = function(image)
yield testing.assert_array_equal, im_expected, im_test
class TestDTypes():
def setUp(self):