Rotate a 2D image around specified origin in Python

16,065

If OpenCV is not an option, you can do image rotation around a so called pivot point with NumPy (import numpy as np) and SciPy (from scipy import ndimage) the following way:

  1. Pad the image img such that the pivot point is in the image center and the image size is doubled:

    padX = [img.shape[1] - pivot[0], pivot[0]]
    padY = [img.shape[0] - pivot[1], pivot[1]]
    imgP = np.pad(img, [padY, padX], 'constant')
    

    (While the image shape is in row-column order, pivot is in X-Y or column-row order here. You might want to define it differently.)

  2. Rotate the image around its center (here the rotation angle is 45 degrees):

    imgR = ndimage.rotate(imgP, 45, reshape=False)
    

    Note that we disallow reshaping the image, since we'll crop the image ourselves.

  3. Crop the image such that the pivot point is at its original position. Therefore, we simply reverse the padding from step 1:

    imgC = imgR[padY[0] : -padY[1], padX[0] : -padX[1]]
    

You can see the different steps in the following plot (original image, padded, rotated, cropped; 45 degrees around (100, 300)).

enter image description here

Wrapping it up in a handy function yields:

def rotateImage(img, angle, pivot):
    padX = [img.shape[1] - pivot[0], pivot[0]]
    padY = [img.shape[0] - pivot[1], pivot[1]]
    imgP = np.pad(img, [padY, padX], 'constant')
    imgR = ndimage.rotate(imgP, angle, reshape=False)
    return imgR[padY[0] : -padY[1], padX[0] : -padX[1]]

Update

For colored images you'd have to avoid adding more channels while padding (zero padding in 3rd dimension):

imgP = np.pad(img, [padY, padX, [0, 0]], 'constant')

Don't forget to use a 0 for both "before" and "after" padding. Otherwise you get a ValueError.

Share:
16,065
Habib Rosyad
Author by

Habib Rosyad

I'am just a web geeks passing by.

Updated on June 05, 2022

Comments

  • Habib Rosyad
    Habib Rosyad almost 2 years

    I have a 2D image of 512x512 pixels that I would like to rotate with a certain angle at a certain origin (rotation center). All this time, I uses Scipy to rotate images with its rotate method. But, I got stumbled because the rotation always done around the center of the image. With 512x512 pixels the rotation center should be around point (x,y) 128,128. How can I rotate the image with a custom rotation center, let's say around (x,y) 20,128?

  • Fight Fire With Fire
    Fight Fire With Fire almost 9 years
    i tried this code and I got ValueError: "Unable to create correctly shaped tuple" on all the images I tried it on. Is this because they are in color and lena is B&W?
  • Falko
    Falko almost 9 years
    @FightFireWithFire: I could reproduce your error and edited my answer accordingly.