Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I efficiently process a numpy array in blocks similar to Matlab's blkproc (blockproc) function

I'm looking for a good approach for efficiently dividing an image into small regions, processing each region separately, and then re-assembling the results from each process into a single processed image. Matlab had a tool for this called blkproc (replaced by blockproc in newer versions of Matlab).

In an ideal world, the function or class would support overlap between the divisions in the input matrix too. In the Matlab help, blkproc is defined as:

B = blkproc(A,[m n],[mborder nborder],fun,...)

  • A is your input matrix,
  • [m n] is the block size
  • [mborder, nborder] is the size of your border region (optional)
  • fun is a function to apply to each block

I have kluged together an approach, but it strikes me as clumsy and I bet there's a much better way. At the risk of my own embarrassment, here's my code:

 import numpy as np  def segmented_process(M, blk_size=(16,16), overlap=(0,0), fun=None):     rows = []     for i in range(0, M.shape[0], blk_size[0]):         cols = []         for j in range(0, M.shape[1], blk_size[1]):             cols.append(fun(M[i:i+blk_size[0], j:j+blk_size[1]]))         rows.append(np.concatenate(cols, axis=1))     return np.concatenate(rows, axis=0)  R = np.random.rand(128,128) passthrough = lambda(x):x Rprime = segmented_process(R, blk_size=(16,16),                             overlap=(0,0),                             fun=passthrough)  np.all(R==Rprime) 
like image 549
Carl F. Avatar asked Feb 22 '11 03:02

Carl F.


People also ask

What makes a NumPy array faster than other Python objects?

Because the Numpy array is densely packed in memory due to its homogeneous type, it also frees the memory faster. So overall a task executed in Numpy is around 5 to 100 times faster than the standard python list, which is a significant leap in terms of speed.

How can I speed up my NumPy operation?

By explicitly declaring the "ndarray" data type, your array processing can be 1250x faster. This tutorial will show you how to speed up the processing of NumPy arrays using Cython. By explicitly specifying the data types of variables in Python, Cython can give drastic speed increases at runtime.

Are NumPy arrays more efficient?

NumPy Arrays are faster than Python Lists because of the following reasons: An array is a collection of homogeneous data-types that are stored in contiguous memory locations. On the other hand, a list in Python is a collection of heterogeneous data types stored in non-contiguous memory locations.

What is faster than NumPy?

pandas provides a bunch of C or Cython optimized functions that can be faster than the NumPy equivalent function (e.g. reading text from text files). If you want to do mathematical operations like a dot product, calculating mean, and some more, pandas DataFrames are generally going to be slower than a NumPy array.


1 Answers

Here are some examples of a different (loop free) way to work with blocks:

import numpy as np from numpy.lib.stride_tricks import as_strided as ast  A= np.arange(36).reshape(6, 6) print A #[[ 0  1  2  3  4  5] # [ 6  7  8  9 10 11] # ... # [30 31 32 33 34 35]]  # 2x2 block view B= ast(A, shape= (3, 3, 2, 2), strides= (48, 8, 24, 4)) print B[1, 1] #[[14 15] # [20 21]]  # for preserving original shape B[:, :]= np.dot(B[:, :], np.array([[0, 1], [1, 0]])) print A #[[ 1  0  3  2  5  4] # [ 7  6  9  8 11 10] # ... # [31 30 33 32 35 34]] print B[1, 1] #[[15 14] # [21 20]]  # for reducing shape, processing in 3D is enough C= B.reshape(3, 3, -1) print C.sum(-1) #[[ 14  22  30] # [ 62  70  78] # [110 118 126]] 

So just trying to simply copy the matlab functionality to numpy is not all ways the best way to proceed. Sometimes a 'off the hat' thinking is needed.

Caveat:
In general, implementations based on stride tricks may (but does not necessary need to) suffer some performance penalties. So be prepared to all ways measure your performance. In any case it's wise to first check if the needed functionality (or similar enough, in order to easily adapt for) has all ready been implemented in numpy or scipy.

Update:
Please note that there is no real magic involved here with the strides, so I'll provide a simple function to get a block_view of any suitable 2D numpy-array. So here we go:

from numpy.lib.stride_tricks import as_strided as ast  def block_view(A, block= (3, 3)):     """Provide a 2D block view to 2D array. No error checking made.     Therefore meaningful (as implemented) only for blocks strictly     compatible with the shape of A."""     # simple shape and strides computations may seem at first strange     # unless one is able to recognize the 'tuple additions' involved ;-)     shape= (A.shape[0]/ block[0], A.shape[1]/ block[1])+ block     strides= (block[0]* A.strides[0], block[1]* A.strides[1])+ A.strides     return ast(A, shape= shape, strides= strides)  if __name__ == '__main__':     from numpy import arange     A= arange(144).reshape(12, 12)     print block_view(A)[0, 0]     #[[ 0  1  2]     # [12 13 14]     # [24 25 26]]     print block_view(A, (2, 6))[0, 0]     #[[ 0  1  2  3  4  5]     # [12 13 14 15 16 17]]     print block_view(A, (3, 12))[0, 0]     #[[ 0  1  2  3  4  5  6  7  8  9 10 11]     # [12 13 14 15 16 17 18 19 20 21 22 23]     # [24 25 26 27 28 29 30 31 32 33 34 35]] 
like image 199
eat Avatar answered Oct 13 '22 22:10

eat