我可以简单地添加变换的仿射或透视(单应性)矩阵吗?

时间:2015-04-20 13:30:54

标签: c++ opencv image-processing affinetransform homography

众所周知,在OpenCV中,我可以在两幅图像之间进行仿射或透视转换:

然后我可以做:

  • 仿射变换 - 使用findHomography()
  • 透视转换 - 使用warpAffine(img_src, img_dst, M)

但如果我有3个或更多图像,我已经找到了:

  • 仿射:M1(img1 - > img2),M2(img2 - > img3)
  • 透视:H1(img1 - > img2),H2(img2 - > img3)

然后我可以通过简单地添加两个矩阵来获得变换的矩阵( img1 - > img3 )吗?

  • 的仿射变换:warpPerspective(img_src, img_dst, H)
  • 的透视变换:M3 = M1 + M2;

或者我应该使用哪种功能?

1 个答案:

答案 0 :(得分:5)

不,您需要乘以矩阵才能获得级联效果。我不会进入数学,但对坐标应用变换是执行矩阵乘法的问题。如果您对如何知道原因感到好奇,我建议你参考good Wikipedia article on cascading matrix transformations。给定坐标X和转换矩阵M,您可以得到输出坐标Y

Y = M*X

这里我使用*来指代矩阵乘法而不是逐元素乘法。您拥有的是一对转换矩阵,从img1img2再到img2img3。你需要做两次操作。所以,从img1img2 X属于img1的坐标空间,我们有(假设我们使用的是仿射矩阵):

Y1 = M1*X

接下来,从img2转到img3,我们有:

Y2 = M2*Y1 --> Y2 = M2*M1*X --> Y2 = M3*X --> M3 = M2*M1

因此,要获得所需的链效果,您需要创建一个新的矩阵,使M2乘以M1。与H2H1相同。

因此,定义一个新的矩阵:

cv::Mat M3 = M2*M1;

同样对于你的投射矩阵,你可以这样做:

cv::Mat H3 = H2*H1;

但是,estimateRigidTransform(在您的情况下输出为M)会为您提供2 x 3矩阵。一个技巧是增加这个矩阵,使其变为3 x 3,我们在其中添加一个额外的行,除了以外的最后一个元素,它被设置为1.因此,你将拥有最后一行,它变成[0 0 1]。您可以对两个矩阵执行此操作,将它们相乘,然后仅将前两行提取到新矩阵中以管道输入warpAffine。因此,做这样的事情:

// Create padded matrix for M1
cv::Mat M1new = cv::Mat(3,3,M1.type());
M1new.at<double>(0,0) = M1.at<double>(0,0);
M1new.at<double>(0,1) = M1.at<double>(0,1);
M1new.at<double>(0,2) = M1.at<double>(0,2);

M1new.at<double>(1,0) = M1.at<double>(1,0);
M1new.at<double>(1,1) = M1.at<double>(1,1);
M1new.at<double>(1,2) = M1.at<double>(1,2);

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

// Create padded matrix for M2
cv::Mat M2new = cv::Mat(3,3,M2.type());
M2new.at<double>(0,0) = M2.at<double>(0,0);
M2new.at<double>(0,1) = M2.at<double>(0,1);
M2new.at<double>(0,2) = M2.at<double>(0,2);

M2new.at<double>(1,0) = M2.at<double>(1,0);
M2new.at<double>(1,1) = M2.at<double>(1,1);
M2new.at<double>(1,2) = M2.at<double>(1,2);

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

// Multiply the two matrices together
cv::Mat M3temp = M2new*M1new;

// Extract out relevant rows and place into M3
cv::Mat M3 = cv::Mat(2, 3, M3temp.type());
M3.at<double>(0,0) = M3temp.at<double>(0,0);
M3.at<double>(0,1) = M3temp.at<double>(0,1);
M3.at<double>(0,2) = M3temp.at<double>(0,2);

M3.at<double>(1,0) = M3temp.at<double>(1,0);
M3.at<double>(1,1) = M3temp.at<double>(1,1);
M3.at<double>(1,2) = M3temp.at<double>(1,2);

处理cv::Mat*运营商时,it is overloaded to specifically perform matrix multiplication

然后,您可以分别将M3H3用于warpAffinewarpPerspective


希望这有帮助!