我想采用从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个步骤
- 单应性的第一列乘以 x
- 单应性的第二列乘以y
- 单应性图的第三列乘以 1
- 得到的第一个和第二个向量元素除以第三个向量元素
您需要在 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
中的a
,m12
相当于 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)
};
}