如何正确使用cv::triangulatePoints()
How to correctly use cv::triangulatePoints()
我试图用OpenCV对一些点进行三角测量,我发现了这个cv::triangulatePoints()
函数。问题是几乎没有关于它的文档或示例。
我对此有些怀疑。
-
使用什么方法?我做了一些关于三角测量的研究,有几种方法(线性,线性LS,特征,迭代LS,迭代特征,…),但我找不到OpenCV中使用的是哪一种。
-
我应该如何使用它?作为输入,它似乎需要一个投影矩阵和3xN齐次2D点。我将它们定义为
std::vector<cv::Point3d> pnts
,但作为输出,它需要4xN数组,显然我不能创建std::vector<cv::Point4d>
,因为它不存在,所以我应该如何定义输出向量?
对于第二个问题,我尝试了:cv::Mat pnts3D(4, N, CV_64F);
和cv::Mat pnts3d;
,但似乎都不起作用(它抛出一个异常)。
1。- 使用的方法是最小二乘。还有比这个更复杂的算法。尽管如此,它仍然是最常见的一种,因为其他方法在某些情况下可能会失败(例如,当点在平面上或无穷远处时,其他一些方法会失败)。
方法可以在Richard Hartley和Andrew Zisserman的Multiple View Geometry in Computer Vision (p312)
中找到2。——使用:
cv::Mat pnts3D(1, N, CV_64FC4);
cv::Mat cam0pnts(1, N, CV_64FC2);
cv::Mat cam1pnts(1, N, CV_64FC2);
用图像中的点填充2通道点矩阵
cam0
和cam1
是Mat3x4
相机矩阵(内部参数和外部参数)。你可以通过乘以A*RT
来构造它们,其中A
是固有参数矩阵,RT
是旋转平移3x4姿态矩阵。
cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);
注: pnts3D
需要是4通道1xN cv::Mat
定义时,如果不是抛出异常,但结果是一个cv::Mat(4, N, cv_64FC1)
矩阵。真的很混乱,但这是我没有得到异常的唯一方法。
UPDATE:从3.0或更早的版本开始,这不再是真的,pnts3D
也可以是Mat(4, N, CV_64FC1)
类型,或者可以完全为空(像往常一样,它是在函数内部创建的)。
对@Ander Biguri的回答的一个小补充。您应该在非undistort
ed图像上获得图像点,并在cam0pnts
和cam1pnts
上调用undistortPoints()
,因为cv::triangulatePoints
期望在标准化坐标(独立于相机)中的2D点,cam0
和cam1
应该仅为[R|t^ t]矩阵,您不需要将其与 a 相乘。
感谢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::Point4f,所以pnts3D必须是cv::Mat…
我尝试cv::triangulatePoints,但不知何故它计算垃圾。我被迫手动执行线性三角测量方法,该方法为三角测量的3D点返回4x1矩阵:
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;
}
输入参数为两个3x4相机投影矩阵和对应的左/右像素对(x,y,w)。
除了对ginsamas Hidalgo的评论,
如果你做了一个立体校准,可以从那里准确地估计基本矩阵,这是基于棋盘格计算的。
使用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)
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 概念中的cv限定符需要表达式参数列表
- 将CHW格式的浮点向量转换为cv::Mat
- 错误的cv::face FacemarkLBF实例化
- 如何检查给定的参数是否为 cv::noArray()?
- 开放 CV 中的动态内存分配,用于视频处理
- 如何在 opencv 中使用 cv::VideoCapture::waitAny()
- 错误:未定义对cv::cudacodec::createVideoReader的引用
- OpenCV 3.4.1 error readNetFromTensorflow 无法在 cv::d nn::ReadProtoFromBinaryFile 中打开 .pb
- C++:从GPU内存(cudaMemcpy2D)获取BGR图像(cv::Mat)
- 选择基于另一个垫子的非零像素的cv::Mat的一部分?
- 将 cv::mat 转换为 QImage
- Inference pytorch C++ with alexnet and cv::imread image
- OpenCV 3.4.3 中对 'cv::String::d eallocate()' 错误的未定义引用
- cv::Normalise() 中的 L2_NORM 和 NORM_MINMAX 实现有什么区别?
- 将 cv::Mat 转换为 std::vector 的通用函数
- OpenCV undefined reference to 'cv::imread(cv::String const&, int)'
- 在 QML VideoOutput 中将 cv::mat 显示为 QVideoFrame
- OpenCV:使用 cv::triangulatepoints() 的立体摄像机跟踪问题
- 如何正确使用cv::triangulatePoints()