59

What is the best way (in c/c++) to rotate an IplImage/cv::Mat by 90 degrees? I would assume that there must be something better than transforming it using a matrix, but I can't seem to find anything other than that in the API and online.

Antonio
  • 17,405
  • 10
  • 78
  • 178
Ben H
  • 2,878
  • 2
  • 21
  • 32

7 Answers7

74

As of OpenCV3.2, life just got a bit easier, you can now rotate an image in a single line of code:

cv::rotate(image, image, cv::ROTATE_90_CLOCKWISE);

For the direction you can choose any of the following:

ROTATE_90_CLOCKWISE
ROTATE_180
ROTATE_90_COUNTERCLOCKWISE
Morris Franken
  • 1,878
  • 1
  • 16
  • 13
64

Rotation is a composition of a transpose and a flip.

R_{+90} = F_x \circ T

R_{-90} = F_y \circ T

Which in OpenCV can be written like this (Python example below):

img = cv.LoadImage("path_to_image.jpg")
timg = cv.CreateImage((img.height,img.width), img.depth, img.channels) # transposed image

# rotate counter-clockwise
cv.Transpose(img,timg)
cv.Flip(timg,timg,flipMode=0)
cv.SaveImage("rotated_counter_clockwise.jpg", timg)

# rotate clockwise
cv.Transpose(img,timg)
cv.Flip(timg,timg,flipMode=1)
cv.SaveImage("rotated_clockwise.jpg", timg)
sastanin
  • 36,792
  • 11
  • 94
  • 126
  • 1
    see my `cv2` below: http://stackoverflow.com/questions/2259678/easiest-way-to-rotate-by-90-degrees-an-image-using-opencv/42359233#42359233 – Eran W Feb 21 '17 at 05:19
  • Flipping vertically (flipMode=0) should be somewhat more expensive than flipping horizontally, because you are using the cache better. Therefore, counter-clockwise rotation should be somewhat faster doing a horizontal flip first, and then the transpose. – Cris Luengo Apr 04 '17 at 17:20
15

Here is my python cv2 implementation:

import cv2

img=cv2.imread("path_to_image.jpg")

# rotate ccw
out=cv2.transpose(img)
out=cv2.flip(out,flipCode=0)

# rotate cw
out=cv2.transpose(img)
out=cv2.flip(out,flipCode=1)

cv2.imwrite("rotated.jpg", out)
Eran W
  • 1,425
  • 11
  • 17
  • The benefit of this approach is that it has the correct rotated aspect instead of keeping the original image aspect. – VoteCoffee May 18 '21 at 18:49
10

Update for transposition:

You should use cvTranspose() or cv::transpose() because (as you rightly pointed out) it's more efficient. Again, I recommend upgrading to OpenCV2.0 since most of the cvXXX functions just convert IplImage* structures to Mat objects (no deep copies). If you stored the image in a Mat object, Mat.t() would return the transpose.

Any rotation:

You should use cvWarpAffine by defining the rotation matrix in the general framework of the transformation matrix. I would highly recommend upgrading to OpenCV2.0 which has several features as well as a Mat class which encapsulates matrices and images. With 2.0 you can use warpAffine to the above.

Jacob
  • 33,032
  • 14
  • 105
  • 160
  • Thanks! Are you sure that's not less efficient than simply transposing the pixel array? The thing is, I wasn't sure if OpenCV even internally represents the image as an array of pixels, i.e. something like a 32-bit int*, and if it did, how to get a pointer to that array. – Ben H Feb 15 '10 at 16:20
  • I'm sorry, I didn't read your question properly, I've updated my answer. – Jacob Feb 15 '10 at 18:30
  • 22
    The transpose must be followed by a flip (cvFlip) to correctly rotate the image – Amnon Dec 30 '10 at 14:22
5

This is an example without the new C++ interface (works for 90, 180 and 270 degrees, using param = 1, 2 and 3). Remember to call cvReleaseImage on the returned image after using it.

IplImage *rotate_image(IplImage *image, int _90_degrees_steps_anti_clockwise)
{
    IplImage *rotated;

    if(_90_degrees_steps_anti_clockwise != 2)
        rotated = cvCreateImage(cvSize(image->height, image->width), image->depth, image->nChannels);
    else
        rotated = cvCloneImage(image);

    if(_90_degrees_steps_anti_clockwise != 2)
        cvTranspose(image, rotated);

    if(_90_degrees_steps_anti_clockwise == 3)
        cvFlip(rotated, NULL, 1);
    else if(_90_degrees_steps_anti_clockwise == 1)
        cvFlip(rotated, NULL, 0);
    else if(_90_degrees_steps_anti_clockwise == 2)
        cvFlip(rotated, NULL, -1);

    return rotated;
}
Chris
  • 7,494
  • 4
  • 35
  • 55
Andres Hurtis
  • 245
  • 3
  • 6
2

Here's my EmguCV (a C# port of OpenCV) solution:

public static Image<TColor, TDepth> Rotate90<TColor, TDepth>(this Image<TColor, TDepth> img)
    where TColor : struct, IColor
    where TDepth : new()
{
    var rot = new Image<TColor, TDepth>(img.Height, img.Width);
    CvInvoke.cvTranspose(img.Ptr, rot.Ptr);
    rot._Flip(FLIP.HORIZONTAL);
    return rot;
}

public static Image<TColor, TDepth> Rotate180<TColor, TDepth>(this Image<TColor, TDepth> img)
    where TColor : struct, IColor
    where TDepth : new()
{
    var rot = img.CopyBlank();
    rot = img.Flip(FLIP.VERTICAL);
    rot._Flip(FLIP.HORIZONTAL);
    return rot;
}

public static void _Rotate180<TColor, TDepth>(this Image<TColor, TDepth> img)
    where TColor : struct, IColor
    where TDepth : new()
{
    img._Flip(FLIP.VERTICAL);
    img._Flip(FLIP.HORIZONTAL);
}

public static Image<TColor, TDepth> Rotate270<TColor, TDepth>(this Image<TColor, TDepth> img)
    where TColor : struct, IColor
    where TDepth : new()
{
    var rot = new Image<TColor, TDepth>(img.Height, img.Width);
    CvInvoke.cvTranspose(img.Ptr, rot.Ptr);
    rot._Flip(FLIP.VERTICAL);
    return rot;
}

Shouldn't be too hard to translate it back into C++.

mpen
  • 237,624
  • 230
  • 766
  • 1,119
1

Well I was looking for some details and didn't find any example. So I am posting a transposeImage function which, I hope, will help others who are looking for a direct way to rotate 90° without losing data:

IplImage* transposeImage(IplImage* image) {

    IplImage *rotated = cvCreateImage(cvSize(image->height,image->width),   
        IPL_DEPTH_8U,image->nChannels);
    CvPoint2D32f center;
    float center_val = (float)((image->width)-1) / 2;
    center.x = center_val;
    center.y = center_val;
    CvMat *mapMatrix = cvCreateMat( 2, 3, CV_32FC1 );        
    cv2DRotationMatrix(center, 90, 1.0, mapMatrix);
    cvWarpAffine(image, rotated, mapMatrix, 
        CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, 
        cvScalarAll(0));      
    cvReleaseMat(&mapMatrix);

    return rotated;
}

Question : Why this?

float center_val = (float)((image->width)-1) / 2; 

Answer : Because it works :) The only center I found that doesn't translate image. Though if somebody has an explanation I would be interested.

thejartender
  • 9,119
  • 6
  • 31
  • 50
Artem
  • 11
  • 2
  • 1
    The reason for your math is probably due to integer division. What you want to do is: float center_val = (float)image->width / 2.0f. – Ben H Jul 02 '10 at 22:22
  • Note that the cvTranspose + cvFlip method is slightly faster if you only require rotation in 90 degree increments. – Brent Faust Aug 13 '12 at 21:32
  • For an image N pixels wide, the mathematical center of the image in width is halfway between the center of the pixel at index 0 and the center of the pixel at index N-1, thus it is at (N-1)/2. – mikeTronix May 11 '20 at 14:23