opencv 如何正确使用cv::triangulatePoints()

ukqbszuj  于 2023-03-03  发布在  其他
关注(0)|答案(5)|浏览(531)

我试图用OpenCV来三角测量一些点,我发现了这个cv::triangulatePoints()函数。问题是几乎没有文档或例子。
我对此有些怀疑。
1.它使用什么方法?我对三角测量做了一些研究,有几种方法(线性、线性LS、特征值、迭代LS、迭代特征值...),但我找不到OpenCV使用的是哪一种。
1.我应该如何使用它?它似乎需要一个投影矩阵和3xN齐次
2D
点作为输入,我将它们定义为std::vector<cv::Point3d> pnts,但作为输出,它需要4xN数组,显然我不能创建std::vector<cv::Point4d>,因为它不存在,那么我应该如何定义输出向量?
对于第二个问题,我试着回答:cv::Mat pnts3D(4, N, CV_64F);cv::Mat pnts3d;,但似乎都不起作用(它抛出异常)。

pqwbnv8z

pqwbnv8z1#

1.-使用的方法是最小二乘法。还有比这更复杂的算法。尽管如此,它仍然是最常用的一种,因为其他方法在某些情况下可能会失败(例如,如果点在平面上或无穷远处,其他一些方法会失败)。
该方法可以在 Richard Hartley和Andrew Zisserman(p312)的***计算机视觉中的多视图几何***中找到。
2.-用法

cv::Mat pnts3D(1, N, CV_64FC4);
cv::Mat cam0pnts(1, N, CV_64FC2);
cv::Mat cam1pnts(1, N, CV_64FC2);

用图像中的点填充2通道点矩阵。
cam0cam1Mat3x4摄影机矩阵(内部和外部参数)。可以通过乘以A*RT来构造它们,其中A是内部参数矩阵,RT是旋转平移3x 4姿势矩阵。

cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);

注意pnts3D需要是一个4通道1xNcv::Mat当定义时,抛出异常,如果不是,但结果是一个cv::Mat(4, N, cv_64FC1)矩阵。真的很混乱,但这是唯一的方法,我没有得到一个异常。
UPDATE:从3.0版或更早版本开始,这不再成立,pnts3D也可以是Mat(4, N, CV_64FC1)类型,或者可以完全为空(通常,它在函数内部创建)。

yzxexxkh

yzxexxkh2#

对@Ander Biguri的回答做了一点补充。您应该在非undistort艾德的图像上获取图像点,并在cam0pntscam1pnts上调用undistortPoints(),因为cv::triangulatePoints需要归一化坐标中的2D点(独立于相机),而cam0cam1应该仅为**[R|t^T]矩阵不需要乘以A**。

h79rfbju

h79rfbju3#

感谢Ander Biguri!他的回答帮了我很大的忙。但我总是更喜欢std::vector的替代方案,我将他的解决方案编辑为:

std::vector<cv::Point2d> cam0pnts;
std::vector<cv::Point2d> cam1pnts;
// You fill them, both with the same size...

// You can pick any of the following 2 (your choice)
// cv::Mat pnts3D(1,cam0pnts.size(),CV_64FC4);
cv::Mat pnts3D(4,cam0pnts.size(),CV_64F);

cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);

所以你只需要在点中做emplace_back即可。主要优点:在开始填充它们之前,你不需要知道N的大小。不幸的是,没有cv::Point 4f,所以pnts 3D必须是cv::Mat...

06odsfpq

06odsfpq4#

我试过cv::triangulatePoints,但不知怎么的它计算垃圾,我被迫手动实现线性三角测量方法,它为三角测量的3D点返回一个4x 1矩阵:

Mat triangulate_Linear_LS(Mat mat_P_l, Mat mat_P_r, Mat warped_back_l, Mat warped_back_r)
{
    Mat A(4,3,CV_64FC1), b(4,1,CV_64FC1), X(3,1,CV_64FC1), X_homogeneous(4,1,CV_64FC1), W(1,1,CV_64FC1);
    W.at<double>(0,0) = 1.0;
    A.at<double>(0,0) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,0) - mat_P_l.at<double>(0,0);
    A.at<double>(0,1) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,1) - mat_P_l.at<double>(0,1);
    A.at<double>(0,2) = (warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,2) - mat_P_l.at<double>(0,2);
    A.at<double>(1,0) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,0) - mat_P_l.at<double>(1,0);
    A.at<double>(1,1) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,1) - mat_P_l.at<double>(1,1);
    A.at<double>(1,2) = (warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,2) - mat_P_l.at<double>(1,2);
    A.at<double>(2,0) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,0) - mat_P_r.at<double>(0,0);
    A.at<double>(2,1) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,1) - mat_P_r.at<double>(0,1);
    A.at<double>(2,2) = (warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,2) - mat_P_r.at<double>(0,2);
    A.at<double>(3,0) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,0) - mat_P_r.at<double>(1,0);
    A.at<double>(3,1) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,1) - mat_P_r.at<double>(1,1);
    A.at<double>(3,2) = (warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,2) - mat_P_r.at<double>(1,2);
    b.at<double>(0,0) = -((warped_back_l.at<double>(0,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,3) - mat_P_l.at<double>(0,3));
    b.at<double>(1,0) = -((warped_back_l.at<double>(1,0)/warped_back_l.at<double>(2,0))*mat_P_l.at<double>(2,3) - mat_P_l.at<double>(1,3));
    b.at<double>(2,0) = -((warped_back_r.at<double>(0,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,3) - mat_P_r.at<double>(0,3));
    b.at<double>(3,0) = -((warped_back_r.at<double>(1,0)/warped_back_r.at<double>(2,0))*mat_P_r.at<double>(2,3) - mat_P_r.at<double>(1,3));
    solve(A,b,X,DECOMP_SVD);
    vconcat(X,W,X_homogeneous);
    return X_homogeneous;
}

输入参数是两个3 × 4摄像机投影矩阵和对应的左/右像素对(x,y,w)。

j8yoct9x

j8yoct9x5#

除了吉内斯·伊达尔戈的评论外,
如果你做了立体校准,并且可以从那里精确地估计出基本矩阵,它是基于棋盘格计算出来的。
使用correctMatches函数细化检测到的关键点

std::vector<cv::Point2f> pt_set1_pt_c, pt_set2_pt_c;
cv::correctMatches(F,pt_set1_pt,pt_set2_pt,pt_set1_pt_c,pt_set2_pt_c)

相关问题