[Solved] Extracting the elements matching the filter


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