如何使用OpenCV的triangulatePoints函数

7
我很难让OpenCV的triangulatePoints函数正常工作。我正在使用由光流生成的点匹配来调用该函数。我使用单个移动相机的两个连续帧/位置来调用该函数。
目前我的步骤如下:
给定相机内参,看起来是符合预期的:
2.6551e+003  0.           1.0379e+003
0.           2.6608e+003  5.5033e+002
0.           0.           1.

我会很乐意为您翻译IT技术相关内容。需要翻译的内容如下:

然后,我基于(高度精确的)GPS和相机相对于GPS的位置计算出两个外参矩阵([R|t])。请注意,GPS数据使用荷兰周围的笛卡尔坐标系,以米为单位(因此不需要奇怪的纬度/经度数学计算)。这样就得到了以下矩阵:

Camera extrinsic matrices

接下来,我只需删除这些矩阵的底部行,并将它们与内参矩阵相乘即可获得投影矩阵:

projectionMat = intrinsics * extrinsics;

这将导致:

投影矩阵

我的图像点只是第一组的所有像素坐标。

(0, 0)...(1080, 1920)

并且对于第二组,需要翻译出所有像素坐标及其计算得出的光流。

(0 + flowY0, 0 + flowX0)...(1080 + flowYN, 1920 + flowXN)

为了计算3D点,我将图像点(以OpenCV期望的格式)和投影矩阵输入到triangulatePoints函数中:
cv::triangulatePoints(projectionMat1, projectionMat2, imagePoints1, imagePoints2, outputPoints);

最后,我通过将outputPoints除以它们的第四个坐标(w)并移除此坐标来将其从齐次坐标转换为笛卡尔坐标系。
最终得到的是一些奇怪的锥形点云: Output 1 现在我尝试了我能想到的所有调整组合(矩阵求逆、改变X/Y/Z顺序、翻转X/Y/Z轴、改变乘法顺序等),但所有的结果都类似奇怪的输出。唯一让我得到更好结果的事情是将光流值乘以0.01。这会产生以下点云: Output 2 这仍然不完美(远离相机的区域看起来非常弯曲),但更接近我的预期。
我想知道是否有人能发现我做错了什么。我的矩阵看起来还好吗?我得到的输出与某个问题相关吗?
我很确定这与GPS或光流无关,因为我测试了多个帧,它们都产生相同类型的输出。我真的认为这与三角测量本身有关。

嘿,你是想复制一个Structure-from-Motion吗?你所提到的坐标(X,Y,Z)是在GPS坐标系中吗?这可能不是最好的来源,但是在这里你可以找到使用opencv实现SFM的完整流程。不幸的是,逐步解释此过程的书籍需要付费。 - NAmorim
@NAmorim 谢谢!那就是我也找到的那个,但我还没有完全弄清楚那个源代码和我的代码之间的区别,因为它们的结构非常不同,所以很难找出哪个矩阵是哪个。 - Wouter Florijn
1
嗯,我不确定你的代码有什么问题,但我认为你应该从使用本地坐标开始,而不是GPS(纬度、经度、高度是一个球形系统,在使用SFM时可能会导致Y轴上的奇怪伪影(在你的情况下)。例如,看看你的相机平移矩阵(t),你有大量的X和Z值(e+05级别),而Y值很小(1.238),这意味着你将在水平轴上有大的变化,而在垂直方向上则很小。因此,点云的形状很奇怪。没有测试,只是一个建议。 - NAmorim
@NAmorim 所有的观点都非常有价值,尽管我应该添加有关GPS系统的信息。所有的纬度/经度坐标都被转换为荷兰的“Rijksdriehoek”系统,这是一个包含荷兰的笛卡尔坐标系。因此,X和Z值很大,因为它们以米为单位,并且位于荷兰中部某个地方。Y值表示相机安装的高度(1.238m)。我会将这些信息编辑到问题中。 - Wouter Florijn
1
好的,那么在这个语句中,“最后,我通过将输出点乘以它们的第四个坐标(w)并移除此坐标来将其从齐次坐标转换。”你的意思是通过除以它们,对吗? - NAmorim
同样的问题在这里,使用了所有的惯例和类似于这个例子中的东西:http://www.tobias-weis.de/triangulate-3d-points-from-3d-imagepoints-from-a-moving-camera/。 - Stav Bodik
2个回答

1
函数是用于立体相机,而不是单目相机!在 opencv 文档中,我读到以下表述:该函数通过使用双目相机对三维点(使用齐次坐标)进行重建。可以从 中获取投影矩阵。

0
在我的情况下,我不得不修复旋转矩阵中使用的约定,以便计算投影矩阵,请确保两个相机都使用此约定:

Respect to OpenCv Axis and rotation conventions

rotationMatrix0 = rotation_by_Y_Matrix_Camera_Calibration(camera_roll)*rotation_by_X_Matrix_Camera_Calibration(camera_pitch)  *rotation_by_Z_Matrix_Camera_Calibration(camera_yaw);



Mat3x3 Algebra::rotation_by_Y_Matrix_Camera_Calibration(double yaw)
{
    Mat3x3 matrix;
    matrix[2][2] = 1.0f;

    double sinA = sin(yaw), cosA = cos(yaw);
    matrix[0][0] = +cosA; matrix[0][1] = -sinA;
    matrix[1][0] = +sinA; matrix[1][1] = +cosA;



    return matrix;
}

Mat3x3 Algebra::rotation_by_X_Matrix_Camera_Calibration(double pitch)
{

    Mat3x3 matrix;
    matrix[1][1] = 1.0f;

    double sinA = sin(pitch), cosA = cos(pitch);

    matrix[0][0] = +cosA; matrix[0][2] = +sinA;
    matrix[2][0] = -sinA; matrix[2][2] = +cosA;


    return matrix;
}

Mat3x3 Algebra::rotation_by_Z_Matrix_Camera_Calibration(double roll)
{

    Mat3x3 matrix;
    matrix[0][0] = 1.0f;

    double sinA = sin(roll), cosA = cos(roll);
    matrix[1][1] = +cosA; matrix[1][2] = -sinA;
    matrix[2][1] = +sinA; matrix[2][2] = +cosA;



    return matrix;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接