4

我想采用从 OpenCVfindHomography函数返回的透视变换矩阵并将其(在 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;
};

类似的问题:

使用 Core Graphics 应用单应矩阵

将 opencv 仿射矩阵转换为 CGAffineTransform

4

3 回答 3

5

免责声明

我从来没有试过这个,所以把它和一粒盐一起吃。

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

推理

findHomography 返回的 3x3 矩阵对二维齐次向量进行运算。该过程可以分为 4 个步骤

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

您需要在 4x4 向量中复制此过程,我假设结果向量中的第三个元素对您的目的没有意义。

解决方案

像这样构造你的矩阵(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 的答案以了解转换为主要列的外观(您基本上只是转置它)。但是请注意,目前汤米和我在如何构建矩阵方面存在分歧。

于 2013-01-22T23:29:04.837 回答
4

根据我对文档的阅读,m11inCATransform3D相当于ain CGAffineTransformm12相当于b等等。

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

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

所以我想你会想要:

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

或者cvGetReal1D,如果您不使用 C++,请使用它。

于 2013-01-22T21:08:45.160 回答
0

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

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)
    };
}
于 2020-04-14T02:21:49.873 回答