0

I've currently trouble to understand what's necessary to transform a cv::RotatedRect after rotating an image without cropping using the following code by Lars Schillingmann in this question.

Here's the code he provided as answer:

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

In my case, I've a cv::RotatedRect which matches a certain position in the src image. This cv::RotatedRect should match the same postion after the transformation/rotation was applied to the src mat. Currently, I struggle with doing it the right way.

From what I know, to rotate a cv::RotatedRect, it's only necessary to directly modify the members of the structure e.g. angle. I'm quite sure that I only have to modify the center, but the new position is always a bit off from the expected location. I initially expected that I only have to add the difference between bbox and src dimensions to get what I'm looking for but it turns out to be not the case (inlcuding the rotation of course).

connected_components[i].center.x += ...
connected_components[i].center.y += ...
cv::RotatedRect newRect(connected_components[i].center, connected_components[i].size, connected_components[i].angle- median);
Bastian
  • 1,553
  • 13
  • 33
  • As of OpenCV3.2 , `cv::rotate(image, image, cv::ROTATE_180);` or `ROTATE_90_CLOCKWISE` , `ROTATE_90_COUNTERCLOCKWISE` ... – Vahagn Avagyan Aug 10 '19 at 12:43
  • I don't know how this should help... – Bastian Aug 10 '19 at 12:49
  • will angle be 0 after rotation? x and y will be moved according to the "adjust transformation ..." lines. You could also transform the rotatedRect corner points with cv::perspectiveTransform and compute minAreaRect on the result. – Micka Aug 10 '19 at 12:50
  • The angle will be close to zero but not exactly. I estimate text lines in an swt image and perform a rotation according to the angle. – Bastian Aug 10 '19 at 12:53
  • Could you provide an example of your suggestion please? A simple formula would be less expensive but I can fix that later. – Bastian Aug 10 '19 at 12:59
  • I'm writing from mobile, so hard to provide code. rotatedRect has class members to get the 4 corner points. Add them to a vector and use the function cv::perspectiveTransform to warp them according to your transformation (you have to add a [0,0,1] row to your transformation, though, because of affine->perspective). Afterwards you have the transformed rotatedRect's corner points and can use cv::minAreaRect to compute the new rotatedRect from them. – Micka Aug 10 '19 at 13:18
  • Thank you. See my own answer to the question. This is quite similar to your suggestion but only using cv::transform(). – Bastian Aug 11 '19 at 09:01

1 Answers1

0

The answer is quite simple. We can reuse the transformation matrix for a point transform using cv::transform. Sample code is below:

        cv::Point2f points[4];
        connected_components[i].points(points);
        std::vector<cv::Point2f> old_points;
        old_points.insert(old_points.begin(), std::begin(points), std::end(points));
        std::vector<cv::Point2f> new_points;
        cv::transform(old_points, new_points, rotation_matrix);
        for (unsigned int j = 0; j < 4; ++j) {
            cv::line(dest, new_points[j], new_points[(j + 1) % 4], cv::Scalar(0, 255, 0));
        }
Bastian
  • 1,553
  • 13
  • 33