将OpenCV的findHomography透视矩阵转换为iOS'CATransform3D

时间:2013-01-22 20:48:35

标签: ios opencv matrix perspective catransform3d

我想从OpenCV的findHomography函数返回透视变换矩阵,并将其转换(在C ++或Objective-C中)到iOS'CATransform3D。我希望它们尽可能地准确地再现核心图形方面的“扭曲”效果。示例代码真的很感激!

来自iOS'CATransform3D.h:

/* Homogeneous three-dimensional transforms. */

struct CATransform3D
{
    CGFloat m11, m12, m13, m14;
    CGFloat m21, m22, m23, m24;
    CGFloat m31, m32, m33, m34;
    CGFloat m41, m42, m43, m44;
};

类似的问题:

Apply homography matrix using Core Graphics

convert an opencv affine matrix to CGAffineTransform

3 个答案:

答案 0 :(得分:5)

<强>声明

我从来没有尝试过这种方式,所以请耐心等待。

CATRansform3D是一个4x4矩阵,它在3维齐次矢量(4x1)上运算,以产生相同类型的另一个矢量。我假设在渲染时,4x1向量描述的对象将每个元素除以第4个元素,而第3个元素仅用于确定哪些对象出现在其中。假设这是正确的......

<强>推理

findHomography返回的3x3矩阵在2维均匀向量上运行。可以通过4个步骤考虑该过程

  1. 单应性的第一列乘以x
  2. 单应性的第二列乘以y
  3. 单应体的第三列乘以1
  4. 将得到的第1和第2向量元素除以第3个
  5. 您需要在4x4向量中复制此过程,其中我假设结果向量中的第3个元素对于您的目的而言毫无意义。

    <强>解决方案

    像这样构造你的矩阵(H是你的单应矩阵)

    [H(0,0), H(0,1), 0, H(0,2),
     H(1,0), H(1,1), 0, H(1,2),
          0,      0, 1,      0
     H(2,0), H(2,1), 0, H(2,2)]
    

    这显然满足1,2和3. 4因为均匀元素总是最后一个。这就是为什么“同质排”,如果你不得不被撞到一行。第3行的1是让向量的z分量通过unmolested。

    以上所有内容都以行主要表示法(如openCV)完成,以避免混淆。您可以查看Tommy的答案,了解转换为专业列的外观(基本上只是转置它)。但请注意,目前Tommy和我不同意如何构建矩阵。

答案 1 :(得分:3)

在阅读文档时,m11中的CATransform3D相当于a中的CGAffineTransformm12相当于b,等等。

根据你在下面的评论,我理解矩阵OpenCV返回3x3(回想起来,它是你期望的大小)。因此,您将使用与单位矩阵等效的元素填充其他元素。根据Hammer的回答,你想要保留处理(通常是隐含的)同质坐标的部分,同时用身份填充其他所有内容。

[旁白:我原来的回答是错误的。我编辑它是正确的,因为我发布了代码而Hammer没有。这篇文章被标记为社区维基,以反映它绝不仅仅是我的答案]

所以我认为你想要:

CATransform3D MatToTransform(Mat cvTransform)
{
    CATransform3D transform;

    transform.m11 = cvTransform.at<float>(0, 0);
    transform.m12 = cvTransform.at<float>(1, 0);
    transform.m13 = 0.0f;
    transform.m14 = cvTransform.at<float>(2, 0);

    transform.m21 = cvTransform.at<float>(0, 1);
    transform.m22 = cvTransform.at<float>(1, 1);
    transform.m23 = 0.0f;
    transform.m24 = cvTransform.at<float>(2, 1);

    transform.m31 = 0.0f;
    transform.m32 = 0.0f;
    transform.m33 = 1.0f;
    transform.m34 = 0.0f;

    transform.m41 = cvTransform.at<float>(0, 2);
    transform.m42 = cvTransform.at<float>(1, 2);
    transform.m43 = 0.0f;
    transform.m44 = cvTransform.at<float>(2, 2);

    return transform;
}

如果您要保留C ++,请使用cvGetReal1D

答案 2 :(得分:0)

Tommy答案对我有用,但是我需要使用double而不是float。这也是代码的简化版本:

CATransform3D MatToCATransform3D(cv::Mat H) {
    return {
        H.at<double>(0, 0), H.at<double>(1, 0), 0.0, H.at<double>(2, 0),
        H.at<double>(0, 1), H.at<double>(1, 1), 0.0, H.at<double>(2, 1),
        0.0, 0.0, 1.0, 0.0,
        H.at<double>(0, 2), H.at<double>(1, 2), 0.0f, H.at<double>(2, 2)
    };
}