Unnecessary logical and

I have bool arrays A and B, and you want to get C. C is like a logical AND from A and B, but with some wiggle room over index matching. That is, a logical AND will do A [r, c] AND B [r, c], but what I would like is A [r +/- 1, c +/- 1] AND B [r +/- 1, c +/- 1]. Is there a good way to do this, ideally without scrolling through each index?

>>> import numpy as np
>>> A
np.ndarray([[True, False, False, True],
           [False, False, False, False],
           [False, False, True, False],
           [False, False, False, False])
>>> B
np.ndarray([[False, True, False, False],
           [False, False, False, False],
           [True, True, True, False],
           [False, False, False, False])
>>> np.logical_and(A, B)  # only (2,2) is True
np.ndarray([[False, False, False, False],
           [False, False, False, False],
           [False, False, True, False],
           [False, False, False, False])
>>> C  # (0,0), (1,0), and (2,1) also become True
np.ndarray([[True, False, False, False],
           [True, False, False, False],
           [False, True, True, False],
           [False, False, False, False])

      

+3


source to share


3 answers


If I understand it correctly, A [r +/- 1, c +/- 1] AND B [r +/- 1, c +/- 1] will produce the following results since @AetherUnbound is reproduced.

[[ True  True  True False]
 [ True  True  True  True]
 [False  True  True  True]
 [False  True  True  True]]

      

If this is the desired result, we can use the convolution operation on a and b and finally do the boolean and.



Decision

from scipy import ndimage
#define a convolution filter with size 3*3
f = np.full((3,3),True, dtype=bool)

#Convolve A and B using a 3*3 filter and then do a logical and in the end.
np.logical_and(ndimage.convolve(A,f,mode='constant', cval=False),ndimage.convolve(B,f,mode='constant', cval=False))
Out[766]: 
array([[ True,  True,  True, False],
       [ True,  True,  True,  True],
       [False,  True,  True,  True],
       [False,  True,  True,  True]], dtype=bool)

      

+1


source


As other commenters have pointed out, the notation you have indicates an array having a two-element overlap radius. If you want a 1-element overlap radius instead, try this:

import numpy as np

A=np.array([[True, False, False, True], 
            [False, False, False, False], 
            [False, False, True, False], 
            [False, False, False, False]])

B=np.array([[False, True, False, False],
           [False, False, False, False],
           [True, True, True, False],
           [False, False, False, False]])

def conv(mat):
    mat_pad=np.pad(mat,1,'constant')
    return mat+.5*(np.roll(mat_pad,1,0)[1:-1,1:-1]+np.roll(mat_pad,-1,0)[1:-1,1:-1]+np.roll(mat_pad,1,1)[1:-1,1:-1]+np.roll(mat_pad,-1,1)[1:-1,1:-1])


C=conv(A)*conv(B)>=.5
print(C)

      



This returns the approach:

array([[ True,  True, False, False],
       [False, False, False, False],
       [False,  True,  True, False],
       [False, False, False, False]], dtype=bool)

      

+1


source


Here's one potential solution. This checks every point on A if there is a 3x3 square around True

, and does the same for B. Then if both are True

, this index also True

. It does not give the desired result, but I may need some further clarification for that.

import numpy as np

A = np.array([[True, False, False, True], [False, False, False, False], [False, False, True, False], [False, False, False, False]])

B = np.array([[False, True, False, False], [False, False, False, False], [True, True, True, False], [False, False, False, False]])

def and3x3(arr, x, y):
    subarr = arr[max(0, x-1):x+2, max(0, y-1):y+2]
    return np.any(subarr)

C = np.zeros_like(B)

for a in range(A.shape[0]):
    for b in range(A.shape[1]):
        t1 = and3x3(A, a, b)
        t2 = and3x3(B, a, b)
        C[a, b] = t1 * t2

print(C)

      

Output:

[[ True  True  True False]
 [ True  True  True  True]
 [False  True  True  True]
 [False  True  True  True]]

      

0


source







All Articles