Rotate Cv::Mat Using Cv::Warpaffine Offsets Destination Image

Rotate cv::Mat using cv::warpAffine offsets destination image

I've found a solution that doesn't involve warpAffine().

But before that, I need to state (for future references) that my suspicion was right, you needed to pass the size of the destination when calling warpAffine():

warpAffine(image, rotated_img, rot_matrix, rotated_img.size());

As far as I can tell, the black border (caused by writing at an offset) drawed by this function seems to be it's standard behavior. I've noticed this with the C interface and also with the C++ interface of OpenCV running on Mac and Linux, using the versions 2.3.1a and 2.3.0.

The solution I ended up using is much simpler than all this warp thing. You can use cv::transpose() and cv::flip() to rotate an image by 90 degrees. Here it is:

Mat src = imread(argv[1], 1);

cv::Mat dst;
cv::transpose(src, dst);
cv::flip(dst, dst, 1);

imwrite("rotated90.jpg", dst);

----I>

OpenCV: how to rotate IplImage?

If you use OpenCV > 2.0 it is as easy as

using namespace cv;

Mat rotateImage(const Mat& source, double angle)
{
Point2f src_center(source.cols/2.0F, source.rows/2.0F);
Mat rot_mat = getRotationMatrix2D(src_center, angle, 1.0);
Mat dst;
warpAffine(source, dst, rot_mat, source.size());
return dst;
}

Note: angle is in degrees, not radians.

See the C++ interface documentation for more details and adapt as you need:

  • getRotationMatrix
  • warpAffine

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;
}

Combining two warpAffine, shift and rotate image

You have to multiply the matrices. Add third row [0,0,1] to the 2x3 matrices. This is called homogeneous coordinates.

M = np.float32([[1,0,20],[0,1,10],[0,0,1]]) // shift matrix
center_of_rot = (500, 500)
Rot = cv2.getRotationMatrix2D(center_of_rot, 1.23, 1.0)
Rot = np.vstack([Rot, [0,0,1]])
TransfomMatrix = np.matmul(M, Rot)
rotated = cv2.warpPerspective(img, TransformMatrix, (y_size, x_size),flags=cv2.INTER_LANCZOS4) // note - warpPerspective is used here, because the matrix is now 3x3 not 3x2


Related Topics



Leave a reply



Submit