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)
Here are some examples of a different (loop free) way to work with blocks:
So just trying to simply copy the
matlab
functionality tonumpy
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
orscipy
.Update:
Please note that there is no real
magic
involved here with thestrides
, so I'll provide a simple function to get ablock_view
of any suitable 2Dnumpy
-array. So here we go:I found this tutorial - The final source code provides exactly the desired functionality! It even should work for any dimensionality (I did not test it) http://www.johnvinyard.com/blog/?p=268
Though the "flatten" option at the very end of the source code seems to be a little buggy. Nevertheless, very nice piece of software!
Process by slices/views. Concatenation is very expensive.
I took both inputs, as well as my original approach and compared the results. As @eat correctly points out, the results depend on the nature of your input data. Surprisingly, concatenate beats view processing in a few instances. Each method has a sweet-spot. Here is my benchmark code:
And here are the results:
Note that the segmented stride method wins by 3-4x for small block sizes. Only at large block sizes (128 x 128) and very large matrices (2048 x 2048 and larger) does the view processing approach win, and then only by a small percentage. Based on the bake-off, it looks like @eat gets the check-mark! Thanks to both of you for good examples!
Bit late to the game, but this would do overlapping blocks. I haven't done it here, but you could easily adapt for step sizes for shifting the window, I think:
Even later in the game. There is a Swiss Image processing package called Bob available at: https://www.idiap.ch/software/bob/docs/releases/last/sphinx/html/index.html It has a python command bob.ip.block described at: https://www.idiap.ch/software/bob/docs/releases/last/sphinx/html/ip/generated/bob.ip.block.html#bob.ip.block which appears to do everything the Matlab command 'blockproc' does. I have not tested it.
There's also an interesting command bob.ip.DCTFeatures which incorporates the 'block' capabilities to extract or modify DCT coefficients of an image.