web-dev-qa-db-fra.com

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 d'exemples.

J'ai des doutes à ce sujet. 

  1. Quelle méthode utilise-t-il? J'ai fait une petite recherche sur les triangulations et il existe plusieurs méthodes (Linéaire, Linéaire LS, eigen, LS itératif, Eigen itératif, ...) mais je ne trouve pas laquelle est utilisée dans OpenCV . 

  2. Comment devrais-je l'utiliser? Il semble qu’en entrée, il faut une matrice de projection et 3xN homogène 2D points. Je les ai définis en tant que std::vector<cv::Point3d> pnts, mais en sortie, il a besoin de 4xN arrays et, bien entendu, je ne peux pas créer de std::vector<cv::Point4d> car il n’existe pas. Comment définir le vecteur de sortie?

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

27
Ander Biguri

1.- La méthode utilisée est la méthode des moindres carrés. Il existe des algorithmes plus complexes que celui-ci. Néanmoins, c’est la plus courante, 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 Géométrie à vues multiples en vision par ordinateurpar Richard Hartley et Andrew Zisserman (p312)

2.-L'utilisation:

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

Remplissez les matrices à 2 points de chanel avec les points des 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 des paramètres intrinsèques et RT la matrice de pose en translation avec rotation 3x4.

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

NOTE: pnts3D BESOIN d'être un 4 canaux 1xNcv::Mat lorsqu'il est défini, lève une exception sinon, mais le résultat est une matrice cv::Mat(4,N,cv_64FC1). Vraiment déroutant, mais c'est la seule façon pour laquelle je n'ai pas eu d'exception.


UPDATE: A partir de la version 3.0 ou antérieure, ce n'est plus le cas, 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).

45
Ander Biguri

Un petit ajout à la réponse de @Ander Biguri. Vous devriez obtenir vos points d'image sur une image non-undistorted et appeler undistortPoints() sur les cam0pnts et cam1pnts, car cv::triangulatePoints s'attend à ce que les points 2D soient en coordonnées normalisées (indépendantes de la caméra) et que cam0 et cam1 soient uniquement/ [R | t ^ T] matricies vous n'avez pas besoin de le multiplier avecA.

10
Bálint Kriván

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

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

Il suffit donc 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
Gines Hidalgo

J'ai essayé cv :: triangulatePoints, mais d'une manière ou d'une autre, il calcule les déchets. J'ai été contraint 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
YuZ

Sinon, vous pouvez utiliser la méthode de Hartley & Zisserman mise en œuvre ici: http://www.morethantechnical.com/2012/01/04/simple-triangulation-with-opencv-from-harley-zisserman-w-code/

0
Chris