我试图用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;
,似乎都没有效果(它会引发异常)。
答案 0 :(得分:46)
1.- 使用的方法是最小二乘法。有比这更复杂的算法。它仍然是最常见的一种,因为在某些情况下其他方法可能会失败(即,如果点在平面上或在无限远处,则其他方法会失败)。
该方法可在 Richard Hartley和Andrew Zisserman
2 .- 用法:cv::Mat pnts3D(1,N,CV_64FC4);
cv::Mat cam0pnts(1,N,CV_64FC2);
cv::Mat cam1pnts(1,N,CV_64FC2);
用图像中的点填充2个chanel点矩阵。
cam0
和cam1
是Mat3x4
个相机矩阵(内在和外在参数)。您可以通过乘以A * RT来构造它们,其中A是内在参数矩阵,RT是旋转平移3x4姿势矩阵。
cv::triangulatePoints(cam0,cam1,cam0pnts,cam1pnts,pnts3D);
注意:pnts3D
定义时需要4通道 1xN cv::Mat
,否则抛出异常,但结果为{ {1}}矩阵。真的很混乱,但这是我没有例外的唯一方法。
更新:从版本3.0或更早版本开始,这不再是真的,cv::Mat(4,N,cv_64FC1)
也可以是pnts3D
类型,也可以保持完全为空(如通常,它是在函数内创建的。
答案 1 :(得分:10)
@Ander Biguri的一个小补充回答。您应该在非undistort
的图像上获取图像点,并在undistortPoints()
和cam0pnts
上调用cam1pnts
,因为cv::triangulatePoints
需要2D点数标准化坐标(独立于相机)和cam0
和cam1
应仅 [R | t ^ T] matricies,您不需要使用 A将其复数强>
答案 2 :(得分:3)
感谢Ander Biguri!他的回答对我很有帮助。但我总是喜欢使用std :: vector的替代方案,我编写了他的解决方案:
sudo rm -Rf $GOPATH/src/github.com/hyperledger
mkdir -pv $GOPATH/src/github.com/hyperledger
cd $GOPATH/src/github.com/hyperledger
git clone http://gerrit.hyperledger.org/r/fabric
git clone https://github.com/hyperledger/fabric-ca
cd $GOPATH/src/github.com/hyperledger/fabric
git branch --all
git fetch
make clean
make dist-clean
make configtxgen
make docker
make peer-docker
make orderer-docker
make couchdb
cd $GOPATH/src/github.com/hyperledger/fabric-ca
git branch --all
git fetch
make clean
make dist-clean
make docker
所以你只需要在点上做emplace_back。主要优点:在开始填充之前,您不需要知道大小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);
。不幸的是,没有cv :: Point4f,所以pnts3D必须是cv :: Mat ......
答案 3 :(得分:2)
我尝试了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)。
答案 4 :(得分:0)
或者你可以使用Hartley&amp; amp; Zisserman在这里实施:http://www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-from-harley-zisserman-w-code/