将 OpenCV 的 findHomography 透视矩阵转换为 iOS 的 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;
};

类似问题:

使用核心图形应用单应性矩阵

将 openCV 仿射矩阵转换为 CGAffineTransform

免责声明

我从来没有尝试过这个,所以用一粒盐来对待它。

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

推理

findHomography 返回的 3x3 矩阵在二维齐次向量上运行。 这个过程可以分为4个步骤

  1. 单应性的第一列乘以 x
  2. 单应性的第二列乘以y
  3. 单应性图的第三列乘以 1
  4. 得到的第一个和第二个向量元素除以第三个向量元素

您需要在 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 分量不受干扰地通过。

以上所有内容都是以行主要符号(如 openCV)完成的,以尽量避免混淆。 你可以看看 Tommy 的回答,看看转换为列专业的样子(你基本上只是转置它)。但请注意,目前汤米和我对如何构建矩阵存在分歧。

从我对文档的阅读来看,CATransform3D 中的m11相当于 CGAffineTransform 中的am12相当于 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

汤米的答案对我有用,但我需要使用双精度,而不是浮点数。这也是代码的缩短版本:

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)
    };
}

相关内容

  • 没有找到相关文章