From b1891dc24e8b3d6ab26221dfc521ee9d4d34d57b Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Thu, 8 Jan 2015 17:00:06 +1100 Subject: [PATCH] Make find_boundaries symmetric Fixes #738 --- skimage/segmentation/boundaries.py | 33 +++++++++++--- skimage/segmentation/tests/test_boundaries.py | 43 ++++++++++--------- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/skimage/segmentation/boundaries.py b/skimage/segmentation/boundaries.py index 8e4ef32e..11773b1c 100644 --- a/skimage/segmentation/boundaries.py +++ b/skimage/segmentation/boundaries.py @@ -1,15 +1,34 @@ import numpy as np -from ..morphology import dilation, square +from scipy import ndimage as nd +from ..morphology import dilation, erosion, square from ..util import img_as_float from ..color import gray2rgb from .._shared.utils import deprecated -def find_boundaries(label_img): - """Return bool array where boundaries between labeled regions are True.""" - boundaries = np.zeros(label_img.shape, dtype=np.bool) - boundaries[1:, :] += label_img[1:, :] != label_img[:-1, :] - boundaries[:, 1:] += label_img[:, 1:] != label_img[:, :-1] +def find_boundaries(label_img, connectivity=1): + """Return bool array where boundaries between labeled regions are True. + + Parameters + ---------- + label_img : array of int + An array in which different regions are labeled with different + integers. + connectivity: int in {1, ..., `label_img.ndim`}, optional + A pixel is considered a boundary pixel if any of its neighbors + has a different label. `connectivity` controls which pixels are + considered neighbors. A connectivity of 1 (default) means + pixels sharing an edge (in 2D) or a face (in 3D) will be + considered neighbors. A connectivity of `label_img.ndim` means + pixels sharing a corner will be considered neighbors. + + Returns + ------- + boundaries : array of bool, same shape as `label_img` + A bool image where `True` represents a boundary pixel. + """ + selem = nd.generate_binary_structure(label_img.ndim, connectivity) + boundaries = dilation(label_img, selem) != erosion(label_img, selem) return boundaries @@ -35,7 +54,7 @@ def mark_boundaries(image, label_img, color=(1, 1, 0), boundaries = find_boundaries(label_img) if outline_color is not None: - outer_boundaries = dilation(boundaries.astype(np.uint8), square(2)) + outer_boundaries = dilation(boundaries.astype(np.uint8), square(3)) image[outer_boundaries != 0, :] = np.array(outline_color) image[boundaries, :] = np.array(color) return image diff --git a/skimage/segmentation/tests/test_boundaries.py b/skimage/segmentation/tests/test_boundaries.py index 2fff52f8..7d5e5d9c 100644 --- a/skimage/segmentation/tests/test_boundaries.py +++ b/skimage/segmentation/tests/test_boundaries.py @@ -8,12 +8,12 @@ def test_find_boundaries(): image[2:7, 2:7] = 1 ref = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 0, 0, 0, 1, 1, 0, 0], + [0, 1, 1, 0, 0, 0, 1, 1, 0, 0], + [0, 1, 1, 0, 0, 0, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) @@ -28,27 +28,28 @@ def test_mark_boundaries(): label_image[2:7, 2:7] = 1 ref = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 0, 0, 0, 1, 1, 0, 0], + [0, 1, 1, 0, 0, 0, 1, 1, 0, 0], + [0, 1, 1, 0, 0, 0, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) + result = mark_boundaries(image, label_image, color=(1, 1, 1)).mean(axis=2) assert_array_equal(result, ref) - ref = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 1, 1, 1, 1, 1, 2, 0], - [0, 0, 1, 2, 2, 2, 2, 1, 2, 0], - [0, 0, 1, 2, 0, 0, 0, 1, 2, 0], - [0, 0, 1, 2, 0, 0, 0, 1, 2, 0], - [0, 0, 1, 2, 0, 0, 0, 1, 2, 0], - [0, 0, 1, 1, 1, 1, 1, 2, 2, 0], - [0, 0, 2, 2, 2, 2, 2, 2, 0, 0], + ref = np.array([[0, 2, 2, 2, 2, 2, 2, 2, 0, 0], + [2, 2, 1, 1, 1, 1, 1, 2, 2, 0], + [2, 1, 1, 1, 1, 1, 1, 1, 2, 0], + [2, 1, 1, 2, 2, 2, 1, 1, 2, 0], + [2, 1, 1, 2, 0, 2, 1, 1, 2, 0], + [2, 1, 1, 2, 2, 2, 1, 1, 2, 0], + [2, 1, 1, 1, 1, 1, 1, 1, 2, 0], + [2, 2, 1, 1, 1, 1, 1, 2, 2, 0], + [0, 2, 2, 2, 2, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) result = mark_boundaries(image, label_image, color=(1, 1, 1), outline_color=(2, 2, 2)).mean(axis=2)