Search code examples
numpyscipyscikit-learnscikit-image

Extract blocks or patches from NumPy Array


I have a 2-d numpy array as follows:

a = np.array([[1,5,9,13],
              [2,6,10,14],
              [3,7,11,15],
              [4,8,12,16]]

I want to extract it into patches of 2 by 2 sizes with out repeating the elements.

The answer should exactly be the same. This can be 3-d array or list with the same order of elements as below:

[[[1,5],
 [2,6]],   

 [[3,7],
 [4,8]],

 [[9,13],
 [10,14]],

 [[11,15],
 [12,16]]]

How can do it easily?

In my real problem the size of a is (36, 72). I can not do it one by one. I want programmatic way of doing it.


Solution

  • Here's a rather cryptic numpy one-liner to generate your 3-d array, called result1 here:

    In [60]: x
    Out[60]: 
    array([[2, 1, 2, 2, 0, 2, 2, 1, 3, 2],
           [3, 1, 2, 1, 0, 1, 2, 3, 1, 0],
           [2, 0, 3, 1, 3, 2, 1, 0, 0, 0],
           [0, 1, 3, 3, 2, 0, 3, 2, 0, 3],
           [0, 1, 0, 3, 1, 3, 0, 0, 0, 2],
           [1, 1, 2, 2, 3, 2, 1, 0, 0, 3],
           [2, 1, 0, 3, 2, 2, 2, 2, 1, 2],
           [0, 3, 3, 3, 1, 0, 2, 0, 2, 1]])
    
    In [61]: result1 = x.reshape(x.shape[0]//2, 2, x.shape[1]//2, 2).swapaxes(1, 2).reshape(-1, 2, 2)
    

    result1 is like a 1-d array of 2-d arrays:

    In [68]: result1.shape
    Out[68]: (20, 2, 2)
    
    In [69]: result1[0]
    Out[69]: 
    array([[2, 1],
           [3, 1]])
    
    In [70]: result1[1]
    Out[70]: 
    array([[2, 2],
           [2, 1]])
    
    In [71]: result1[5]
    Out[71]: 
    array([[2, 0],
           [0, 1]])
    
    In [72]: result1[-1]
    Out[72]: 
    array([[1, 2],
           [2, 1]])
    

    (Sorry, I don't have time at the moment to give a detailed breakdown of how it works. Maybe later...)

    Here's a less cryptic version that uses a nested list comprehension. In this case, result2 is a python list of 2-d numpy arrays:

    In [73]: result2 = [x[2*j:2*j+2, 2*k:2*k+2] for j in range(x.shape[0]//2) for k in range(x.shape[1]//2)]
    
    In [74]: result2[5]
    Out[74]: 
    array([[2, 0],
           [0, 1]])
    
    In [75]: result2[-1]
    Out[75]: 
    array([[1, 2],
           [2, 1]])