mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-09 15:53:43 +08:00
Added new functionality to remove small holes from images.
This is currently working with **kwargs except for inplace which I cannot get working. It works with arrays of type int but returns an array of type bool. Possibly in future add labelling for arrays of type int. A UserWarning is produced when using arrays of type int which seems to work normally but the test created for this does not pick up the warning. Any assistance on these issues would be helpful. I started this at EuroScipy 2015 and this fixes issue #1642
This commit is contained in:
@@ -8,7 +8,7 @@ from .watershed import watershed
|
||||
from ._skeletonize import skeletonize, medial_axis
|
||||
from .convex_hull import convex_hull_image, convex_hull_object
|
||||
from .greyreconstruct import reconstruction
|
||||
from .misc import remove_small_objects
|
||||
from .misc import remove_small_objects, remove_small_holes
|
||||
|
||||
from ..measure._label import label
|
||||
from .._shared.utils import deprecated as _deprecated
|
||||
@@ -40,4 +40,5 @@ __all__ = ['binary_erosion',
|
||||
'convex_hull_image',
|
||||
'convex_hull_object',
|
||||
'reconstruction',
|
||||
'remove_small_objects']
|
||||
'remove_small_objects',
|
||||
'remove_small_holes']
|
||||
|
||||
@@ -124,3 +124,84 @@ def remove_small_objects(ar, min_size=64, connectivity=1, in_place=False):
|
||||
out[too_small_mask] = 0
|
||||
|
||||
return out
|
||||
|
||||
def remove_small_holes(ar, min_size=64, connectivity=1, in_place=False):
|
||||
"""Remove connected components smaller than the specified size within a
|
||||
larger connected object.
|
||||
|
||||
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
|
||||
labels are not kept in the output image (this function always outputs
|
||||
a bool image. It is suggested that labeling is completed after using
|
||||
this function.
|
||||
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
|
||||
------
|
||||
TypeError
|
||||
If the input array is of an invalid type, such as float or string.
|
||||
ValueError
|
||||
If the input array contains negative values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray, same shape and type as input `ar`
|
||||
The input array with small holes within connected components removed.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from skimage import morphology
|
||||
>>> a = np.array([[1, 1, 1, 1, 1, 0],
|
||||
... [1, 1, 1, 0, 1, 0],
|
||||
... [1, 0, 0, 1, 1, 0],
|
||||
... [1, 1, 1, 1, 1, 0]], bool)
|
||||
>>> b = morphology.remove_small_holes(a, 2)
|
||||
>>> b
|
||||
array([[True, True, True, True, True, False],
|
||||
[True, True, True, True, True, False],
|
||||
[True, False, False, True, True, False],
|
||||
[True, True, True, True, True, False]], dtype=bool)
|
||||
>>> c = morphology.remove_small_holes(a, 2, connectivity=2)
|
||||
>>> c
|
||||
array([[True, True, True, True, True, False],
|
||||
[True, True, True, False, True, False],
|
||||
[True, False, False, True, True, False],
|
||||
[True, True, True, True, True, False]], dtype=bool)
|
||||
>>> d = morphology.remove_small_holes(a, 2, in_place=True)
|
||||
>>> d is a
|
||||
True
|
||||
"""
|
||||
# Should use `issubdtype` for bool below, but there's a bug in numpy 1.7
|
||||
if not (ar.dtype == bool or np.issubdtype(ar.dtype, np.integer)):
|
||||
raise TypeError("Only bool or integer image types are supported. "
|
||||
"Got %s." % ar.dtype)
|
||||
|
||||
if in_place:
|
||||
out = ar
|
||||
else:
|
||||
out = ar.copy()
|
||||
|
||||
#Creates warning if image is an integer image
|
||||
if out.dtype != bool:
|
||||
print("I'm about to warn")
|
||||
warnings.warn("Any labeled images will be returned as a boolean array. "
|
||||
"Did you mean to use a boolean array?", UserWarning)
|
||||
|
||||
#Creating the inverse of ar
|
||||
out = np.logical_not(out)
|
||||
|
||||
#removing small objects from the inverse of ar
|
||||
out = remove_small_objects(out, min_size, connectivity, in_place)
|
||||
|
||||
out = np.logical_not(out)
|
||||
|
||||
return out
|
||||
@@ -1,7 +1,7 @@
|
||||
import numpy as np
|
||||
from numpy.testing import (assert_array_equal, assert_equal, assert_raises,
|
||||
assert_warns)
|
||||
from skimage.morphology import remove_small_objects
|
||||
from skimage.morphology import remove_small_objects, remove_small_holes
|
||||
|
||||
test_image = np.array([[0, 0, 0, 1, 0],
|
||||
[1, 1, 1, 0, 0],
|
||||
@@ -72,6 +72,101 @@ def test_negative_input():
|
||||
negative_int = np.random.randint(-4, -1, size=(5, 5))
|
||||
assert_raises(ValueError, remove_small_objects, negative_int)
|
||||
|
||||
test_holes_image = np.array([[0,0,0,0,0,0,1,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,0,0,1,1,0,0,0,0],
|
||||
[0,1,1,1,0,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,1,1,1],
|
||||
[0,0,0,0,0,0,0,1,0,1],
|
||||
[0,0,0,0,0,0,0,1,1,1]], bool)
|
||||
|
||||
def test_one_connectivity_holes():
|
||||
expected = np.array([[0,0,0,0,0,0,1,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,1,1,1],
|
||||
[0,0,0,0,0,0,0,1,1,1],
|
||||
[0,0,0,0,0,0,0,1,1,1]], bool)
|
||||
observed = remove_small_holes(test_holes_image, min_size=3)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_two_connectivity_holes():
|
||||
expected = np.array([[0,0,0,0,0,0,1,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,0,0,1,1,0,0,0,0],
|
||||
[0,1,1,1,0,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,1,1,1],
|
||||
[0,0,0,0,0,0,0,1,1,1],
|
||||
[0,0,0,0,0,0,0,1,1,1]], bool)
|
||||
observed = remove_small_holes(test_holes_image, min_size=3, connectivity=2)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
def test_in_place_holes():
|
||||
observed = remove_small_holes(test_holes_image, min_size=3, in_place=True)
|
||||
assert_equal(observed is test_holes_image, True,
|
||||
"remove_small_holes in_place argument failed.")
|
||||
|
||||
def test_labeled_image_holes():
|
||||
labeled_holes_image = np.array([[0,0,0,0,0,0,1,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,0,0,1,1,0,0,0,0],
|
||||
[0,1,1,1,0,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,2,2,2],
|
||||
[0,0,0,0,0,0,0,2,0,2],
|
||||
[0,0,0,0,0,0,0,2,2,2]], dtype=int)
|
||||
expected = np.array([[0,0,0,0,0,0,1,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,1,1,1],
|
||||
[0,0,0,0,0,0,0,1,1,1],
|
||||
[0,0,0,0,0,0,0,1,1,1]], dtype=bool)
|
||||
observed = remove_small_holes(labeled_holes_image, min_size=3)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_uint_image_holes():
|
||||
labeled_holes_image = np.array([[0,0,0,0,0,0,1,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,0,0,1,1,0,0,0,0],
|
||||
[0,1,1,1,0,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,2,2,2],
|
||||
[0,0,0,0,0,0,0,2,0,2],
|
||||
[0,0,0,0,0,0,0,2,2,2]], dtype=np.uint8)
|
||||
expected = np.array([[0,0,0,0,0,0,1,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,1,1,1],
|
||||
[0,0,0,0,0,0,0,1,1,1],
|
||||
[0,0,0,0,0,0,0,1,1,1]], dtype=bool)
|
||||
observed = remove_small_holes(labeled_holes_image, min_size=3)
|
||||
assert_array_equal(observed, expected)
|
||||
|
||||
|
||||
def test_label_warning_holes():
|
||||
labeled_holes_image = np.array([[0,0,0,0,0,0,1,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,1,0,0,1,1,0,0,0,0],
|
||||
[0,1,1,1,0,1,0,0,0,0],
|
||||
[0,1,1,1,1,1,0,0,0,0],
|
||||
[0,0,0,0,0,0,0,2,2,2],
|
||||
[0,0,0,0,0,0,0,2,0,2],
|
||||
[0,0,0,0,0,0,0,2,2,2]], dtype=int)
|
||||
assert_warns(UserWarning, remove_small_holes, labeled_holes_image, min_size=3)
|
||||
|
||||
def test_float_input_holes():
|
||||
float_test = np.random.rand(5, 5)
|
||||
assert_raises(TypeError, remove_small_holes, float_test)
|
||||
|
||||
if __name__ == "__main__":
|
||||
np.testing.run_module_suite()
|
||||
|
||||
Reference in New Issue
Block a user