使用estimateRigidTransform代替findHomography。

6
下面链接中的示例正在使用 findHomography 来获取两个点集之间的变换。我想限制变换中使用的自由度,因此想要用 estimateRigidTransform 替换 findHomography

http://docs.opencv.org/doc/tutorials/features2d/feature_homography/feature_homography.html#feature-homography

下面我使用estimateRigidTransform来获取物体和场景点之间的变换。objPointsscePointsvector <Point2f>表示。
Mat H = estimateRigidTransform(objPoints, scePoints, false);

按照上面教程中的方法,我想使用变换H来改变角落的值。该教程使用findHomography返回的3x3矩阵与perspectiveTransform一起使用。对于刚性变换,它只返回一个2x3矩阵,所以不能使用这种方法。

如何使用这个2x3矩阵转换表示为vector <Point2f>的角落值。我只是想执行与教程相同的功能,但变换的自由度较少。我也尝试了其他方法,如warpAffinegetPerspectiveTransform,但迄今为止没有找到解决方案。

编辑:

我尝试了David Nilosek的建议。下面我将额外的行添加到矩阵中。

Mat row = (Mat_<double>(1,3) << 0, 0, 1);
H.push_back(row);

然而,当使用perspectiveTransform时会出现此错误。
OpenCV Error: Assertion failed (mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0)) in create, file /Users/cgray/Downloads/opencv-2.4.6/modules/core/src/matrix.cpp, line 1486
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /Users/cgray/Downloads/opencv-2.4.6/modules/core/src/matrix.cpp:1486: error: (-215) mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0) in function create

ChronoTrigger建议使用warpAffine。我在下面调用了warpAffine方法,1 x 5的大小是objCornerssceCorners的大小。

warpAffine(objCorners, sceCorners, H, Size(1,4));

这导致了下面的错误,表明类型错误。 objCornerssceCorners 是表示4个角落的vector <Point2f>。 我以为 warpAffine 会接受可能会解释错误的Mat图像。
OpenCV Error: Assertion failed ((M0.type() == CV_32F || M0.type() == CV_64F) && M0.rows == 2 && M0.cols == 3) in warpAffine, file /Users/cgray/Downloads/opencv-2.4.6/modules/imgproc/src/imgwarp.cpp, line 3280
3个回答

5
我过去是这样做的:
cv::Mat R = cv::estimateRigidTransform(p1,p2,false);

    if(R.cols == 0)
    {
        continue;
    }

    cv::Mat H = cv::Mat(3,3,R.type());
    H.at<double>(0,0) = R.at<double>(0,0);
    H.at<double>(0,1) = R.at<double>(0,1);
    H.at<double>(0,2) = R.at<double>(0,2);

    H.at<double>(1,0) = R.at<double>(1,0);
    H.at<double>(1,1) = R.at<double>(1,1);
    H.at<double>(1,2) = R.at<double>(1,2);

    H.at<double>(2,0) = 0.0;
    H.at<double>(2,1) = 0.0;
    H.at<double>(2,2) = 1.0;


    cv::Mat warped;
    cv::warpPerspective(img1,warped,H,img1.size());

这与David Nilosek建议的相同:在矩阵末尾添加一个0 0 1行

此代码使用刚性变换来扭曲图像。

如果您想要扭曲/转换点,则必须使用3x3矩阵的perspectiveTransform函数(http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=perspectivetransform#perspectivetransform

教程在此处:

http://docs.opencv.org/doc/tutorials/features2d/feature_homography/feature_homography.html

或者您可以通过循环遍历向量来手动完成

cv::Point2f result;
result.x = point.x * R.at<double>(0,0) + point.y * R.at<double>(0,1) + R.at<double>(0,2);
result.y = point.x * R.at<double>(1,0) + point.y * R.at<double>(1,1) + R.at<double>(1,2);

希望这能有所帮助。
备注:没有测试手动代码,但应该可以工作。那里不需要进行PerspectiveTransform转换!
编辑:这是完整的(经过测试的)代码:
// points
std::vector<cv::Point2f> p1;
p1.push_back(cv::Point2f(0,0));
p1.push_back(cv::Point2f(1,0));
p1.push_back(cv::Point2f(0,1));

// simple translation from p1 for testing:
std::vector<cv::Point2f> p2;
p2.push_back(cv::Point2f(1,1));
p2.push_back(cv::Point2f(2,1));
p2.push_back(cv::Point2f(1,2));

cv::Mat R = cv::estimateRigidTransform(p1,p2,false);

// extend rigid transformation to use perspectiveTransform:
cv::Mat H = cv::Mat(3,3,R.type());
H.at<double>(0,0) = R.at<double>(0,0);
H.at<double>(0,1) = R.at<double>(0,1);
H.at<double>(0,2) = R.at<double>(0,2);

H.at<double>(1,0) = R.at<double>(1,0);
H.at<double>(1,1) = R.at<double>(1,1);
H.at<double>(1,2) = R.at<double>(1,2);

H.at<double>(2,0) = 0.0;
H.at<double>(2,1) = 0.0;
H.at<double>(2,2) = 1.0;

// compute perspectiveTransform on p1
std::vector<cv::Point2f> result;
cv::perspectiveTransform(p1,result,H);

for(unsigned int i=0; i<result.size(); ++i)
    std::cout << result[i] << std::endl;

这将按预期输出:

[1, 1]
[2, 1]
[1, 2]

我仍然收到有关类型的相同错误消息,我认为这意味着objCorners和sceCorners。它们不是Mat矩阵,它们是Point2f向量,因为我目前只想将变换应用于角值。 - Tom smith
啊,好的,抱歉。你可以手动进行乘法运算: result.x = a.x*transf.at<double>(0,0) + a.y*transf.at<double>(0,1) + transf.at<double>(0,3); result.y = ... 这是标准矩阵乘法。我发现这比一些点到矩阵转换更少出错。 - Micka
@Tomsmith添加了“tested”代码,用于在刚性变换下使用Point2f稀疏向量的perspectiveTransform。 - Micka
1
我已经用手动代码使其工作,但我也会尝试您所做的修改,谢谢! - Tom smith

5

使用函数cv::warpAffine将仿射变换(即cv::estimateRigidTransform的结果)应用于图像。


我已经更新了问题,并在尝试了您的建议后得到了结果。 - Tom smith

3
一个刚性变换的3x3单应形式为:
 a1 a2 b1
-a2 a3 b2
  0  0  1

当使用estimateRigidTransform时,如果您想要3x3的矩阵,可以将[0 0 1]添加为第三行。


我已经尝试实现这个,但在调用perspectiveTransform时出现了错误,我已在原问题的编辑中进行了描述。 - Tom smith
根据抛出的异常猜测,这些矩阵不是同一类型。这个函数只是一个矩阵乘法后跟着一个除法,如果你不知道如何使用该函数,你可以编写代码来实现它。 - David Nilosek
我没有使用矩阵进行perspectiveTransform,而是使用了两个Point2f向量,它们是相同类型的。这些向量与教程链接中使用的相同,只是使用了不同的变换矩阵。 - Tom smith
这似乎不太对。刚性变换可以使用旋转和平移。因此,它将仿射变换的 [a1,a2; -a2,a3] 限制为旋转矩阵的值。 - Gelliant
抱歉,我有些困惑。在openCV中的命名有点奇怪。刚性变换通常意味着您只使用旋转和平移。因此,它将仿射变换的[a1,a2; -a2,a3]限制为旋转矩阵的值。但是,estimateRigidTransform将仅估计仿射变换。可能是他们更新命名的原因。 - Gelliant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接