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])
source to share
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)
source to share
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)
source to share
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]]
source to share