OpenCV Python rotate image by X degrees around specific point

I'm having a hard time finding examples for rotating an image around a specific point by a specific (often very small) angle in Python using OpenCV.

This is what I have so far, but it produces a very strange resulting image, but it is rotated somewhat:

def rotateImage( image, angle ): if image != None: dst_image = cv.CloneImage( image ) rotate_around = (0,0) transl = cv.CreateMat(2, 3, cv.CV_32FC1 ) matrix = cv.GetRotationMatrix2D( rotate_around, angle, 1.0, transl ) cv.GetQuadrangleSubPix( image, dst_image, transl ) cv.GetRectSubPix( dst_image, image, rotate_around ) return dst_image 

12 Answers

import numpy as np import cv2 def rotate_image(image, angle): image_center = tuple(np.array(image.shape[1::-1]) / 2) rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0) result = cv2.warpAffine(image, rot_mat, image.shape[1::-1], flags=cv2.INTER_LINEAR) return result 

Assuming you're using the cv2 version, that code finds the center of the image you want to rotate, calculates the transformation matrix and applies to the image.

8

Or much easier use SciPy

from scipy import ndimage #rotation angle in degree rotated = ndimage.rotate(image_to_rotate, 45) 

see here for more usage info.

4
def rotate(image, angle, center = None, scale = 1.0): (h, w) = image.shape[:2] if center is None: center = (w / 2, h / 2) # Perform the rotation M = cv2.getRotationMatrix2D(center, angle, scale) rotated = cv2.warpAffine(image, M, (w, h)) return rotated 

The cv2.warpAffine function takes the shape parameter in reverse order: (col,row) which the answers above do not mention. Here is what worked for me:

import numpy as np def rotateImage(image, angle): row,col = image.shape center=tuple(np.array([row,col])/2) rot_mat = cv2.getRotationMatrix2D(center,angle,1.0) new_image = cv2.warpAffine(image, rot_mat, (col,row)) return new_image 
2

I had issues with some of the above solutions, with getting the correct "bounding_box" or new size of the image. Therefore here is my version

def rotation(image, angleInDegrees): h, w = image.shape[:2] img_c = (w / 2, h / 2) rot = cv2.getRotationMatrix2D(img_c, angleInDegrees, 1) rad = math.radians(angleInDegrees) sin = math.sin(rad) cos = math.cos(rad) b_w = int((h * abs(sin)) + (w * abs(cos))) b_h = int((h * abs(cos)) + (w * abs(sin))) rot[0, 2] += ((b_w / 2) - img_c[0]) rot[1, 2] += ((b_h / 2) - img_c[1]) outImg = cv2.warpAffine(image, rot, (b_w, b_h), flags=cv2.INTER_LINEAR) return outImg 
3
import imutils vs = VideoStream(src=0).start() ... while (1): frame = vs.read() ... frame = imutils.rotate(frame, 45) 

More:

1

You can simply use the imutils package to do the rotation. it has two methods

  1. rotate: Rotate the image at specified angle. however the drawback is image might get cropped if it is not a square image.
  2. Rotate_bound: it overcomes the problem happened with rotate. It adjusts the size of the image accordingly while rotating the image.

more info you can get on this blog:

1

Quick tweak to @alex-rodrigues answer... deals with shape including the number of channels.

import cv2 import numpy as np def rotateImage(image, angle): center=tuple(np.array(image.shape[0:2])/2) rot_mat = cv2.getRotationMatrix2D(center,angle,1.0) return cv2.warpAffine(image, rot_mat, image.shape[0:2],flags=cv2.INTER_LINEAR) 

You can easily rotate the images using opencv python-

def funcRotate(degree=0): degree = cv2.getTrackbarPos('degree','Frame') rotation_matrix = cv2.getRotationMatrix2D((width / 2, height / 2), degree, 1) rotated_image = cv2.warpAffine(original, rotation_matrix, (width, height)) cv2.imshow('Rotate', rotated_image) 

If you are thinking of creating a trackbar, then simply create a trackbar using cv2.createTrackbar() and the call the funcRotate()fucntion from your main script. Then you can easily rotate it to any degree you want. Full details about the implementation can be found here as well- Rotate images at any degree using Trackbars in opencv

0

Here's an example for rotating about an arbitrary point (x,y) using only openCV

def rotate_about_point(x, y, degree, image): rot_mtx = cv.getRotationMatrix2D((x, y), angle, 1) abs_cos = abs(rot_mtx[0, 0]) abs_sin = abs(rot_mtx[0, 1]) rot_wdt = int(frm_hgt * abs_sin + frm_wdt * abs_cos) rot_hgt = int(frm_hgt * abs_cos + frm_wdt * abs_sin) rot_mtx += np.asarray([[0, 0, -lftmost_x], [0, 0, -topmost_y]]) rot_img = cv.warpAffine(image, rot_mtx, (rot_wdt, rot_hgt), borderMode=cv.BORDER_CONSTANT) return rot_img 

you can use the following code:

import numpy as np from PIL import Image import math def shear(angle,x,y): tangent=math.tan(angle/2) new_x=round(x-y*tangent) new_y=y #shear 2 new_y=round(new_x*math.sin(angle)+new_y) #since there is no change in new_x according to the shear matrix #shear 3 new_x=round(new_x-new_y*tangent) #since there is no change in new_y according to the shear matrix return new_y,new_x image = np.array(Image.open("test.png")) # Load the image angle=-int(input("Enter the angle :- ")) # Ask the user to enter the angle of rotation # Define the most occuring variables angle=math.radians(angle) #converting degrees to radians cosine=math.cos(angle) sine=math.sin(angle) height=image.shape[0] #define the height of the image width=image.shape[1] #define the width of the image # Define the height and width of the new image that is to be formed new_height = round(abs(image.shape[0]*cosine)+abs(image.shape[1]*sine))+1 new_width = round(abs(image.shape[1]*cosine)+abs(image.shape[0]*sine))+1 output=np.zeros((new_height,new_width,image.shape[2])) image_copy=output.copy() # Find the centre of the image about which we have to rotate the image original_centre_height = round(((image.shape[0]+1)/2)-1) #with respect to the original image original_centre_width = round(((image.shape[1]+1)/2)-1) #with respect to the original image # Find the centre of the new image that will be obtained new_centre_height= round(((new_height+1)/2)-1) #with respect to the new image new_centre_width= round(((new_width+1)/2)-1) #with respect to the new image for i in range(height): for j in range(width): #co-ordinates of pixel with respect to the centre of original image y=image.shape[0]-1-i-original_centre_height x=image.shape[1]-1-j-original_centre_width #Applying shear Transformation new_y,new_x=shear(angle,x,y) new_y=new_centre_height-new_y new_x=new_centre_width-new_x output[new_y,new_x,:]=image[i,j,:] pil_img=Image.fromarray((output).astype(np.uint8)) pil_img.save("rotated_image.png") 

You need a homogenous matrix of size 2x3. First 2x2 is the rotation matrix and last column is a translation vector.

enter image description here

Here's how to build your transformation matrix:

# Exemple with img center point: # angle = # specific_point = np.array(img.shape[:2][::-1])/2 def rotate(img: np.ndarray, angle: float, specific_point: np.ndarray) -> np.ndarray: warp_mat = np.zeros((2,3)) cos, sin = np.cos(angle), np.sin(angle) warp_mat[:2,:2] = [[cos, -sin],[sin, cos]] warp_mat[:2,2] = specific_point - np.matmul(warp_mat[:2,:2], specific_point) return cv2.warpAffine(img, warp_mat, img.shape[:2][::-1]) 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like