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?
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:
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.)
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.
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)).
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With