Rotate a 2D image around a specified source in Python

I have a 512x512 px 2D image that I would like to rotate at a specific angle in a specific direction (center of rotation). All this time I have been using Scipy to rotate images using the rotate method. But, I came across because the rotation was always done around the center of the image. With 512x512 pixels, the center of rotation should be around point (x, y) 128,128. How can I rotate the image with a custom rotation center, say around (x, y) 20,128?

+3


source to share


1 answer


If OpenCV is not an option, you can rotate the image around the so-called pivot point using NumPy ( import numpy as np

) and SciPy ( from scipy import ndimage

) like this:

  • Draw the image img

    so that the pivot is in the center of the image 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')
    
          

    (As long as the image shape is in row-column order, it pivot

    is here in XY or column order. You might want to define it differently.)

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

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

    Please note that we do not allow changing the image, as we crop the image ourselves.

  • Crop the image so that the pivot point is at its original position. So we just undo the indent from step 1:

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

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

enter image description here

Combining it into a convenient function, we get:

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 color images, you will need to add no more channels when filling (zero padding in 3rd dimension):

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

      

Remember to use 0

"before" and "after" shims. Otherwise, you will receive ValueError

.

+13


source







All Articles