2015-11-16 1 views
1

Je souhaite extraire une carte de profondeur à partir d'une image calibrée et d'un maillage triangulaire en utilisant OpenCV appelé depuis Matlab 2014b (en utilisant les liaisons OpenCV). Je suis un utilisateur régulier de Matlab mais je suis nouveau à OpenCV. Je les entrées suivantes:Carte de profondeur à partir d'une image calibrée et d'un maillage triangulaire utilisant OpenCV et Matlab

im - une image non déformée RVB de la scène

ou - vecteur de position caméra

R - matrice de rotation caméra décrivant pose

points - NX3 liste de sommets de maille triangulaire représentant la scène

faces - liste de face de maillage triangulaire MX3

EFL - image effective f longueur ocale en pixels

J'ai écrit un moteur de lancer de rayons Matlab natif pour extraire une carte de profondeur à partir de ces entrées, mais cela est assez lent et souffre d'erreurs de reprojection élevées (je veux comparer les résultats des fonctions OpenCV à mes propres établir si ces erreurs se rapportent à ma mise en œuvre ou juste à une erreur d'étalonnage de la caméra).

Comment une carte de profondeur peut-elle être obtenue à partir de ces entrées en utilisant OpenCV appelé par Matlab?

Toute aide serait grandement appréciée

Merci

Thomas

Répondre

1

stratégie proposée

Vous pouvez projeter les sommets de votre maillage en coordonnées de pixels 2D (en utilisant votre modèle d'appareil photo calibré). Ensuite, pour chaque face, vous pouvez trouver tous les centres de pixels (points de réseau) contenus dans le triangle 2D formé par ses sommets projetés. Vous devrez peut-être garder la trace du triangle le plus proche en cas de chevauchement. Vous savez maintenant quel visage correspond à chaque pixel. Cela devrait être très rapide à moins que votre maillage soit beaucoup plus haute résolution que votre image.

Vous pouvez alors trouver le rayon 3D correspondant à chaque pixel en utilisant le modèle de caméra, et croiser le rayon avec la face connue pour ce pixel pour calculer la profondeur (cela sonne comme si vous aviez déjà fait cette partie). Cela ne devrait pas prendre trop de temps non plus, maintenant que vous connaissez l'avion.

Plus d'informations sur la projection de la caméra

OpenCV a a good resource sur l'utilisation du modèle d'appareil photo (ci-dessous). Fondamentalement, vous pouvez projeter le point 3D M' en coordonnées pixel m'; C'est ainsi que vous projetez vos sommets aux positions de pixels. Aller dans l'autre sens, l'échelle est irrécupérable - vous obtenez le rayon M'/s plutôt que le point M'. La profondeur que vous recherchez est s, qui est la coordonnée Z du point 3D dans le cadre de la caméra. Si votre maillage est dans un cadre centré sur la caméra (X droite, Y vers le bas, Z vers l'extérieur), R = Identity et t = 0. Si ce n'est pas le cas, [R|t] le transforme en.

Compact

L'expansion chaque facteur nous permet de voir la composition des matrices.

Expanded

Le code ci-dessous que vous suggérez utilise la fonction projectPoints de OpenCV, qui met en oeuvre l'équation ci-dessus plus une calibration de distorsion (voir référence principale de OpenCV). Vous devez remplir les matrices et les multiplier. Un autre exemple pour projectPoints est disponible on GitHub, et je crois que ce même exemple est discuté dans this SO question.

code proposé par asker

Apparemment, le code suivant fait le travail. Je besoin de temps pour choix à travers elle, étant donné que mon C++ connaissance est pratiquement nul (je réalise qu'il est commenté BTW):

 //CString str; 
     //cv::Mat CamMatrix(3, 3, CV_64F); 
     //cv::Mat distCoeffs(5, 1, CV_64F); 
     //m_CamCalib.GetOpenCVInfo(&CamMatrix, &distCoeffs); 
     //vector<Point3d> GCP_Points; 
     //vector<Point2d> Image_Points; 
     //cv::Mat RVecs(3, 3, CV_64F); // rotation matrix 
     //cv::Mat TranRVecs(3, 3, CV_64F); // rotation matrix 
     //cv::Mat TVecs(3, 1, CV_64F); // translation vector 
     //RVecs.at<double>(0, 0) = m_CamPosMtrx.m_pMtrx[0]; 
     //RVecs.at<double>(1, 0) = m_CamPosMtrx.m_pMtrx[1]; 
     //RVecs.at<double>(2, 0) = m_CamPosMtrx.m_pMtrx[2]; 

     //RVecs.at<double>(0, 1) = m_CamPosMtrx.m_pMtrx[4]; 
     //RVecs.at<double>(1, 1) = m_CamPosMtrx.m_pMtrx[5]; 
     //RVecs.at<double>(2, 1) = m_CamPosMtrx.m_pMtrx[6]; 

     //RVecs.at<double>(0, 2) = m_CamPosMtrx.m_pMtrx[8]; 
     //RVecs.at<double>(1, 2) = m_CamPosMtrx.m_pMtrx[9]; 
     //RVecs.at<double>(2, 2) = m_CamPosMtrx.m_pMtrx[10]; 
     //transpose(RVecs, TranRVecs); 
     //TVecs.at<double>(0, 0) = 0; 
     //TVecs.at<double>(1, 0) = 0; 
     //TVecs.at<double>(2, 0) = 0; 
     //GCP_Points.push_back(Point3d((x - m_CamPosMtrx.m_pMtrx[12]), (y - m_CamPosMtrx.m_pMtrx[13]), (z - m_CamPosMtrx.m_pMtrx[14]))); 
     //Image_Points.push_back(Point2d(0, 0)); 
     //projectPoints(GCP_Points, TranRVecs, TVecs, CamMatrix, distCoeffs, Image_Points); 

/bool CCameraCalibration::GetOpenCVInfo(Mat * cameraMatrix, Mat * distCoeffs) 
//{ 
//   int i,j; 
//   Mat projMatrix; 
//   CMatrix4x4 m1; 
//   if(cameraMatrix->rows==0) cameraMatrix->create(3,3, CV_64F); 
//   if(distCoeffs->rows==0) distCoeffs->create(5, 1, CV_64F); 
//   for(i=0;i<3;i++) 
//   for(j=0;j<3;j++){ 
//     cameraMatrix->at<double>(i,j)=m_pCameraMatrix[i][j]; 
//   } 
//   for(i=0;i<5;i++) 
//     distCoeffs->at<double>(i,0)=m_pCoefficients[i]; 
//  return false; 
//} 
+0

J'aime votre approche. À l'heure actuelle, le code Matlab utilise la subdivision Octree pour partitionner le maillage (re-maillage du split split d'octree Le modèle TIN est le premier goulot d'étranglement: la fonction de recherche d'élément dans Matlab échoue très mal). Je localise ensuite l'intersection des rayons en utilisant l'algorithme de Smit, puis je recherche le contenu de chaque boîte et je résous les intersections de Ray-tri en utilisant l'algorithme de Moller et Trumbore. Bien que votre méthode semble meilleure, la vitesse n'est pas mon problème principal: je me bats avec la configuration du rayon-arbre car cela semble être d'où proviennent les erreurs de re-projection. Comment régler ceci en utilisant OpenCV? Merci. Thomas –

+0

Hmm, que se passe-t-il lorsqu'un visage traverse plusieurs subdivisions d'octree? L'ajoutez-vous à chaque feuille, juste une, ou divisez-vous le visage en plusieurs triangles pour chaque subdivision? Faire cette recherche en 3D ajoute définitivement de la complexité ici. Même si cela signifie commencer une nouvelle méthode, la recherche 2D peut être encore plus facile à travailler. – kmac

+0

À votre santé kmac. Le partitionnement spatial et la recherche par ray box sont assez standard dans la littérature de ray tracing (c'est-à-dire les arbres BSP). Comme je pense que vous l'avez repéré, un triangle partagé est dupliqué dans des cases espacées (cette recherche tue vraiment la vitesse de l'opération). J'ai acquis du code C++ d'un collègue censé effectuer la projection de pixels en utilisant OpenCV. En tant que Noob C++/OpenCV, je suis toujours en train de le choisir. Peut-être sera-t-il utile à quelqu'un d'autre ... Je l'afficherai ci-dessous: –