如果我在estimateRigidTransform或getAffineTransform中提供更多输入会发生什么?

时间:2014-08-19 04:16:06

标签: opencv

我使用的是带有两个100点向量的estimateRigidTransform,并且工作正常。 但不知怎的,getAffineTransform不起作用。

我知道findHomography使用RANSAC找到最佳矩阵,getPerspectiveTransform只需要4个点。

我的问题是如果我在estimateRigidTransform或getAffineTransform中提供更多输入会发生什么?

输入矩阵只需要4个点吗?或者做某种RANSAC?

1 个答案:

答案 0 :(得分:18)

您提到的功能可以分为3种不同的类型:

类型1:getAffineTransform和getPerspectiveTransform。给定一个平面上的3个点和另一个平面上的3个匹配点,您可以计算这些平面之间的仿射变换。给出4分,你可以找到透视变换。这就是getAffineTransform和getPerspectiveTransform可以做的事情:它们需要3对和4对点,不多也不少,并计算相关变换。唯一的。

类型2:estimateRigidTransform。如果你不能以绝对精度获得你的点(通常是从图像中获取它们的情况),那么你需要超过3对点来减少误差。越多越好(即更好的准确性)。有多种方法可以定义要减少的错误,以及用于查找最小错误的方法。 estimateRigidTransform正在最小化最小平方误差(我认为最流行的错误定义)。它通过求解方程组来实现。如果你提供3点,那么结果当然与getAffineTransform的结果相同。如果estimateRigidTransform可以完成其工作,您可以问我们为什么需要在OpenCV中使用getAffineTransform。唉,这不是OpenCV中唯一的冗余。

类型3:findHomography。这个更先进。它不仅可以处理点位置的错误,而且还可以处理异常值的存在。如果点之间存在一些错误的匹配,那么使用它们进行最小平方误差估计将导致非常差的精度。它可以使用RANSAC或LMeD来测试可能的匹配并消除这些异常值。它的工作方式类似于estimateRigidTransform的多次迭代:找到不同子点集的最小二乘匹配。如果您知道没有异常值,那么您可以设置'方法'参数为0,它将像estimateRigidTransform一样工作 - 通过尝试最小化从所有点的匹配创建的最小平方误差。

修改。感谢Micka的评论。

我想我的记忆在欺骗我。我记得estimateRigidTransform是通过OpenCV中的方程系统实现的,但现在我检查了它,看到Micka是对的。它确实使用了一些硬编码的RANSAC ...抱歉误导了你。

对于那些仍然有兴趣使用封闭式解决方案代替RANSAC的人来说,这里是:

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