我正在使用estimateRigidTransform和大约两个100点的向量,并且工作正常.但不知何故getAffineTransform不起作用.
我知道findHomography使用RANSAC找到最好的矩阵,getPerspectiveTransform只需要4个点.
我的问题是如果我在estimateRigidTransform或getAffineTransform中提供更多输入会发生什么?
输入矩阵只需要4个点吗?或者做某种RANSAC?
Mic*_*nov 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的多次迭代:找到不同子点集的最小二乘匹配.如果您知道不存在异常值,那么您可以将'method'参数设置为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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2746 次 |
| 最近记录: |