Add fallback decorator for 3D images

We don't support images greater than 2D, so fall back on ndimage
This commit is contained in:
Nelson Brown
2014-07-12 15:22:48 -07:00
parent 9cd276f754
commit 2b91c259d6
5 changed files with 71 additions and 38 deletions
+5 -8
View File
@@ -2,8 +2,10 @@ import warnings
import numpy as np
from scipy import ndimage
from .selem import _default_selem
from .misc import default_fallback
@default_fallback
def binary_erosion(image, selem=None, out=None):
"""Return fast binary morphological erosion of an image.
@@ -32,10 +34,6 @@ def binary_erosion(image, selem=None, out=None):
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
selem = (selem != 0)
selem_sum = np.sum(selem)
@@ -52,6 +50,7 @@ def binary_erosion(image, selem=None, out=None):
return np.equal(conv, selem_sum, out=out)
@default_fallback
def binary_dilation(image, selem=None, out=None):
"""Return fast binary morphological dilation of an image.
@@ -81,10 +80,6 @@ def binary_dilation(image, selem=None, out=None):
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
selem = (selem != 0)
if np.sum(selem) <= 255:
@@ -100,6 +95,7 @@ def binary_dilation(image, selem=None, out=None):
return np.not_equal(conv, 0, out=out)
@default_fallback
def binary_opening(image, selem=None, out=None):
"""Return fast binary morphological opening of an image.
@@ -133,6 +129,7 @@ def binary_opening(image, selem=None, out=None):
return out
@default_fallback
def binary_closing(image, selem=None, out=None):
"""Return fast binary morphological closing of an image.
+14 -23
View File
@@ -2,7 +2,7 @@ import warnings
from skimage import img_as_ubyte
from scipy import ndimage
from .selem import _default_selem
from .misc import default_fallback
from . import cmorph
@@ -11,6 +11,7 @@ __all__ = ['erosion', 'dilation', 'opening', 'closing', 'white_tophat',
'black_tophat']
@default_fallback
def erosion(image, selem=None, out=None, shift_x=False, shift_y=False):
"""Return greyscale morphological erosion of an image.
@@ -56,9 +57,9 @@ def erosion(image, selem=None, out=None, shift_x=False, shift_y=False):
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
# If image has more than 2 dimensions, use scipy.ndimage
if image.ndim > 2:
return ndimage.morphology.grey_erosion(image, footprint=selem, out=out)
if image is out:
raise NotImplementedError("In-place erosion not supported!")
@@ -68,6 +69,7 @@ def erosion(image, selem=None, out=None, shift_x=False, shift_y=False):
shift_x=shift_x, shift_y=shift_y)
@default_fallback
def dilation(image, selem=None, out=None, shift_x=False, shift_y=False):
"""Return greyscale morphological dilation of an image.
@@ -114,18 +116,20 @@ def dilation(image, selem=None, out=None, shift_x=False, shift_y=False):
"""
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
# If image has more than 2 dimensions, use scipy.ndimage
if image.ndim > 2:
return ndimage.morphology.grey_dilation(image, footprint=selem,out=out)
if image is out:
raise NotImplementedError("In-place dilation not supported!")
image = img_as_ubyte(image)
selem = img_as_ubyte(selem)
return cmorph._dilate(image, selem, out=out,
shift_x=shift_x, shift_y=shift_y)
@default_fallback
def opening(image, selem=None, out=None):
"""Return greyscale morphological opening of an image.
@@ -169,10 +173,6 @@ def opening(image, selem=None, 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
@@ -182,6 +182,7 @@ def opening(image, selem=None, out=None):
return out
@default_fallback
def closing(image, selem=None, out=None):
"""Return greyscale morphological closing of an image.
@@ -225,10 +226,6 @@ def closing(image, selem=None, 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
@@ -238,6 +235,7 @@ def closing(image, selem=None, out=None):
return out
@default_fallback
def white_tophat(image, selem=None, out=None):
"""Return white top hat of an image.
@@ -280,10 +278,6 @@ def white_tophat(image, selem=None, 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.")
@@ -292,6 +286,7 @@ def white_tophat(image, selem=None, out=None):
return out
@default_fallback
def black_tophat(image, selem=None, out=None):
"""Return black top hat of an image.
@@ -335,10 +330,6 @@ def black_tophat(image, selem=None, 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.")
+28
View File
@@ -1,5 +1,33 @@
import numpy as np
import scipy.ndimage as nd
from .selem import _default_selem
skimage2ndimage = {x: 'grey_' + x
for x in ('erosion','dilation','opening','closing')}
skimage2ndimage.update({x: x
for x in ('binary_erosion','binary_dilation',
'binary_opening','binary_closing',
'black_tophat','white_tophat')})
def default_fallback(func):
def func_out(image, selem=None, out=None, **kwargs):
# Default structure element
if selem is None:
selem = _default_selem(image.ndim)
# If image has more than 2 dimensions, use scipy.ndimage
if image.ndim > 2:
function = getattr(nd, skimage2ndimage[func.__name__])
try:
return function(image, footprint=selem, output=out, **kwargs)
except TypeError:
# nd.binary_* take structure instead of footprint
return function(image, structure=selem, output=out, **kwargs)
else:
return func(image, selem=selem, out=out, **kwargs)
return func_out
def remove_small_objects(ar, min_size=64, connectivity=1, in_place=False):
-7
View File
@@ -311,10 +311,3 @@ def _default_selem(ndim):
"""
return ndimage.morphology.generate_binary_structure(ndim, 1)
+24
View File
@@ -142,6 +142,30 @@ def test_default_selem():
im_test = function(image)
yield 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 = morphology.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] = ndimage.generate_binary_structure(3, 1)
testing.assert_array_equal(opened, image_expected)
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
cube = np.ones((3, 3, 3),dtype=np.uint8)
for function in [grey.closing, grey.opening]:
new_image = function(image, cube)
yield testing.assert_array_equal, new_image, image
class TestDTypes():
def setUp(self):