mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-04 03:53:26 +08:00
Merge pull request #778 from stefanv/binary_morph_out
Simplify output handling for binary morphology.
This commit is contained in:
@@ -3,67 +3,46 @@ import numpy as np
|
||||
from scipy import ndimage
|
||||
|
||||
|
||||
def _convolve(image, selem, out, cval):
|
||||
|
||||
# determine the smallest integer dtype which does not overflow
|
||||
selem = selem != 0
|
||||
selem_sum = np.sum(selem)
|
||||
if selem_sum < 2 ** 8:
|
||||
out_dtype = np.uint8
|
||||
else:
|
||||
out_dtype = np.intp
|
||||
|
||||
if out is None:
|
||||
out = np.zeros_like(image, dtype=out_dtype)
|
||||
else:
|
||||
warnings.warn('Parameter `out` is deprecated and it does not equal '
|
||||
'the output image if the sum of the structuring element '
|
||||
'overflows the dtype of `out`.')
|
||||
iinfo = np.iinfo(out.dtype)
|
||||
if iinfo.max - iinfo.min < selem_sum:
|
||||
raise ValueError('Sum of structuring (=%d) element results in '
|
||||
'overflow for dtype of `out`. You must raise the '
|
||||
'bit-depth.')
|
||||
|
||||
conv = ndimage.convolve(image > 0, selem, output=out,
|
||||
mode='constant', cval=cval)
|
||||
|
||||
if conv is not None:
|
||||
out = conv
|
||||
|
||||
return out, selem_sum
|
||||
|
||||
|
||||
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.
|
||||
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.
|
||||
Binary input image.
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
out : ndarray
|
||||
out : ndarray of bool
|
||||
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.
|
||||
eroded : ndarray of bool or intp
|
||||
The result of the morphological erosion with values in ``[0, 1]``.
|
||||
|
||||
"""
|
||||
selem = (selem != 0)
|
||||
selem_sum = np.sum(selem)
|
||||
|
||||
out, selem_sum = _convolve(image, selem, out, 1)
|
||||
return np.array(np.equal(out, selem_sum, out=out), dtype=np.bool,
|
||||
copy=False)
|
||||
if selem_sum <= 255:
|
||||
conv = np.empty_like(image, dtype=np.uint8)
|
||||
else:
|
||||
conv = np.empty_like(image, dtype=np.intp)
|
||||
|
||||
binary = (image > 0).view(np.uint8)
|
||||
ndimage.convolve(binary, selem, mode='constant', cval=1, output=conv)
|
||||
|
||||
if out is None:
|
||||
out = conv
|
||||
return np.equal(conv, selem_sum, out=out)
|
||||
|
||||
|
||||
def binary_dilation(image, selem, out=None):
|
||||
@@ -72,30 +51,40 @@ def binary_dilation(image, selem, out=None):
|
||||
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.
|
||||
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.
|
||||
Binary input image.
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
out : ndarray
|
||||
out : ndarray of bool
|
||||
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.
|
||||
dilated : ndarray of bool or intp
|
||||
The result of the morphological dilation with values in ``[0, 1]``.
|
||||
|
||||
"""
|
||||
selem = (selem != 0)
|
||||
|
||||
out, _ = _convolve(image, selem, out, 0)
|
||||
return np.array(np.not_equal(out, 0, out=out), dtype=np.bool, copy=False)
|
||||
if np.sum(selem) <= 255:
|
||||
conv = np.empty_like(image, dtype=np.uint8)
|
||||
else:
|
||||
conv = np.empty_like(image, dtype=np.intp)
|
||||
|
||||
binary = (image > 0).view(np.uint8)
|
||||
ndimage.convolve(binary, selem, mode='constant', cval=0, output=conv)
|
||||
|
||||
if out is None:
|
||||
out = conv
|
||||
return np.not_equal(conv, 0, out=out)
|
||||
|
||||
|
||||
def binary_opening(image, selem, out=None):
|
||||
@@ -112,20 +101,19 @@ def binary_opening(image, selem, out=None):
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Image array.
|
||||
Binary input image.
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
out : ndarray
|
||||
out : ndarray of bool
|
||||
The array to store the result of the morphology. If None
|
||||
is passed, a new array will be allocated.
|
||||
|
||||
Returns
|
||||
-------
|
||||
opening : bool array
|
||||
opening : ndarray of bool
|
||||
The result of the morphological opening.
|
||||
|
||||
"""
|
||||
|
||||
eroded = binary_erosion(image, selem)
|
||||
out = binary_dilation(eroded, selem, out=out)
|
||||
return out
|
||||
@@ -145,16 +133,16 @@ def binary_closing(image, selem, out=None):
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Image array.
|
||||
Binary input image.
|
||||
selem : ndarray
|
||||
The neighborhood expressed as a 2-D array of 1's and 0's.
|
||||
out : ndarray
|
||||
out : ndarray of bool
|
||||
The array to store the result of the morphology. If None,
|
||||
is passed, a new array will be allocated.
|
||||
|
||||
Returns
|
||||
-------
|
||||
closing : bool array
|
||||
closing : ndarray of bool
|
||||
The result of the morphological closing.
|
||||
|
||||
"""
|
||||
|
||||
@@ -17,27 +17,6 @@ def test_non_square_image():
|
||||
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))
|
||||
img[2:19, 2:19] = 1
|
||||
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_selem_overflow_exception():
|
||||
strel = np.ones((17, 17), dtype=np.uint8)
|
||||
img = np.zeros((20, 20))
|
||||
img[2:19, 2:19] = 1
|
||||
out = np.zeros((20, 20), dtype=np.uint8)
|
||||
testing.assert_raises(ValueError, binary.binary_erosion, img, strel, out)
|
||||
out = np.zeros((20, 20), dtype=np.uint16)
|
||||
binary_res = binary.binary_erosion(img, strel, out=out)
|
||||
grey_res = img_as_bool(grey.erosion(img, strel))
|
||||
testing.assert_array_equal(binary_res, grey_res)
|
||||
|
||||
|
||||
def test_binary_erosion():
|
||||
strel = selem.square(3)
|
||||
binary_res = binary.binary_erosion(bw_lena, strel)
|
||||
@@ -66,5 +45,24 @@ def test_binary_opening():
|
||||
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))
|
||||
img[2:19, 2:19] = 1
|
||||
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))
|
||||
|
||||
if __name__ == '__main__':
|
||||
testing.run_module_suite()
|
||||
|
||||
Reference in New Issue
Block a user