2015-12-16 22 views
8

Ho recentemente iniziato a lavorare con OpenCV 3.0 e il mio obiettivo è quello di acquisire una coppia di immagini stereo da una serie di telecamere stereo, creare una mappa di disparità corretta, convertire la mappa di disparità in una nuvola di punti 3D e infine mostrare la nuvola di punti risultante in un visualizzatore di nuvole di punti utilizzando PCL.Come generare una rappresentazione di nuvole di punti valida di una coppia di immagini stereo usando OpenCV 3.0 StereoSGBM e PCL

Ho già effettuato la calibrazione della fotocamera e l'RMS calibrazione risultante è 0,4

È possibile trovare i miei coppie di immagini (immagine a sinistra) 1 e (immagine a destra) 2 nel link qui sotto. Sto usando StereoSGBM per creare un'immagine di disparità. Sto anche usando le barre delle tracce per regolare i parametri della funzione StereoSGBM al fine di ottenere immagini con una migliore disparità. Purtroppo non posso pubblicare la mia immagine di disparità da quando sono nuovo in StackOverflow e non ho abbastanza reputazione per pubblicare più di due link di immagini!

Dopo aver ottenuto l'immagine di disparità ("disp" nel codice di seguito), utilizzo la funzione reprojectImageTo3D() per convertire le informazioni di immagine di disparità in coordinate XYZ 3D e quindi converto i risultati in un array di "pcl: : PointXYZRGB "punta in modo che possano essere visualizzati in un visualizzatore di nuvole di punti PCL. Dopo aver eseguito la conversione richiesta, quello che ottengo come nuvola di punti è una stupida nuvola di punti a forma di piramide che non ha alcun senso. Ho già letto e provato tutti i metodi suggeriti nei seguenti link:

1- http: //blog.martinperis.com/2012/01/3d-reconstruction-with-opencv-and-point.html

2- http: //stackoverflow.com/questions/13463476/opencv-stereorectifyuncalibrated-to-3d-point-cloud

3- http: //stackoverflow.com/questions/22418846/reprojectimageto3d-in- opencv

e non hanno funzionato !!!

Qui di seguito ho fornito la porzione di conversione del mio codice, che sarebbe molto apprezzato se mi si potrebbe dire che cosa mi manca:

pcl::PointCloud<pcl::PointXYZRGB>::Ptr pointcloud(new pcl::PointCloud<pcl::PointXYZRGB>()); 
    Mat xyz; 
    reprojectImageTo3D(disp, xyz, Q, false, CV_32F); 
    pointcloud->width = static_cast<uint32_t>(disp.cols); 
    pointcloud->height = static_cast<uint32_t>(disp.rows); 
    pointcloud->is_dense = false; 
    pcl::PointXYZRGB point; 
    for (int i = 0; i < disp.rows; ++i) 
     { 
      uchar* rgb_ptr = Frame_RGBRight.ptr<uchar>(i); 
      uchar* disp_ptr = disp.ptr<uchar>(i); 
      double* xyz_ptr = xyz.ptr<double>(i); 

      for (int j = 0; j < disp.cols; ++j) 
      { 
       uchar d = disp_ptr[j]; 
       if (d == 0) continue; 
       Point3f p = xyz.at<Point3f>(i, j); 

       point.z = p.z; // I have also tried p.z/16 
       point.x = p.x; 
       point.y = p.y; 

       point.b = rgb_ptr[3 * j]; 
       point.g = rgb_ptr[3 * j + 1]; 
       point.r = rgb_ptr[3 * j + 2]; 
       pointcloud->points.push_back(point); 
      } 
     } 
    viewer.showCloud(pointcloud); 
+0

Si prega di controllare le immagini che avete fornito, sembrano uguali – alexisrozhkov

+0

Siamo spiacenti, il mio male. Ho caricato i frame giusti! –

risposta

11

Dopo aver fatto qualche lavoro e qualche ricerca ho trovato la mia risposta e io sono condividerlo qui in modo che altri lettori possano usarlo.

Niente di sbagliato nell'algoritmo di conversione dall'immagine di disparità in 3D XYZ (e infine in una nuvola di punti). Il problema era la distanza degli oggetti (che stavo facendo delle foto) alle telecamere e la quantità di informazioni che erano disponibili per gli algoritmi StereoBM o StereoSGBM per rilevare le somiglianze tra le due immagini (coppia di immagini). Per ottenere una nuvola di punti 3D corretta è necessario avere una buona immagine di disparità e per avere una buona immagine di disparità (supponendo di aver eseguito una buona calibrazione) assicurarsi di quanto segue:

1- Ci dovrebbe essere abbastanza caratteristiche comuni rilevabili e distinguibili disponibili tra i due frame (frame destro e sinistro). La ragione è che gli algoritmi StereoBM o StereoSGBM cercano caratteristiche comuni tra i due frame e possono facilmente essere ingannati da cose simili nei due frame che potrebbero non necessariamente appartenere agli stessi oggetti. Personalmente ritengo che questi due algoritmi di corrispondenza abbiano molto margine di miglioramento. Quindi fai attenzione a quello che stai guardando con le tue fotocamere.

2- Gli oggetti di interesse (quelli a cui si desidera avere il proprio modello di nuvola di punti 3D) devono trovarsi a una certa distanza dalle telecamere. Più grande è la linea di base (la linea di base è la distanza tra le due telecamere), più i tuoi oggetti di interesse (target) possono essere più lontani.

Un'immagine di disparità rumorosa e distorta non genera mai una buona nuvola di punti 3D. Una cosa che puoi fare per migliorare le tue immagini di disparità è usare le barre di tracciamento nelle tue applicazioni in modo da poter regolare i parametri StereoSBM o StereoSGBM fino a quando puoi vedere buoni risultati (immagine di disparità chiara e uniforme). Il codice qui sotto è un esempio piccolo e semplice su come generare trackbar (l'ho scritto il più semplice possibile). Utilizzare come richiesto:

int PreFilterType = 0, PreFilterCap = 0, MinDisparity = 0, UniqnessRatio = 0, TextureThreshold = 0, 
    SpeckleRange = 0, SADWindowSize = 5, SpackleWindowSize = 0, numDisparities = 0, numDisparities2 = 0, PreFilterSize = 5; 


      Ptr<StereoBM> sbm = StereoBM::create(numDisparities, SADWindowSize); 

while(1) 
{ 
      sbm->setPreFilterType(PreFilterType); 
      sbm->setPreFilterSize(PreFilterSize); 
      sbm->setPreFilterCap(PreFilterCap + 1); 
      sbm->setMinDisparity(MinDisparity-100); 
      sbm->setTextureThreshold(TextureThreshold*0.0001); 
      sbm->setSpeckleRange(SpeckleRange); 
      sbm->setSpeckleWindowSize(SpackleWindowSize); 
      sbm->setUniquenessRatio(0.01*UniqnessRatio); 
      sbm->setSmallerBlockSize(15); 
      sbm->setDisp12MaxDiff(32); 

      namedWindow("Track Bar Window", CV_WINDOW_NORMAL); 
      cvCreateTrackbar("Number of Disparities", "Track Bar Window", &PreFilterType, 1, 0); 
      cvCreateTrackbar("Pre Filter Size", "Track Bar Window", &PreFilterSize, 100); 
      cvCreateTrackbar("Pre Filter Cap", "Track Bar Window", &PreFilterCap, 61); 
      cvCreateTrackbar("Minimum Disparity", "Track Bar Window", &MinDisparity, 200); 
      cvCreateTrackbar("Uniqueness Ratio", "Track Bar Window", &UniqnessRatio, 2500); 
      cvCreateTrackbar("Texture Threshold", "Track Bar Window", &TextureThreshold, 10000); 
      cvCreateTrackbar("Speckle Range", "Track Bar Window", &SpeckleRange, 500); 
      cvCreateTrackbar("Block Size", "Track Bar Window", &SADWindowSize, 100); 
      cvCreateTrackbar("Speckle Window Size", "Track Bar Window", &SpackleWindowSize, 200); 
      cvCreateTrackbar("Number of Disparity", "Track Bar Window", &numDisparities, 500); 

      if (PreFilterSize % 2 == 0) 
      { 
       PreFilterSize = PreFilterSize + 1; 
      } 


      if (PreFilterSize2 < 5) 
      { 
       PreFilterSize = 5; 
      } 

      if (SADWindowSize % 2 == 0) 
      { 
       SADWindowSize = SADWindowSize + 1; 
      } 

      if (SADWindowSize < 5) 
      { 
       SADWindowSize = 5; 
      } 


      if (numDisparities % 16 != 0) 
      { 
       numDisparities = numDisparities + (16 - numDisparities % 16); 
      } 
     } 
} 

Se non si ottengono risultati corretti e l'immagine di disparità liscia, non rimarrete delusi. Prova a utilizzare le immagini campione OpenCV (quella con una lampada da tavolo arancione al suo interno) con il tuo algoritmo per assicurarti di avere la linea di condotta corretta e quindi provare a scattare foto da distanze diverse e giocare con i parametri StereoBM/StereoSGBM fino a ottenere qualcosa utile. Ho usato il mio viso per questo scopo e dato che avevo una linea di base molto piccola, mi sono avvicinato molto alle mie macchine fotografiche (qui c'è un link alla mia immagine 3D di nuvole di punti in faccia, e ciao, non ti azzardare a ridere !!!) 1. Ero molto felice di vedermi in forma di nuvola di punti 3D dopo una settimana di difficoltà. Non sono mai stato così felice di vedermi prima !!! ;)