I’m basing this answer on a very similar answer I wrote just a few hours ago.
#from sklearn.feature_extraction.image import extract_patches # similar to numpy's stride_tricks
from numpy.lib.stride_tricks import as_strided
data = np.array([[1, 1 , 0 , 0 , 0 , 0 , 1 , 0],
[1, 1 , 1 , 0 , 0 , 1 , 1 , 0],
[1, 1 , 1 , 1 , 1 , 0 , 0 , 0],
[0, 0 , 1 , 1 , 1 , 0 , 0 , 0],
[0, 0 , 1 , 1 , 1 , 1 , 0 , 1],
[1, 1 , 0 , 0 , 0 , 1 , 1 , 1],
[1, 1 , 0 , 0 , 0 , 1 , 1 , 1]])
patches = as_strided(data, shape=(data.shape[0]-2,data.shape[1]-2, 3, 3), strides=data.strides*2)
dual = patches.all(axis=-1).all(axis=-1)
patches[dual==False] = 0
patches[dual] = 1
The result (in data
) is as you’ve shown.
The way this works is as follows:
the function extract_patches
generates a view into the array data
, which means it is not a copy of the actual data but uses the strides to generate a seemingly different array. In this case, it will generate all possible 3×3 submatrices (which can be overlapping) of the array data
. Then, by writing patches.all(axis=-1).all(axis=-1)
, you are first checking if the elements in the rows of the submatrices are all True (or equivalent to True in a boolean sense, so not 0, empty lists, empty dictionaries, empty tuples and a few other special cases), thereby collapsing one of the axes of this array and then with the second .all(axis=-1)
the columns are being checked to see if they’re all True.
Small example of this paragraph to clarify visually:
>>> A = np.array([
... [1, 1, 0], # -> along this row, not all elements are 1: so `all` along the last axis will return False
... [1, 1, 1], # -> along this row, all elements are 1: so `all` along the last axis (axis=-1) will return True
... [1, 1, 1]])
>>> A.all(axis=-1)
array([False, True, True], dtype=bool) # so it is done along the last axis, along the rows
>>> A.all(axis=-1).all(axis=-1)
False
So this array dual
now has a “1” (True actually) for every 3×3 submatrix that was full of ones. Those submatrices are overlapping however, so you first want to set the patches all to 0 whenevery any of these 3×3 submatrices was not all ones (that’s the one-to-last line in the first code block: patches[dual==False] = 0
) and then you can apply the ones again in each 3×3 submatrix that originally had all ones.
The alternatives are to correlate with a kernel = np.ones((3,3))
or to take multiple bitwise operations into account (like in the other answer), but that last method becomes very difficult to write when the array’s dimensions grow beyond simply (2,2)
.
5
solved Extracting the elements matching the filter