Ios 使用SceneKit和OpenCV的增强现实。[外在矩阵]

Ios 使用SceneKit和OpenCV的增强现实。[外在矩阵],ios,opencv,matrix,opengl-es,scenekit,Ios,Opencv,Matrix,Opengl Es,Scenekit,一段时间以来,我一直在尝试让AR应用程序与SceneKit和OpenCV一起工作。我有些东西可以用,但还不够好 这是一个稍微复杂的管道,所以我将分部分描述它,也许你可以告诉我我是否犯了错误的假设/逻辑错误 首先,我通过运行用于相机校准的标准opencv棋盘算法来获得内在矩阵 然后我使用 intrinsic matrix, 3D model of the marker, points in the image corresponding to the marker

一段时间以来,我一直在尝试让AR应用程序与
SceneKit
OpenCV
一起工作。我有些东西可以用,但还不够好

这是一个稍微复杂的管道,所以我将分部分描述它,也许你可以告诉我我是否犯了错误的假设/逻辑错误

首先,我通过运行用于相机校准的标准
opencv
棋盘算法来获得
内在矩阵

然后我使用

     intrinsic matrix,
     3D model of the marker,
     points in the image corresponding to the marker
opencv
solvePnP
(++
rodrigues
)中获取
外部矩阵
。标准的东西

现在我需要将这个
外部矩阵
OpenCv
坐标系
转换为
SceneKit
坐标系

此转换如下所示:

由于
OpenCV
具有左手坐标系:

  • +Z
    远离摄像机

  • +X
    右侧

  • +Y
    向下
SceneKit
有一个右手坐标系:

  • +Z
    插入摄像头
  • +X
    右侧
  • +Y
    向上
我使用此代码反转
Y
Z
轴:

    // convert from left hand coor in opencv to right handed coor in opengl and scenekit

    cv::Mat cvToGl = cv::Mat::zeros(4, 4, CV_32F);
    cvToGl.at<float>(0, 0) = 1.0f;
    cvToGl.at<float>(1, 1) = -1.0f; // Invert the y axis.
    cvToGl.at<float>(2, 2) = -1.0f; // invert the z axis
    cvToGl.at<float>(3, 3) = 1.0f;

    extrinMatrix = cvToGl * extrinMatrix; 
因此,要按如下方式进行转换:

-(SCNMatrix4) transformToSceneKit:(cv::Mat&) RightHandtransform
{

    SCNMatrix4 mat = SCNMatrix4Identity; 

    // RightHandtransform is column major
    // Scene Kit is row major.
    RightHandtransform = RightHandtransform.t(); // Take the transpose

    // Copy the rotation rows
    // Copy the first row.
    mat.m11 = RightHandtransform.at<float>(0,0);
    mat.m12 = RightHandtransform.at<float>(0,1);
    mat.m13 = RightHandtransform.at<float>(0,2);
    mat.m14 = RightHandtransform.at<float>(0,3);

    mat.m21 = RightHandtransform.at<float>(1,0);
    mat.m22 = RightHandtransform.at<float>(1,1);
    mat.m23 = RightHandtransform.at<float>(1,2);
    mat.m24 = RightHandtransform.at<float>(1,3);

    mat.m31 = RightHandtransform.at<float>(2,0);
    mat.m32 = RightHandtransform.at<float>(2,1);
    mat.m33 = RightHandtransform.at<float>(2,2);
    mat.m34 = RightHandtransform.at<float>(2,3);

    //Copy the translation row. Which is the bottom row in SceneKIT
    mat.m41 = RightHandtransform.at<float>(3,0);
    mat.m42 = RightHandtransform.at<float>(3,1);
    mat.m43 = RightHandtransform.at<float>(3,2);
    mat.m44 = RightHandtransform.at<float>(3,3);

    return mat;
}
-(SCNMatrix4)转换到场景:(cv::Mat&)右手转换
{
SCNMatrix4 mat=SCNMatrix4标识;
//RightHandtransform是主列
//场景套件是排大调。
RightHandtransform=RightHandtransform.t();//进行转置
//复制旋转行
//复制第一行。
mat.m11=在(0,0)处的右手变换;
mat.m12=在(0,1)处的右手变换;
mat.m13=在(0,2)处的右手变换;
mat.m14=在(0,3)处的右手变换;
mat.m21=在(1,0)处的右手变换;
mat.m22=在(1,1)处的右手变换;
mat.m23=在(1,2)处的右手变换;
mat.m24=在(1,3)处的右手变换;
mat.m31=在(2,0)处的右手变换;
mat.m32=在(2,1)处的右手变换;
mat.m33=在(2,2)处的右手变换;
mat.m34=在(2,3)处的右手变换;
//复制翻译行。这是SceneKIT中的底行
mat.m41=右手变换在(3,0)处;
mat.m42=在(3,1)处的右手变换;
mat.m43=在(3,2)处的右手变换;
mat.m44=在(3,3)处的右手变换;
返回垫;
}
问题2:这种转换正确吗?我所做的转置应该从
列主键
顺序转换为
行主键
顺序

现在我们有了
场景工具包中
opencv
中的外部矩阵。我对此不是绝对确定,因为我发现了与此相关的冲突信息,但从
solvePnP
获得的外部矩阵描述了模型在摄影机坐标系中的旋转和平移

问题3:是这样吗

所以现在我唯一要做的就是设置
SCNNode
的变换属性,模型应该显示在
SCNCamera
坐标系的正确位置。但它有点车

我还有一些代码,用于从摄影机坐标进行透视投影,以剪裁空间(
NDC
)。由于篇幅的关系,我将把它写成不同的问题

问题4:我做出的假设是否合理

我在图形方面没有很多经验,所以如果我做了一些非常愚蠢的事情,请提醒我。多谢各位

旁注:


我对使用3D派对软件不感兴趣

@sleek这部分有3个问题。我认为把问题分成几个小问题并不能提供足够的上下文。我很高兴你编辑了你的问题。我对其进行了进一步编辑,使其更加清晰。GL.@SLEK非常感谢您的更正。@nnrales:您知道如何正确创建投影矩阵和透视矩阵以使用OpenCV吗?OpenCV和SceneKit都有右手坐标系。它们只是相对于相机的方向不同。
-(SCNMatrix4) transformToSceneKit:(cv::Mat&) RightHandtransform
{

    SCNMatrix4 mat = SCNMatrix4Identity; 

    // RightHandtransform is column major
    // Scene Kit is row major.
    RightHandtransform = RightHandtransform.t(); // Take the transpose

    // Copy the rotation rows
    // Copy the first row.
    mat.m11 = RightHandtransform.at<float>(0,0);
    mat.m12 = RightHandtransform.at<float>(0,1);
    mat.m13 = RightHandtransform.at<float>(0,2);
    mat.m14 = RightHandtransform.at<float>(0,3);

    mat.m21 = RightHandtransform.at<float>(1,0);
    mat.m22 = RightHandtransform.at<float>(1,1);
    mat.m23 = RightHandtransform.at<float>(1,2);
    mat.m24 = RightHandtransform.at<float>(1,3);

    mat.m31 = RightHandtransform.at<float>(2,0);
    mat.m32 = RightHandtransform.at<float>(2,1);
    mat.m33 = RightHandtransform.at<float>(2,2);
    mat.m34 = RightHandtransform.at<float>(2,3);

    //Copy the translation row. Which is the bottom row in SceneKIT
    mat.m41 = RightHandtransform.at<float>(3,0);
    mat.m42 = RightHandtransform.at<float>(3,1);
    mat.m43 = RightHandtransform.at<float>(3,2);
    mat.m44 = RightHandtransform.at<float>(3,3);

    return mat;
}