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

Ale*_*lex 6 c++ opencv image-processing homography affinetransform

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

  • M - 仿射变换 - 使用estimateRigidTransform()
  • H - 透视(单应性)转换 - 使用FeatureDetector(SIFT,SURF,BRISK,FREAK,......),然后FlannBasedMatcherfindHomography()

然后我可以这样做:

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

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

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

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

  • 仿射变换: M3 = M1 + M2;
  • 透视变换: H3 = H1 + H2;

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

ray*_*ica 5

不,您需要矩阵相乘以获得级联效果.我不会进入数学,但将变换应用于坐标是执行矩阵乘法的问题.如果您对如何知道原因感到好奇,我会向您推荐这篇关于级联矩阵变换的维基百科文章.给定坐标X和变换矩阵M,您可以Y通过以下方式获得输出坐标:

Y = M*X
Run Code Online (Sandbox Code Playgroud)

这里我*用来指代矩阵乘法而不是逐元素乘法.你有什么是一对变换矩阵,从走的img1img2,然后img2img3.你需要做两次操作.因此,从去img1img2哪里X所属的坐标空间img1,我们已经(假设我们使用仿射矩阵):

Y1 = M1*X
Run Code Online (Sandbox Code Playgroud)

其次,从去img2img3,我们有:

Y2 = M2*Y1 --> Y2 = M2*M1*X --> Y2 = M3*X --> M3 = M2*M1
Run Code Online (Sandbox Code Playgroud)

因此,要获得所需的链效应,您需要创建一个M2乘以的新矩阵M1.与H2和相同H1.

因此,定义一个新矩阵,以便:

cv::Mat M3 = M2*M1;
Run Code Online (Sandbox Code Playgroud)

类似地,对于投影矩阵,您可以:

cv::Mat H3 = H2*H1;
Run Code Online (Sandbox Code Playgroud)

但是,estimateRigidTransform(输出是M在你的情况下)给你一个2 x 3矩阵.一个技巧是增加这个矩阵,使它变成3 x 3,我们在其中添加一个额外的行,除了最后一个元素(设置为1)之外全部为0. 因此,你将得到最后一行[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);
Run Code Online (Sandbox Code Playgroud)

当处理cv::Mat*操作符时,它被重载以专门执行矩阵乘法.

然后,您可以使用M3H3warpAffinewarpPerspective分别.


希望这可以帮助!