OpenCV triangulatePoints用手

anc*_*jic 24 c++ opencv triangulation

我有两个严格并排连接的摄像机,朝向平行方向.

摄像头的 投影矩阵左摄像头的投影矩阵

适用于相机的投影矩阵适用于右相机的投影矩阵

当我triangulatePoints对相应点的两个向量执行时,我得到了3D空间中的点集合.3D空间中的所有点都具有负Z坐标.

所以,要深究这个......

我的假设是OpenCV使用右手坐标系.

用户提醒: 用手提醒

我假设每个摄像机的初始方向指向正Z轴方向.

因此,通过使用像我在开头提出的那些投影矩阵,我会假设摄像机位于空间中,如下所示:

我怎么想象相机在太空中定位和定向

这个假设与我观察到的负数Z corrdinates的交错点时的观察结果相冲突.我能想到的唯一解释是OpenCV实际上使用左手坐标系.因此,对于我在开头所述的投影矩阵,这就是摄像机在太空中的定位方式:

左手坐标系中的摄像头

这表明我的左侧相机在这种情况下不在左侧.这就是为什么我得分为负的深度.

而且,如果我尝试triangulatePointssolvePnP我结合遇到问题.

我使用输出triangulatePoints作为输入solvePnP.我希望相机坐标靠近3D坐标系的原点.我希望计算出的相机位置与开头使用的投影矩阵相匹配.但这不会发生.我得到了一些完全狂野的结果,错过了预期值超过基线长度的10倍.

此示例比上述内容更完整地表示问题.

points3D 在此输入图像描述

以下是生成这些点的代码.

移动,设置相机A和相机D ...

Mat cameraMatrix = (Mat_<double>(3, 3) <<
    716.731, 0, 660.749,
    0, 716.731, 360.754,
    0, 0, 1);
Mat distCoeffs = (Mat_<double>(5, 1) << 0, 0, 0, 0, 0);



Mat rotation_a = Mat::eye(3, 3, CV_64F); // no rotation
Mat translation_a = (Mat_<double>(3, 1) << 0, 0, 0); // no translation
Mat rt_a;
hconcat(rotation_a, translation_a, rt_a);
Mat projectionMatrix_a = cameraMatrix * rt_a; 

Mat rotation_d = (Mat_<double>(3, 1) << 0, CV_PI / 6.0, 0); // 30° rotation about Y axis
Rodrigues(rotation_d, rotation_d); // convert to 3x3 matrix
Mat translation_d = (Mat_<double>(3, 1) << 100, 0, 0);
Mat rt_d;
hconcat(rotation_d, translation_d, rt_d);
Mat projectionMatrix_d = cameraMatrix * rt_d;
Run Code Online (Sandbox Code Playgroud)

points3D投影AD观察时的像素坐标是多少.

Mat points2D_a = projectionMatrix_a * points3D;
Mat points2D_d = projectionMatrix_d * points3D;
Run Code Online (Sandbox Code Playgroud)

我把它们放在矢量中:

vector<Point2f> points2Dvector_a, points2Dvector_d;
Run Code Online (Sandbox Code Playgroud)

之后,我再次生成3D点.

Mat points3DHomogeneous;
triangulatePoints(projectionMatrix_a, projectionMatrix_d, points2Dvector_a, points2Dvector_d, points3DHomogeneous);
Mat triangulatedPoints3D;
transpose(points3DHomogeneous, triangulatedPoints3D);
convertPointsFromHomogeneous(triangulatedPoints3D, triangulatedPoints3D);
Run Code Online (Sandbox Code Playgroud)

现在,triangulatedPoints3D从这样开始:

在此输入图像描述

他们是完全相同的points3D.

然后是最后一步.

Mat rvec, tvec;
solvePnP(triangulatedPoints3D, points2Dvector_d, cameraMatrix, distCoeffs, rvec, tvec);
Run Code Online (Sandbox Code Playgroud)

结果rvectvec:

在此输入图像描述在此输入图像描述

我曾希望得到更类似于创建中使用的变换projectionMatrix_d,即(100,0,0)的平移和绕Y轴旋转30°.

如果我在创建投影矩阵时使用反转换,如下所示:

Mat rotation_d = (Mat_<double>(3, 1) << 0, CV_PI / 6.0, 0); // 30° rotation about Y axis
Rodrigues(-rotation_d, rotation_d); // NEGATIVE ROTATION
Mat translation_d = (Mat_<double>(3, 1) << 100, 0, 0);
Mat rt_d;
hconcat(rotation_d, -translation_d, rt_d); // NEGATIVE TRANSLATION
Mat projectionMatrix_d = cameraMatrix * rt_d;
Run Code Online (Sandbox Code Playgroud)

然后我得到rvectvec:

在此输入图像描述在此输入图像描述

这更有意义.但后来我改变开始转变使得旋转为负CV_PI / 6.0- > -CV_PI / 6.0所得rvectvec有:

在此输入图像描述在此输入图像描述

我想找到解释为什么会发生这种情况的原因.为什么我会得到如此奇怪的结果solvePnP.

ilk*_*444 3

OpenCV坐标系是右手坐标系,这里的答案给出了一个关于OpenCV相机系统的说明性例子。我猜困惑在于rvectvec,后者没有给出相机的翻译,但它指向世界原点。这里的第一个答案根据示例进行了解释。您可以通过简单的矩阵乘法从输出中获得实际的投影矩阵solvePnP,详细信息第一个答案中。