I find it difficult for you to optimize time using Python + scipy . However, I was able to make a slight improvement by using as_strided to generate rot_filters directly, rather than through Boolean indexing. This is based on the very simple n-dimensional windows function. (I wrote this to solve this problem before I realized that scipy has a 2-bit convolution function.) The following code provides moderate 10% acceleration on my machine; see below for an explanation of how this works:
import numpy as np from scipy import ndimage from numpy.lib import stride_tricks
The above rotation_matrix2 function is equivalent to the following two functions (which are actually a bit slower than your original function, because windows more generalized). This does exactly what your source code does - it creates 9 3x3 windows in a 5x5 array, and then converts them into a 9x9 array for processing.
def windows(a, w, _as_strided=stride_tricks.as_strided): windows_shape = tuple(sa - sw + 1 for sa, sw in zip(a.shape, w)) windows_shape += w windows_strides = a.strides + a.strides return _as_strided(a, windows_shape, windows_strides) def rotation_matrix1(section, _windows=windows): rot_filters = windows(section.reshape(5, 5), (3, 3)).reshape(9, 9) return rot_filters[rot_filters.std(1).argmin(),:].mean()
windows works with arrays of any dimension if the window has the same number of dimensions. Here's a breakdown of how this works:
windows_shape = tuple(sa - sw + 1 for sa, sw in zip(a.shape, w))
We can consider the windows array as an nd array of nd arrays. The shape of the external nd array is dictated by the degree of freedom of the window within the larger array; in each dimension, the number of positions a window can take is equal to the length of the larger array minus the length of the window plus one. In this case, we have a 3x3 window into a 5x5 array, so the external 2-dimensional array is a 3x3 array.
windows_shape += w
The shape of the internal nd array is the same as the shape of the window itself. In our case, it is again a 3x3 array.
Now for the step. We must define the steps for the external nd array and for the internal nd array. But it turns out that they are the same! After all, a window moves around a larger array in the same way a single index moves around an array, right?
windows_strides = a.strides + a.strides
Now we have all the information needed to create windows:
return _as_strided(a, windows_shape, windows_strides)