Comment utiliser correctement cv:: triangulatePoints()

J'essaie de trianguler certains points avec OpenCV et j'ai trouvé cette fonction cv::triangulatePoints(). Le problème est qu'il n'y a presque pas de documentation ou des exemples.

J'ai quelques doutes à ce sujet.

  1. Quelle méthode faut-il utiliser? J'ai fait une petite recherche sur les triangulations et il existe plusieurs méthodes (linéaire, linéaire LS, propre, itérative LS, itérative propre,...) mais je ne trouve pas lequel utilise-t-il dans OpenCV.

  2. Comment devrait - - Je l'utiliser? Il semble qu'en tant qu'entrée, il a besoin d'une matrice de projection et 3XN homogène 2D points. Je les ai définis comme std::vector<cv::Point3d> pnts, mais en tant que sortie, il a besoin de tableaux 4xN et évidemment je ne peux pas créer un std::vector<cv::Point4d> parce qu'il n'existe pas, alors comment dois-je définir le vecteur de sortie?

Pour la deuxième question j'ai essayé: cv::Mat pnts3D(4,N,CV_64F); et cv::Mat pnts3d;, ni semble fonctionner (elle lève une exception).

25
demandé sur Null 2013-04-30 12:37:51

5 réponses

1.- La méthode utilisée est la méthode des moindres Carrés. Il existe des algorithmes plus complexes que celui-ci. Pourtant, c'est le plus commun, car les autres méthodes peuvent échouer dans certains cas (c'est-à-dire que d'autres échouent si les points sont sur le plan ou sur l'infini).

La méthode peut être trouvée dans Plusieurs Vue de la Géométrie de la Vision par Ordinateur par Richard Hartley et Andrew Zisserman (p312)

2.-L'utilisation de:

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

Remplir le 2 chanel point Matrices avec les points dans les images.

cam0 et cam1 sont des matrices de caméra Mat3x4 (paramètres intrinsèques et extrinsèques). Vous pouvez les construire en multipliant A * RT, où A est la matrice de paramètres intrinsèques et RT la matrice de pose de translation de rotation 3x4.

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

NOTE: pnts3D doit être un canal 4 1xN cv::Mat lorsqu'il est défini, lève l'exception si ce n'est pas le cas, mais le résultat est une matrice cv::Mat(4,N,cv_64FC1). Vraiment déroutant, mais c'est la seule façon dont je n'ai pas eu un exception.


UPDATE : à partir de la version 3.0 ou peut-être antérieure, ce n'est plus vrai, et pnts3D peut également être de type Mat(4,N,CV_64FC1) ou peut être laissé complètement vide (comme d'habitude, il est créé dans la fonction).

44
répondu Ander Biguri 2018-05-02 08:38:36

Un petit ajout à la réponse de @Ander Biguri. Vous devriez obtenir vos points d'image sur une image Non - undistorted, et invoquer undistortPoints() sur les cam0pnts et cam1pnts, Car cv::triangulatePoints attend les points 2D en coordonnées normalisées (indépendantes de la caméra) et cam0 et cam1 ne devraient être que [R|T^T] Vous n'avez pas besoin de le multiple avec a.

10
répondu Bálint Kriván 2015-04-23 10:05:03

Merci à Ander Biguri! Sa réponse m'a beaucoup aidé. Mais je préfère toujours l'alternative avec std::vector, j'ai édité solution:

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);

Donc, vous avez juste besoin de faire emplace_back dans les points. Principal avantage: vous n'avez pas besoin de connaître la taille N avant de commencer à les remplir. Malheureusement, il n'y a pas de cv:: Point4f, donc pnts3D doit être un cv:: Mat...

3
répondu Gines Hidalgo 2017-05-08 12:39:36

J'ai essayé cv:: triangulatePoints, mais d'une manière ou d'une autre il calcule les ordures. J'ai été obligé d'implémenter manuellement une méthode de triangulation linéaire, qui renvoie une matrice 4x1 pour le point 3D triangulé:

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;
}

Les paramètres d'entrée sont deux matrices de projection de caméra 3x4 et une paire de pixels gauche/droite correspondante (x, y, w).

2
répondu YuZ 2014-09-12 15:09:12

Vous pouvez également utiliser la méthode de Hartley & Zisserman implémentée ici: http://www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-from-harley-zisserman-w-code/

0
répondu Chris 2013-10-11 09:26:35