Rotate an Image Without Cropping in Opencv in C++

Rotate an image without cropping in OpenCV in C++

My answer is inspired by the following posts / blog entries:

  • Rotate cv::Mat using cv::warpAffine offsets destination image
  • http://john.freml.in/opencv-rotation

Main ideas:

  • Adjusting the rotation matrix by adding a translation to the new image center
  • Using cv::RotatedRect to rely on existing opencv functionality as much as possible

Code tested with opencv 3.4.1:

#include "opencv2/opencv.hpp"

int main()
{
cv::Mat src = cv::imread("im.png", CV_LOAD_IMAGE_UNCHANGED);
double angle = -45;

// get rotation matrix for rotating the image around its center in pixel coordinates
cv::Point2f center((src.cols-1)/2.0, (src.rows-1)/2.0);
cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
// determine bounding rectangle, center not relevant
cv::Rect2f bbox = cv::RotatedRect(cv::Point2f(), src.size(), angle).boundingRect2f();
// adjust transformation matrix
rot.at<double>(0,2) += bbox.width/2.0 - src.cols/2.0;
rot.at<double>(1,2) += bbox.height/2.0 - src.rows/2.0;

cv::Mat dst;
cv::warpAffine(src, dst, rot, bbox.size());
cv::imwrite("rotated_im.png", dst);

return 0;
}

Rotate image without cropping OpenCV

Create new square image with dimension = diagonal of your initial image.

Draw initial image into the center of new image.

Rotate new image

Image Rotation without cropping

The rotated image usually has to be large than the old image to store all pixel values.

Each point (x,y) is translated to

(x', y') = (x*cos(rads) - y*sin(rads), x*sin(rads) + y*cos(rads))

An image with height h and width w, center at (0,0) and corners at

(h/2, w/2)
(h/2, -w/2)
(-h/2, w/2)
(-h/2, -w/2)

has a new height of

h' = 2*y' = 2 * (w/2*sin(rads) + h/2*cos(rads))

and a new width of

w' = 2*x' = 2 * (w/2*cos(rads) + h/2*sin(rads))

for 0 <= rads <= pi/4. It is x * y <= x' * y' and for rads != k*pi/2 with k = 1, 2, ... it is x * y < x' * y'

In any case the area of the rotated image is same size as or larger than the area of the old image.

If you use the old size, you cut off the corners.

Example:

Your image has h=1, w=1 and rads=pi/4. You need a new image with h'=sqrt(2)=1.41421356237 and w'=sqrt(2)=1.41421356237 to store all pixel values. The pixel from (1,1) is translated to (0, sqrt(2)).

Rotate an image using OpenCV with C++ on interface

try this.worked.

                         IplImage* source_image;                     
IplImage *dest = cvCloneImage(source_image);
CvPoint2D32f center;
center.x = dest->width / 2;
center.y = dest->height / 2;
CvMat *mapMatrix = cvCreateMat(2, 3, CV_32FC1);


double angle = System::Convert::ToDouble(numericUpDown1->Value);
cv2DRotationMatrix(center, angle, 1.0, mapMatrix);

cvWarpAffine(source_image, dest, mapMatrix, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
cvReleaseMat(&mapMatrix);
cvShowImage("Rotated", dest);


Related Topics



Leave a reply



Submit