diff --git a/skimage/segmentation/__init__.py b/skimage/segmentation/__init__.py index 69a580c6..9dca2bc3 100644 --- a/skimage/segmentation/__init__.py +++ b/skimage/segmentation/__init__.py @@ -3,3 +3,4 @@ from ._felzenszwalb import felzenszwalb from ._slic import slic from ._quickshift import quickshift from .boundaries import find_boundaries, visualize_boundaries +from ._clear_border import clear_border diff --git a/skimage/segmentation/_clear_border.py b/skimage/segmentation/_clear_border.py new file mode 100644 index 00000000..266e17e2 --- /dev/null +++ b/skimage/segmentation/_clear_border.py @@ -0,0 +1,69 @@ +import numpy as np +from scipy.ndimage import label + + +def clear_border(image, buffer_size=0, bgval=0): + """Clear objects connected to image border. + + The changes will be applied to the input image. + + Parameters + ---------- + image : (N, M) array + Binary image. + buffer_size : int, optional + Define additional buffer around image border. + bgval : float or int, optional + Value for cleared objects. + + Returns + ------- + image : (N, M) array + Cleared binary image. + + Examples + -------- + >>> import numpy as np + >>> from skimage.segmentation import clear_border + >>> image = np.array([[0, 0, 0, 0, 0, 0, 0, 1, 0], + ... [0, 0, 0, 0, 1, 0, 0, 0, 0], + ... [1, 0, 0, 1, 0, 1, 0, 0, 0], + ... [0, 0, 1, 1, 1, 1, 1, 0, 0], + ... [0, 1, 1, 1, 1, 1, 1, 1, 0], + ... [0, 0, 0, 0, 0, 0, 0, 0, 0]]) + >>> clear_border(image) + array([[0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 1, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0]]) + + """ + + rows, cols = image.shape + if buffer_size >= rows or buffer_size >= cols: + raise ValueError("buffer size may not be greater than image size") + + # create borders with buffer_size + borders = np.zeros_like(image, dtype=np.bool_) + ext = buffer_size + 1 + borders[:ext] = True + borders[- ext:] = True + borders[:, :ext] = True + borders[:, - ext:] = True + + labels, number = label(image) + + # determine all objects that are connected to borders + borders_indices = np.unique(labels[borders]) + indices = np.arange(number + 1) + # mask all label indices that are connected to borders + label_mask = np.in1d(indices, borders_indices) + # create mask for pixels to clear + mask = label_mask[labels.ravel()].reshape(labels.shape) + + # clear border pixels + image[mask] = bgval + + return image diff --git a/skimage/segmentation/tests/test_clear_border.py b/skimage/segmentation/tests/test_clear_border.py new file mode 100644 index 00000000..d87f3d25 --- /dev/null +++ b/skimage/segmentation/tests/test_clear_border.py @@ -0,0 +1,32 @@ +import numpy as np +from numpy.testing import assert_array_equal, assert_equal +from skimage.segmentation import clear_border + + +def test_clear_border(): + image = np.array( + [[0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0], + [1, 0, 0, 1, 0, 1, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0]]) + + # test default case + result = clear_border(image.copy()) + ref = image.copy() + ref[2, 0] = 0 + ref[0, -2] = 0 + assert_array_equal(result, ref) + + # test buffer + result = clear_border(image.copy(), 1) + assert_array_equal(result, np.zeros(result.shape)) + + # test background value + result = clear_border(image.copy(), 1, 2) + assert_array_equal(result, 2 * np.ones_like(image)) + + +if __name__ == "__main__": + np.testing.run_module_suite()