簡體   English   中英

如何正確使用 cv::triangulatePoints()

[英]How to correctly use cv::triangulatePoints()

我試圖用 OpenCV 對一些點進行三角剖分,我發現了這個cv::triangulatePoints() function。問題是幾乎沒有文檔或示例。

我對此有些懷疑。

  1. 它使用什么方法? 我對三角剖分進行了一項小型研究,有幾種方法(線性、線性 LS、本征、迭代 LS、迭代本征等),但我找不到它在 OpenCV 中使用的是哪一種。

  2. 我應該如何使用它? 似乎作為輸入,它需要一個投影矩陣和3xN 個均勻的2D點。 我將它們定義為std::vector<cv::Point3d> pnts ,但作為 output 它需要4xN arrays 顯然我無法創建std::vector<cv::Point4d>因為它不存在,那么我應該如何定義 output 向量呢?

對於我嘗試的第二個問題: cv::Mat pnts3D(4,N,CV_64F); cv::Mat pnts3d; ,似乎都不起作用(它拋出異常)。

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是旋轉平移3x4姿勢矩陣。

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

注意pnts3D需要在定義時為4通道1xN cv::Mat ,否則將引發異常,但結果是cv::Mat(4,N,cv_64FC1)矩陣。 確實令人困惑,但這是我沒有例外的唯一方法。


更新 :從3.0版或更早版本開始,這不再是正確的, pnts3D也可以是Mat(4,N,CV_64FC1)類型Mat(4,N,CV_64FC1)或者可以完全留空(通常,它是在函數內部創建的)。

@Ander Biguri的答案的一小部分內容。 您應該在未undistort圖像上獲取圖像點,並在cam0pntscam1pnts上調用undistortPoints() ,因為cv::triangulatePoints期望歸一化坐標系中的2D點(獨立於相機),而cam0cam1應該僅[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)。

另外,您也可以使用Hartley&Zisserman的方法,在此實現: http : //www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-from-harley-zisserman-w-code/

除了 Ginés Hidalgo 的評論,

如果您進行了立體校准並且可以從那里准確估計基本矩陣,該矩陣是基於棋盤格計算的。

使用正確匹配函數細化檢測到的關鍵點

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM