Rotating images by 90 degrees for a multidimensional NumPy array
One solution without using np.rot90
to rotate in clockwise direction would be to swap the last two axes and then flip the last one -
img.swapaxes(-2,-1)[...,::-1]
For counter-clockwise rotation, flip the second last axis -
img.swapaxes(-2,-1)[...,::-1,:]
With np.rot90
, the counter-clockwise rotation would be -
np.rot90(img,axes=(-2,-1))
Sample run -
In [39]: img = np.random.randint(0,255,(7,4,3,5))
In [40]: out_CW = img.swapaxes(-2,-1)[...,::-1] # Clockwise
In [41]: out_CCW = img.swapaxes(-2,-1)[...,::-1,:] # Counter-Clockwise
In [42]: img[0,0,:,:]
Out[42]:
array([[142, 181, 141, 81, 42],
[ 1, 126, 145, 242, 118],
[112, 115, 128, 0, 151]])
In [43]: out_CW[0,0,:,:]
Out[43]:
array([[112, 1, 142],
[115, 126, 181],
[128, 145, 141],
[ 0, 242, 81],
[151, 118, 42]])
In [44]: out_CCW[0,0,:,:]
Out[44]:
array([[ 42, 118, 151],
[ 81, 242, 0],
[141, 145, 128],
[181, 126, 115],
[142, 1, 112]])
Runtime test
In [41]: img = np.random.randint(0,255,(800,600))
# @Manel Fornos's Scipy based rotate func
In [42]: %timeit rotate(img, 90)
10 loops, best of 3: 60.8 ms per loop
In [43]: %timeit np.rot90(img,axes=(-2,-1))
100000 loops, best of 3: 4.19 µs per loop
In [44]: %timeit img.swapaxes(-2,-1)[...,::-1,:]
1000000 loops, best of 3: 480 ns per loop
Thus, for rotating by 90
degrees or multiples of it, numpy.dot
or swapping axes
based ones seem pretty good in terms of performance and also more importantly do not perform any interpolation that would change the values otherwise as done by Scipy's rotate based function.
Another option
You could use scipy.ndimage.rotate
, i think that it's more useful than numpy.rot90
For example,
from scipy.ndimage import rotate
from scipy.misc import imread, imshow
img = imread('raven.jpg')
rotate_img = rotate(img, 90)
imshow(rotate_img)
Updated (Beware with interpolation)
If you pay attention at the rotated image you will observe a black border on the left, this is because Scipy use interpolation. So, actually the image has been changed. However, if that is a problem for you there are many options able to remove the black borders.
See this post.
Rotate three times counter clockwise: np.rot90(image, 3).
It may be three times slower, may not be if the implementation is actually optimized and we are specifying the angle here in 90 increments, not a loop counter.