OpenCV Python rotate image by X degrees around specific point

150,044

Solution 1

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.

Solution 2

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.

Solution 3

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

Solution 4

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

Solution 5

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
Share:
150,044
Mike
Author by

Mike

Updated on July 05, 2022

Comments

  • Mike
    Mike almost 2 years

    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
    
  • Mike
    Mike over 12 years
    Thanks for the help, however I'm using the "cv" module and you are using "cv2", so its complaining specifically about "image.shape" not existing. I have only been using the "cv" module up until now, so I don't quite get all the changes with "cv2" yet. I know my image is (140,140), so I tried hard coding that in place of image.shape, but it didn't like that at all either.
  • Mike
    Mike over 12 years
    I think I may have made some progress, but still running into a problem. Here is the latest code: result = cv2.warpAffine(image, rot_mat, cv.GetSize(image), flags=cv2.INTER_LINEAR) Traceback (most recent call last): result = cv2.warpAffine(image, rot_mat, cv.GetSize(image), flags=cv2.INTER_LINEAR) TypeError: <unknown> is not a numpy array
  • Hani
    Hani about 12 years
    I have a problem running cv2.getRotationMatrix2D(center=image_center ,angle=angle,scale=1) TypeError: function takes exactly 2 arguments (3 given)
  • Treper
    Treper over 11 years
    image.shape include the width,height and channel
  • sreemanth pulagam
    sreemanth pulagam over 10 years
    @Hani try cv2.getRotationMatrix2D((imagecenter[0],imagecenter[1]),angl‌​e,1.0)
  • Graydyn Young
    Graydyn Young almost 8 years
    This solution changes the image dimensions. See nicodjimenez's answer below.
  • Teodorico Levoff
    Teodorico Levoff over 7 years
    I am looping through a directory of png and doing this but I get a RuntimeError: invalid rotation plane specified. Any fixes?
  • fivef
    fivef over 7 years
    do you pass in a open cv image? like from: img = cv2.imread('messi5.jpg',0)
  • Ali Momen Sani
    Ali Momen Sani almost 7 years
    this is quite slow for me
  • Ali Momen Sani
    Ali Momen Sani almost 7 years
    this one wont cut any of the image: imutils.rotate_bound(frame, 90)
  • AljoSt
    AljoSt over 5 years
    Nice, it's easier to use and you have an easy way to decide if you want to keep the image size (reshape=True) or the image content (reshape=False)
  • Eduardo Pignatelli
    Eduardo Pignatelli about 5 years
  • mLstudent33
    mLstudent33 over 4 years
    was this for face detection? I want to rotate video frames by 90 degrees and run MTCNN because it won't detect frontal faces lying sideways (person lying on the ground)
  • mLstudent33
    mLstudent33 over 4 years
    can I run face detection on the rotated frame? MTCNN does not detect frontal faces lying sideways.
  • JTIM
    JTIM over 4 years
    @mLstudent33 No I used it for a different purpose, but this is just rotating an image. So if you have the angle then it should be fine?
  • mLstudent33
    mLstudent33 over 4 years
    I think so. I can rotate, run detection, then draw cv2.rectangle() and then rotate it back. Thanks for replying.
  • erwaman
    erwaman over 4 years
    getRotationMatrix2D seems to require (col,row), too. center should use (col,row) as well, as is done in @Omnipresent's answer.
  • Keithel
    Keithel almost 3 years
    I agree that it wasn't clear. @alex-rodrigues ' answer does some slicing to the image.shape to get the width and height in the right order for warpAffine: image.shape[1::-1] does this. What this does is takes a slice starting at the 1st element, with a step value of -1, so proceeding left, so you end up with a slice with [1][0], which is the width (columns), followed by height (rows).
  • MuadDev
    MuadDev over 2 years
    I believe there might be an error in this answer. I think the correct image center to rotate around is off by 0.5 pixel. The correct code would be image_center = tuple((np.array(image.shape[1::-1])-1) / 2). To check this I encourage you to create a small image with a single line in the middle and rotate it with 45 degrees. Like this im = np.zeros(shape=(3, 3), dtype=np.uint8); im[:, 1] = 1; im_rot = rotate_image(im, 45). Using the original code, the line is not correctly rotated, with the adjusted center it is correctly rotated. Please correct me if I am mistaken.