mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-06 05:00:20 +08:00
Merge pull request #446 from jni/morphology-functions
Morphology functions
This commit is contained in:
@@ -90,12 +90,8 @@ plt.title('Filling the holes')
|
||||
Small spurious objects are easily removed by setting a minimum size for valid
|
||||
objects.
|
||||
"""
|
||||
|
||||
label_objects, nb_labels = ndimage.label(fill_coins)
|
||||
sizes = np.bincount(label_objects.ravel())
|
||||
mask_sizes = sizes > 20
|
||||
mask_sizes[0] = 0
|
||||
coins_cleaned = mask_sizes[label_objects]
|
||||
from skimage import morphology
|
||||
coins_cleaned = morphology.remove_small_objects(fill_coins, 21)
|
||||
|
||||
plt.figure(figsize=(4, 3))
|
||||
plt.imshow(coins_cleaned, cmap=plt.cm.gray, interpolation='nearest')
|
||||
@@ -149,8 +145,7 @@ plt.title('markers')
|
||||
Finally, we use the watershed transform to fill regions of the elevation map starting from the markers determined above:
|
||||
|
||||
"""
|
||||
from skimage.morphology import watershed
|
||||
segmentation = watershed(elevation_map, markers)
|
||||
segmentation = morphology.watershed(elevation_map, markers)
|
||||
|
||||
plt.figure(figsize=(4, 3))
|
||||
plt.imshow(segmentation, cmap=plt.cm.gray, interpolation='nearest')
|
||||
|
||||
@@ -7,3 +7,4 @@ from .watershed import watershed, is_local_maximum
|
||||
from ._skeletonize import skeletonize, medial_axis
|
||||
from .convex_hull import convex_hull_image
|
||||
from .greyreconstruct import reconstruction
|
||||
from .misc import remove_small_objects
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import numpy as np
|
||||
import scipy.ndimage as nd
|
||||
|
||||
def remove_small_objects(ar, min_size=64, connectivity=1, in_place=False):
|
||||
"""Remove connected components smaller than the specified size.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ar : ndarray (arbitrary shape, int or bool type)
|
||||
The array containing the connected components of interest. If the array
|
||||
type is int, it is assumed that it contains already-labeled objects.
|
||||
The ints must be non-negative.
|
||||
min_size : int, optional (default: 64)
|
||||
The smallest allowable connected component size.
|
||||
connectivity : int, {1, 2, ..., ar.ndim}, optional (default: 1)
|
||||
The connectivity defining the neighborhood of a pixel.
|
||||
in_place : bool, optional (default: False)
|
||||
If `True`, remove the connected components in the input array itself.
|
||||
Otherwise, make a copy.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If the input array is of int type but contains negative values.
|
||||
TypeError
|
||||
If the input array is of an invalid type, such as float or string.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray, same shape and type as input `ar`
|
||||
The input array with small connected components removed.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from skimage import morphology
|
||||
>>> from scipy import ndimage as nd
|
||||
>>> a = np.array([[0, 0, 0, 1, 0],
|
||||
... [1, 1, 1, 0, 0],
|
||||
... [1, 1, 1, 0, 1]], bool)
|
||||
>>> b = morphology.remove_small_connected_components(a, 6)
|
||||
>>> b
|
||||
array([[False, False, False, False, False],
|
||||
[ True, True, True, False, False],
|
||||
[ True, True, True, False, False]], dtype=bool)
|
||||
>>> c = morphology.remove_small_connected_components(a, 7, connectivity=2)
|
||||
>>> c
|
||||
array([[False, False, False, True, False],
|
||||
[ True, True, True, False, False],
|
||||
[ True, True, True, False, False]], dtype=bool)
|
||||
>>> d = morphology.remove_small_connected_components(a, 6, in_place=True)
|
||||
>>> d is a
|
||||
True
|
||||
"""
|
||||
errmsg = "Only numpy.ndarrays of bool or integer type are supported. "
|
||||
if type(ar) != np.ndarray:
|
||||
raise TypeError(errmsg + "Got a %s." % type(ar))
|
||||
elif ar.dtype != bool and not np.issubdtype(ar.dtype, np.integer):
|
||||
raise TypeError(errmsg + "Got a numpy.ndarray of type %s" % ar.dtype)
|
||||
if in_place:
|
||||
out = ar
|
||||
else:
|
||||
out = ar.copy()
|
||||
if min_size == 0: # shortcut for efficiency
|
||||
return out
|
||||
if out.dtype == bool:
|
||||
selem = nd.generate_binary_structure(ar.ndim, connectivity)
|
||||
ccs = nd.label(ar, selem)[0]
|
||||
else:
|
||||
ccs = out
|
||||
try:
|
||||
component_sizes = np.bincount(ccs.ravel())
|
||||
except ValueError:
|
||||
raise ValueError("Negative value labels are not supported. Try "
|
||||
"relabeling the input with `scipy.ndimage.label`.")
|
||||
too_small = component_sizes < min_size
|
||||
too_small_mask = too_small[ccs]
|
||||
out[too_small_mask] = 0
|
||||
return out
|
||||
@@ -0,0 +1,56 @@
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_equal, assert_equal, assert_raises
|
||||
from skimage.morphology import remove_small_objects
|
||||
|
||||
test_image = np.array([[0, 0, 0, 1, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 1]], bool)
|
||||
|
||||
|
||||
def test_one_connectivity():
|
||||
expected = np.array([[0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 0]], bool)
|
||||
observed = remove_small_objects(test_image, min_size=6)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_two_connectivity():
|
||||
expected = np.array([[0, 0, 0, 1, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 0, 0]], bool)
|
||||
observed = remove_small_objects(test_image, min_size=7, connectivity=2)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_in_place():
|
||||
observed = remove_small_objects(test_image, min_size=6, in_place=True)
|
||||
assert_equal(observed is test_image, True,
|
||||
"remove_small_objects in_place argument failed.")
|
||||
|
||||
|
||||
def test_labeled_image():
|
||||
labeled_image = np.array([[2, 2, 2, 0, 1],
|
||||
[2, 2, 2, 0, 1],
|
||||
[2, 0, 0, 0, 0],
|
||||
[0, 0, 3, 3, 3]], dtype=int)
|
||||
expected = np.array([[2, 2, 2, 0, 0],
|
||||
[2, 2, 2, 0, 0],
|
||||
[2, 0, 0, 0, 0],
|
||||
[0, 0, 3, 3, 3]], dtype=int)
|
||||
observed = remove_small_objects(labeled_image, min_size=3)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_float_input():
|
||||
float_test = np.random.rand(5, 5)
|
||||
assert_raises(TypeError, remove_small_objects, float_test)
|
||||
|
||||
|
||||
def test_negative_input():
|
||||
negative_int = np.random.randint(-4, -1, size=(5, 5))
|
||||
assert_raises(ValueError, remove_small_objects, negative_int)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
np.testing.run_module_suite()
|
||||
Reference in New Issue
Block a user