Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if all elements are True in sliding windows across a 2D array - Python

I have a multidimensional numpy array where the elements are either True or False values:

import numpy as np 
#just making a toy array grid to show what I want to do 
grid = np.ones((4,4),dtype = 'bool')
grid[0,0]=False 
grid[-1,-1]=False 
#now grid has a few false values but is a 4x4 filled with mostly true values

Now I need to generate another array M, where the value at each site M[i,j] depends on grid[i:i+2,j:j+2] as in

M = np.empty((4x4)) #elements to be filled

#here is the part I want to clean up 
for ii in range(4): 
    for jj in range(4): 

        #details here are unimportant. It's just that M[ii,jj] depends on 
        #multiple elements of grid in some way
        if ii+2<=4 and jj+2<=4:     
            M[ii,jj] = np.all(grid[ii:ii+2,jj:jj+2]==True)
        else: 
            M[ii,jj] = False 

Is there some way to fill the array M using elements from grid without double loops?

like image 678
kevinkayaks Avatar asked Apr 18 '17 07:04

kevinkayaks


1 Answers

Approach #1

Here's one approach with 2D convolution -

from scipy.signal import convolve2d as conv2

out = (conv2(grid,np.ones((2,2),dtype=int),'valid')==4).astype(int)

Sample run -

In [118]: grid
Out[118]: 
array([[False,  True,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True, False]], dtype=bool)

In [119]: (conv2(grid,np.ones((2,2),dtype=int),'valid')==4).astype(int)
Out[119]: 
array([[0, 1, 1],
       [1, 1, 1],
       [1, 1, 0]])

Please note that the last row and last column from the expected output would be all zeros with the initialized output array. This is because of the sliding nature of the code, as it won't have that much of extent along the rows and columns.

Approach #2

Here's another with 2D uniform filter -

from scipy.ndimage.filters import uniform_filter as unif2d

out = unif2d(grid,size=2).astype(int)[1:,1:]

Approach #3

Here's another with 4D slided windowed view -

from skimage.util import view_as_windows as viewW

out = viewW(grid,(2,2)).all(axis=(2,3)).astype(int)

With that all(axis=(2,3)), we are just checking along both the dimensions of every window for all elements to be all True elements.


Runtime test

In [122]: grid = np.random.rand(5000,5000)>0.1

In [123]: %timeit (conv2(grid,np.ones((2,2),dtype=int),'valid')==4).astype(int)
1 loops, best of 3: 520 ms per loop

In [124]: %timeit unif2d(grid,size=2).astype(int)[1:,1:]
1 loops, best of 3: 210 ms per loop

In [125]: %timeit viewW(grid,(2,2)).all(axis=(2,3)).astype(int)
1 loops, best of 3: 614 ms per loop
like image 194
Divakar Avatar answered Oct 30 '22 00:10

Divakar