【问题标题】:Can I simply add affine or perspective (homography) matrices of transformation?我可以简单地添加仿射或透视(单应)变换矩阵吗?
【发布时间】:2015-06-27 06:21:02
【问题描述】:

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

那我可以做:

  • 仿射变换 - 使用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)

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

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

或者我应该使用哪个函数?

【问题讨论】:

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


    【解决方案1】:

    不,您需要将矩阵相乘才能获得级联效果。我不会讨论数学,但对坐标应用变换是执行矩阵乘法的问题。如果您想知道为什么会这样,我建议您参考good Wikipedia article on cascading matrix transformations。给定一个坐标X 和一个变换矩阵M,您可以通过以下方式获得输出坐标Y

    Y = M*X
    

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

    Y1 = M1*X
    

    接下来,从img2img3,我们有:

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

    因此,要获得所需的连锁效应,您需要创建一个新矩阵,使M2M1 相乘。与H2H1 相同。

    所以定义一个新的矩阵:

    cv::Mat M3 = M2*M1;
    

    对于您的投影矩阵,您可以这样做:

    cv::Mat H3 = H2*H1;
    

    但是,estimateRigidTransform(在您的情况下输出为M)为您提供2 x 3 矩阵。一个技巧是增加这个矩阵,使其变为 3 x 3,我们添加一个额外的行,其中最后一个元素全部为 0 except,该元素设置为 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


    希望这会有所帮助!

    【讨论】:

    • 非常感谢!但是只有当第一个矩阵中的列数等于第二个矩阵中的行数时,才能进行矩阵乘法。 H - 透视(单应性)是一个 3x3 矩阵我可以做到:H3 = H1*H2;。但是仿射矩阵是 2x3,我不能简单地将两个仿射矩阵相乘,我不能这样做:M3 = M1*M2;。我怎样才能为仿射变换 - M 做到这一点?
    • estimateRigidTransform(); 给我 2x3 矩阵,and estimateAffine3D(); 给我 3x4 矩阵。
    • @Alex - 我添加了一些信息来帮助您处理estimateRigidTransform。我很抱歉没有早点看到。但是,estimateAffine3D 处理一个 3D 点云到另一个点云之间的转换。您不能使用它来扭曲图像,因为图像本质上是一个 2D 坐标空间。
    • @Alex - 确保您得到正确的订单。这是H2*H1M2*M1
    • @Alex - 我的荣幸。祝你好运!
    猜你喜欢
    • 2020-08-11
    • 1970-01-01
    • 1970-01-01
    • 2013-01-03
    • 1970-01-01
    • 2020-07-06
    • 1970-01-01
    • 2011-03-09
    • 2014-04-06
    相关资源
    最近更新 更多