13

I have a numpy array of shape (7,4,100,100) which means that I have 7 images of 100x100 with depth 4. I want to rotate these images at 90 degrees. I have tried:

rotated= numpy.rot90(array, 1)

but it changes the shape of the array to (4,7,100,100) which is not desired. Any solution for that?

Divakar
  • 218,885
  • 19
  • 262
  • 358
FJ_Abbasi
  • 413
  • 2
  • 5
  • 16
  • sorry it was rot90().. I have edited the question. Plus I have tried numpy.rot90(array,(2,3)) but it gives: TypeError: unsupported operand type(s) for %: 'tuple' and 'int' – FJ_Abbasi May 09 '17 at 08:43
  • You had my answer corrected, explained and working, however since it looks like you like downvoting people trying to help you I deleted my answer. Find someone else who wants to help you! @Divakar could you also delete your answer please? –  May 09 '17 at 08:51
  • @SembeiNorimaki Don't think OP has downvoted. OP's profile shows no votes cast. – Divakar May 09 '17 at 08:53
  • @SembeiNorimaki i did'nt downvote your answer mate! – FJ_Abbasi May 09 '17 at 08:54
  • I asked for explanation to the downvoter and you said the answer was not working as a reply to my question. –  May 09 '17 at 08:54
  • @SembeiNorimaki yeah but that was not the explanation of downvoting, as I didn't do that :) though it seems so, but i have not read your downvoting comment by that time. – FJ_Abbasi May 09 '17 at 08:56

3 Answers3

15

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.

Divakar
  • 218,885
  • 19
  • 262
  • 358
11

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)

enter image description here enter image description here

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.

Community
  • 1
  • 1
mforpe
  • 1,549
  • 1
  • 12
  • 22
  • Thanks man that works! solution to my problem: rotate_img= rotate(array, 90, axes=(2,3)) – FJ_Abbasi May 09 '17 at 09:18
  • @FahadJahangir I am glad I was able to help :) – mforpe May 09 '17 at 09:24
  • 1
    @FahadJahangir Beware this does interpolation. So, the values would be changed and also there would be one black line on the left side. Try with `img = np.random.randint(0,255,(3,5))` and then `rot1 = rotate(img, 90)` and look at `img` and `rot1`. To Manel - This might be worth mentioning in the post for the benefit of OP and future readers. – Divakar May 09 '17 at 09:26
  • FYI, for 90/180/270 rotations and flips, this is much more computationally expensive – VoteCoffee Jan 05 '21 at 22:24
1

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.

Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93