Extract blocks or patches from NumPy Array

I have an array with two numbers:

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 2 by 2 patches without repeating the elements.

The answer should be exactly the same. It can be a 3rd array or a 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 to do it easily?

In my real problem, the size of a is (36, 72). I can’t do it one by one. I want a software way to do this.

+5
source share
3 answers

Here is a pretty cryptic single-line numpy for creating a three-dimensional 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-dimensional array of 2-dimensional 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 to give a detailed description of how this works. Maybe later ...)

It uses a less critical version, which uses a nested list comprehension. In this case, result2 is a list of python arrays with 2 numpy:

 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]]) 
+1
source

Using scikit-image:

 import numpy as np from skimage.util import view_as_blocks a = np.array([[1,5,9,13], [2,6,10,14], [3,7,11,15], [4,8,12,16]]) print(view_as_blocks(a, (2, 2))) 
+7
source

You can achieve this with a combination of np.reshape and np.swapaxes like this -

 def extract_blocks(a, blocksize): M,N = a.shape b0, b1 = blocksize return a.reshape(M//b0,b0,N//b1,b1).swapaxes(1,2).reshape(-1,b0,b1) 

Examples of examples

Let us use a sample input array, for example:

 In [94]: a Out[94]: array([[2, 2, 6, 1, 3, 6], [1, 0, 1, 0, 0, 3], [4, 0, 0, 4, 1, 7], [3, 2, 4, 7, 2, 4], [8, 0, 7, 3, 4, 6], [1, 5, 6, 2, 1, 8]]) 

Now let me use some block sizes for testing. Let two cases be used with blocks from (2,3) and (3,3) .

Case No. 1:

 In [95]: extract_blocks(a, (2,3)) # Blocksize : (2,3) Out[95]: array([[[2, 2, 6], [1, 0, 1]], [[1, 3, 6], [0, 0, 3]], [[4, 0, 0], [3, 2, 4]], [[4, 1, 7], [7, 2, 4]], [[8, 0, 7], [1, 5, 6]], [[3, 4, 6], [2, 1, 8]]]) 

Case No. 2:

 In [96]: extract_blocks(a, (3,3)) # Blocksize : (3,3) Out[96]: array([[[2, 2, 6], [1, 0, 1], [4, 0, 0]], [[1, 3, 6], [0, 0, 3], [4, 1, 7]], [[3, 2, 4], [8, 0, 7], [1, 5, 6]], [[7, 2, 4], [3, 4, 6], [2, 1, 8]]]) 
+4
source

All Articles