What happens if I give more inputs in estimateRigidTransform or getAffineTransform?

后端 未结 1 1869
独厮守ぢ
独厮守ぢ 2021-02-06 11:06

I am using estimateRigidTransform with about two vectors of 100 points and is working FINE. But somehow getAffineTransform doesn\'t work.

I know that findHomography find

相关标签:
1条回答
  • 2021-02-06 11:58

    The functions you mentioned can be split into 3 different types:

    Type 1: getAffineTransform and getPerspectiveTransform. Given 3 points on one plane and 3 matching points on another you can calculate affine transform between those planes. And given 4 points you can find perspective transform. This is all what getAffineTransform and getPerspectiveTransform can do: they require 3 and 4 pairs of points, no more no less, and calculate relevant transform. The one and the only.

    Type 2: estimateRigidTransform. If you can't get your points with absolute precision (which is normally the case when you get them from an image) then you need more than 3 pairs of points to reduce the error. The more the merrier (i.e. better accuracy). There more than one way to define the error you want to reduce, as well as what approach you use to find the minimal error. estimateRigidTransform is minimizing least square error (I think the most popular error definition). It does this by solving system of equations. If you provide 3 point exactly then the result, of course, will be the same as result of getAffineTransform. You can ask why we need getAffineTransform in OpenCV if estimateRigidTransform can do its work. Alas, this is not the only redundancy in OpenCV.

    Type 3: findHomography. This one is more advanced. Not only it can deal with errors in locations of points, but it can also deal with existence of the outliers. If there some wrong matches between points then using them for least square error estimation will lead to very bad accuracy. It can use RANSAC or LMeDs to test possible matches and eliminate those outliers. It works like multiple iterations of estimateRigidTransform: find least square match for different sub-sets of points. If you know that no outliers are present then you can set the 'method' argument to 0, and it will work like estimateRigidTransform - by trying to minimize least square error created from match of all points.

    Edit. Thank to Micka for his comment.

    I guess my memory is playing tricks on me. I remembered that estimateRigidTransform was implemented through system of equations in OpenCV, but now I checked it and saw that Micka is right. It does uses some hard coded RANSAC in it... Sorry for misguiding you.

    For those who are still interested in having closed form solution instead of RANSAC, here it is:

    // find affine transformation between two pointsets (use least square matching)
    static bool computeAffine(const vector<Point2d> &srcPoints, const vector<Point2d> &dstPoints, Mat &transf)
    {
        // sanity check
        if ((srcPoints.size() < 3) || (srcPoints.size() != dstPoints.size()))
            return false;
    
        // container for output
        transf.create(2, 3, CV_64F);
    
        // fill the matrices
        const int n = (int)srcPoints.size(), m = 3;
        Mat A(n,m,CV_64F), xc(n,1,CV_64F), yc(n,1,CV_64F);
        for(int i=0; i<n; i++)
        {
            double x = srcPoints[i].x, y = srcPoints[i].y;
            double rowI[m] = {x, y, 1};
            Mat(1,m,CV_64F,rowI).copyTo(A.row(i));
            xc.at<double>(i,0) = dstPoints[i].x;
            yc.at<double>(i,0) = dstPoints[i].y;
        }
    
        // solve linear equations (for x and for y)
        Mat aTa, resX, resY;
        mulTransposed(A, aTa, true);
        solve(aTa, A.t()*xc, resX, DECOMP_CHOLESKY);
        solve(aTa, A.t()*yc, resY, DECOMP_CHOLESKY);
    
        // store result
        memcpy(transf.ptr<double>(0), resX.data, m*sizeof(double));
        memcpy(transf.ptr<double>(1), resY.data, m*sizeof(double));
    
        return true;
    }
    
    0 讨论(0)
提交回复
热议问题