pythonopencvimage-processingcomputer-visionaffinetransform

Combine rotation and translation in opencv, in one pass


I have a piece of code for rotating and translating image:

Point2f pt(0, in.rows);
double angle = atan(trans.c / trans.b) * 180 / M_PI;
Mat r = getRotationMatrix2D(pt, -angle, 1.0);
warpAffine(in, out, r, in.size(), interpolation); /* rotation */

Mat t = (Mat_<double>(2, 3) << 1, 0, trans.a, 0, 1, -trans.d);
warpAffine(out, out, t, in.size(), interpolation); /* translation */

The problem is that I'm doing this in two times. So if I have an angle of 90degree for example, the first "out" variable will be empty because all data are out of bounds. Is there a way to do it in one pass ? In order to avoid loosing my data and having black image.

I think that the best thing would be to combine r and t in one matrix but I'm a little lost.

Best regards,


Solution

  • Here is an example on how to combine 2 homographies by simple multiplication and how to extract an affine transformation from a 3x3 homography.

    int main(int argc, char* argv[])
    {
        cv::Mat input = cv::imread("C:/StackOverflow/Input/Lenna.png");
    
        // create to 3x3 identity homography matrices
        cv::Mat homography1 = cv::Mat::eye(3, 3, CV_64FC1);
        cv::Mat homography2 = cv::Mat::eye(3, 3, CV_64FC1);
    
        double alpha1 = -13; // degrees
        double t1_x = -86; // pixel
        double t1_y = -86; // pixel
    
        double alpha2 = 21; // degrees
        double t2_x = 86; // pixel
        double t2_y = 86; // pixel
    
        // hope there is no error in the signs:
        // combine homography1
        homography1.at<double>(0, 0) = cos(CV_PI*alpha1 / 180);
        homography1.at<double>(0, 1) = -sin(CV_PI*alpha1 / 180);
        homography1.at<double>(1, 0) = sin(CV_PI*alpha1 / 180);
        homography1.at<double>(1, 1) = cos(CV_PI*alpha1 / 180);
        homography1.at<double>(0, 2) = t1_x;
        homography1.at<double>(1, 2) = t1_y;
    
        // compose homography2
        homography2.at<double>(0, 0) = cos(CV_PI*alpha2 / 180);
        homography2.at<double>(0, 1) = -sin(CV_PI*alpha2 / 180);
        homography2.at<double>(1, 0) = sin(CV_PI*alpha2 / 180);
        homography2.at<double>(1, 1) = cos(CV_PI*alpha2 / 180);
        homography2.at<double>(0, 2) = t2_x;
        homography2.at<double>(1, 2) = t2_y;
    
        cv::Mat affine1 = homography1(cv::Rect(0, 0, 3, 2));
        cv::Mat affine2 = homography2(cv::Rect(0, 0, 3, 2));
    
        cv::Mat dst1;
        cv::Mat dst2;
    
        cv::warpAffine(input, dst1, affine1, input.size());
        cv::warpAffine(input, dst2, affine2, input.size());
    
    
        cv::Mat combined_homog = homography1*homography2;
        cv::Mat combined_affine = combined_homog(cv::Rect(0, 0, 3, 2));
    
        cv::Mat dst_combined;
    
        cv::warpAffine(input, dst_combined, combined_affine, input.size());
    
        cv::imshow("input", input);
        cv::imshow("dst1", dst1);
        cv::imshow("dst2", dst2);
    
        cv::imshow("combined", dst_combined);
    
        cv::waitKey(0);
        return 0;
    }
    

    In this example, an image is first rotated and translated to the left, later to the right. If the two transformations are performed after each other, significant image areas would get lost. Instead if they are combined by homograhy multiplication, it is like the full operation done in a single step without losing image parts in the intemediate step.

    input:

    enter image description here

    if image was first transformed with H1, later with H2:

    enter image description here

    if the image is transformed with the combination of H1*H2 directly:

    enter image description here

    One typical application of this homography combination is to first translate the image center to the origin, then rotate, then translate back to original position. This has the effect as if the image was rotated around its center of gravity.