Reputation: 620
Suppose i have a boolean array with shape (nrows,ncols). True represents that i have a defined value (real number) and False represents an undefined / (not of interest) values.
Im trying to figure out an efficient way to extract the rows and cols of both the boundary and the interior, for example if i had the floowing boolean array, where im marking the boundaries by red and the interior by green:
then a desired output would be (the position of the green Trues):
interior = [(2,3), (2,4)]
We can assume that the interior is always connected.
Using np.where(array == False)[0], i get the indices of the Falses, but how to go from here to the boundaries indices and then to the interior ? I can ofcourse loop through each boolean and check if any of the neighbours is False, if no, then its an interior.
Any tips on how to do this efficiently without looping? Another example to be clear:
desired output: interior = [(2,3) , (2,4) , (3,3) , (3,4) , (3,5) , (4,3), (4,4), (4,5)]
The output can be a boolean array as well, containing Trues in interior positions, False otherwise. It does not matter. Thanks in advance.
Upvotes: 2
Views: 895
Reputation: 221574
Approach #1
We can use 2D convolution
-
from scipy.signal import convolve2d
def interior_indices(a):
kernel = np.ones((3,3),dtype=int)
return np.argwhere(convolve2d(a,kernel,'same')==9)
Sample runs -
In [44]: a1
Out[44]:
array([[False, False, False, False, False, False, False, False],
[ True, True, True, True, True, True, False, False],
[False, True, True, True, True, True, True, False],
[False, False, True, True, True, True, False, False]])
In [45]: interior_indices(a1)
Out[45]:
array([[2, 3],
[2, 4]])
In [46]: a2
Out[46]:
array([[False, False, False, False, False, False, False, False],
[False, True, True, True, True, True, False, False],
[False, True, True, True, True, True, True, False],
[False, False, True, True, True, True, True, False],
[False, False, True, True, True, True, True, False],
[False, True, True, True, True, True, True, False],
[False, False, False, True, True, False, False, False]])
In [47]: interior_indices(a2)
Out[47]:
array([[2, 3],
[2, 4],
[3, 3],
[3, 4],
[3, 5],
[4, 3],
[4, 4],
[4, 5]])
Approach #2
Alternatively, with uniform-filter
-
In [61]: from scipy.ndimage import uniform_filter
In [62]: np.argwhere(uniform_filter(a1,mode='constant'))
Out[62]:
array([[2, 3],
[2, 4]])
In [63]: np.argwhere(uniform_filter(a2,mode='constant'))
Out[63]:
array([[2, 3],
[2, 4],
[3, 3],
[3, 4],
[3, 5],
[4, 3],
[4, 4],
[4, 5]])
Approach #3
And with binary-erosion
-
In [72]: from scipy.ndimage.morphology import binary_erosion
In [73]: kernel = np.ones((3,3),dtype=bool)
In [74]: np.argwhere(binary_erosion(a1,kernel))
Out[74]:
array([[2, 3],
[2, 4]])
In [75]: np.argwhere(binary_erosion(a2,kernel))
Out[75]:
array([[2, 3],
[2, 4],
[3, 3],
[3, 4],
[3, 5],
[4, 3],
[4, 4],
[4, 5]])
Upvotes: 2
Reputation: 620
Found a way ! If its too trivial, vote delete :)
#data: the boolean array
d0 = data[1:-1, 2:]
d1 = data[:-2, 2:]
d2 = data[:-2, 1:-1]
d3 = data[:-2, :-2]
d4 = data[1:-1, :-2]
d5 = data[2:, :-2]
d6 = data[2:, 1:-1]
d7 = data[2:, 2:]
interior = np.where(d0 & d1 & d2 & d3 & d4 & d5 & d6 & d7, True, False)
Upvotes: 1