1import numpy as np 2 3from ..measure import label 4from .._shared.utils import remove_arg 5 6 7@remove_arg("in_place", changed_version="1.0", 8 help_msg="Please use out argument instead.") 9def clear_border(labels, buffer_size=0, bgval=0, in_place=False, mask=None, 10 *, out=None): 11 """Clear objects connected to the label image border. 12 13 Parameters 14 ---------- 15 labels : (M[, N[, ..., P]]) array of int or bool 16 Imaging data labels. 17 buffer_size : int, optional 18 The width of the border examined. By default, only objects 19 that touch the outside of the image are removed. 20 bgval : float or int, optional 21 Cleared objects are set to this value. 22 in_place : bool, optional 23 Whether or not to manipulate the labels array in-place. 24 Deprecated since version 0.19. Please use `out` instead. 25 mask : ndarray of bool, same shape as `image`, optional. 26 Image data mask. Objects in labels image overlapping with 27 False pixels of mask will be removed. If defined, the 28 argument buffer_size will be ignored. 29 out : ndarray 30 Array of the same shape as `labels`, into which the 31 output is placed. By default, a new array is created. 32 33 Returns 34 ------- 35 out : (M[, N[, ..., P]]) array 36 Imaging data labels with cleared borders 37 38 Examples 39 -------- 40 >>> import numpy as np 41 >>> from skimage.segmentation import clear_border 42 >>> labels = np.array([[0, 0, 0, 0, 0, 0, 0, 1, 0], 43 ... [1, 1, 0, 0, 1, 0, 0, 1, 0], 44 ... [1, 1, 0, 1, 0, 1, 0, 0, 0], 45 ... [0, 0, 0, 1, 1, 1, 1, 0, 0], 46 ... [0, 1, 1, 1, 1, 1, 1, 1, 0], 47 ... [0, 0, 0, 0, 0, 0, 0, 0, 0]]) 48 >>> clear_border(labels) 49 array([[0, 0, 0, 0, 0, 0, 0, 0, 0], 50 [0, 0, 0, 0, 1, 0, 0, 0, 0], 51 [0, 0, 0, 1, 0, 1, 0, 0, 0], 52 [0, 0, 0, 1, 1, 1, 1, 0, 0], 53 [0, 1, 1, 1, 1, 1, 1, 1, 0], 54 [0, 0, 0, 0, 0, 0, 0, 0, 0]]) 55 >>> mask = np.array([[0, 0, 1, 1, 1, 1, 1, 1, 1], 56 ... [0, 0, 1, 1, 1, 1, 1, 1, 1], 57 ... [1, 1, 1, 1, 1, 1, 1, 1, 1], 58 ... [1, 1, 1, 1, 1, 1, 1, 1, 1], 59 ... [1, 1, 1, 1, 1, 1, 1, 1, 1], 60 ... [1, 1, 1, 1, 1, 1, 1, 1, 1]]).astype(bool) 61 >>> clear_border(labels, mask=mask) 62 array([[0, 0, 0, 0, 0, 0, 0, 1, 0], 63 [0, 0, 0, 0, 1, 0, 0, 1, 0], 64 [0, 0, 0, 1, 0, 1, 0, 0, 0], 65 [0, 0, 0, 1, 1, 1, 1, 0, 0], 66 [0, 1, 1, 1, 1, 1, 1, 1, 0], 67 [0, 0, 0, 0, 0, 0, 0, 0, 0]]) 68 69 """ 70 if any((buffer_size >= s for s in labels.shape)) and mask is None: 71 # ignore buffer_size if mask 72 raise ValueError("buffer size may not be greater than labels size") 73 74 if out is not None: 75 np.copyto(out, labels, casting='no') 76 in_place = True 77 78 if not in_place: 79 out = labels.copy() 80 elif out is None: 81 out = labels 82 83 if mask is not None: 84 err_msg = (f'labels and mask should have the same shape but ' 85 f'are {out.shape} and {mask.shape}') 86 if out.shape != mask.shape: 87 raise(ValueError, err_msg) 88 if mask.dtype != bool: 89 raise TypeError("mask should be of type bool.") 90 borders = ~mask 91 else: 92 # create borders with buffer_size 93 borders = np.zeros_like(out, dtype=bool) 94 ext = buffer_size + 1 95 slstart = slice(ext) 96 slend = slice(-ext, None) 97 slices = [slice(None) for _ in out.shape] 98 for d in range(out.ndim): 99 slices[d] = slstart 100 borders[tuple(slices)] = True 101 slices[d] = slend 102 borders[tuple(slices)] = True 103 slices[d] = slice(None) 104 105 # Re-label, in case we are dealing with a binary out 106 # and to get consistent labeling 107 labels, number = label(out, background=0, return_num=True) 108 109 # determine all objects that are connected to borders 110 borders_indices = np.unique(labels[borders]) 111 indices = np.arange(number + 1) 112 # mask all label indices that are connected to borders 113 label_mask = np.in1d(indices, borders_indices) 114 # create mask for pixels to clear 115 mask = label_mask[labels.reshape(-1)].reshape(labels.shape) 116 117 # clear border pixels 118 out[mask] = bgval 119 120 return out 121