OpenCV triangulatePoints用手

时间:2015-10-01 14:02:32

标签: c++ opencv triangulation

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

相机的投影矩阵 Projection matrix for left camera

相机Projection matrix for right camera

的投影矩阵

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

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

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

手性提醒: Handedness reminder

我假设每个摄影机的初始方向都指向在正Z轴方向

因此,通过使用像我在开头提到的那些投影矩阵,我会假设相机在这样的空间中定位:

How I imagine cameras are positioned and oriented in space

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

Cameras in Left Hand coordinate system

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

此外,如果我尝试将triangulatePointssolvePnP合并,我会遇到问题。

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

实施例

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

points3D enter image description here

Here是生成这些点的代码。

移动,设置相机 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;

投影 A D 观察时points3D的像素坐标是多少。

Mat points2D_a = projectionMatrix_a * points3D;
Mat points2D_d = projectionMatrix_d * points3D;

我把它们放在载体中:

vector<Point2f> points2Dvector_a, points2Dvector_d;

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

Mat points3DHomogeneous;
triangulatePoints(projectionMatrix_a, projectionMatrix_d, points2Dvector_a, points2Dvector_d, points3DHomogeneous);
Mat triangulatedPoints3D;
transpose(points3DHomogeneous, triangulatedPoints3D);
convertPointsFromHomogeneous(triangulatedPoints3D, triangulatedPoints3D);

现在,triangulatedPoints3D就像这样开始:

enter image description here

,它们与points3D相同。

然后是最后一步。

Mat rvec, tvec;
solvePnP(triangulatedPoints3D, points2Dvector_d, cameraMatrix, distCoeffs, rvec, tvec);

结果rvectvec

enter image description here enter image description here

我原本希望得到更类似于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;

然后我得到rvectvec

enter image description here enter image description here

这更有意义。但后来我改变了起始变换,使旋转为负CV_PI / 6.0 - &gt; -CV_PI / 6.0生成的rvectvec为:

enter image description here enter image description here

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

1 个答案:

答案 0 :(得分:2)

OpenCV坐标系是右撇子,答案here给出了一个关于OpenCV相机系统的说明性示例。我想混淆是关于rvectvec,后者不会给出相机的翻译,但它指向世界的起源。第一个答案here基于一个例子来解释它。您可以通过简单的矩阵乘法从solvePnP的输出中获取实际投影矩阵,第一个答案中的详细信息为here