For sliding blockwise operations, you can borrow an implementation from Implement Matlab's im2col_sliding 'sliding' in python
that groups each block into a column, thereby blockwise operation would become as easy as operating along the axis = 0
and as such would accept all NumPy ufuncs
for vectorized solutions. Here's a formal way to define such a sliding blocks creating function -
def im2col_sliding(A,BLKSZ):
# Parameters
M,N = A.shape
col_extent = N - BLKSZ[1] + 1
row_extent = M - BLKSZ[0] + 1
# Get Starting block indices
start_idx = np.arange(BLKSZ[0])[:,None]*N + np.arange(BLKSZ[1])
# Get offsetted indices across the height and width of input array
offset_idx = np.arange(row_extent)[:,None]*N + np.arange(col_extent)
# Get all actual indices & index into input array for final output
return np.take (A,start_idx.ravel()[:,None] + offset_idx.ravel())
Sample run to calculate blockwise sum
, average
, std
, etc. -
In [6]: arr # Sample array
Out[6]:
array([[6, 5, 0, 6, 0],
[7, 4, 2, 3, 6],
[6, 3, 3, 8, 1],
[5, 5, 1, 1, 8]])
In [7]: im2col_sliding(arr,[2,3]) # Blockwise array with blocksize : (2,3)
Out[7]:
array([[6, 5, 0, 7, 4, 2, 6, 3, 3],
[5, 0, 6, 4, 2, 3, 3, 3, 8],
[0, 6, 0, 2, 3, 6, 3, 8, 1],
[7, 4, 2, 6, 3, 3, 5, 5, 1],
[4, 2, 3, 3, 3, 8, 5, 1, 1],
[2, 3, 6, 3, 8, 1, 1, 1, 8]])
In [8]: np.sum(im2col_sliding(arr,[2,3]),axis=0) # Perform blockwise summation
Out[8]: array([24, 20, 17, 25, 23, 23, 23, 21, 22])
In [9]: np.mean(im2col_sliding(arr,[2,3]),axis=0) # Perform blockwise averaging
Out[9]:
array([ 4. , 3.33333333, 2.83333333, 4.16666667, 3.83333333,
3.83333333, 3.83333333, 3.5 , 3.66666667])
In [10]: np.std(im2col_sliding(arr,[2,3]),axis=0) # Blockwise std. deviation
Out[10]:
array([ 2.38047614, 1.97202659, 2.47767812, 1.77169097, 1.95078332,
2.40947205, 1.67497927, 2.43241992, 3.14466038])