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.
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.
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 unstd::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).
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).
Un petit ajout à la réponse de @Ander Biguri. Vous devriez obtenir vos points d'image sur une image Non - undistort
ed, 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.
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...
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).
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/