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.
7 Answers
Rotation is a composition of a transpose and a flip.
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)
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.
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;
}
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++.
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.