2015-12-16 9 views
8

Niedawno zacząłem pracować z OpenCV 3.0, a moim celem jest uchwycenie pary stereofonicznych obrazów z zestawu kamer stereoskopowych, stworzenie odpowiednią mapę różnic, przekonwertuj mapę różnicową na chmurę punktów 3D i na koniec pokaż wynikową chmurę punktów w przeglądarce chmur punktów za pomocą PCL.Jak wygenerować poprawną reprezentację chmur punktów w pary stereoskopowych obrazów przy użyciu OpenCV 3.0 StereoSGBM i PCL

już przeprowadzono kalibrację kamery i otrzymaną RMS kalibracji wynosi 0,4

można znaleźć moje par obrazków (lewy obraz) 1 i (prawy obraz) 2 w poniższe linki. Używam StereoSGBM w celu uzyskania obrazu różnicowego. Używam także drążków do regulacji parametrów funkcji StereoSGBM w celu uzyskania lepszego obrazu różnic. Niestety nie mogę opublikować mojego obrazu różnicowego, ponieważ jestem nowy w StackOverflow i nie mam wystarczającej reputacji, aby opublikować więcej niż dwa linki do obrazów!

Po uzyskaniu obrazu różnicowego ("disp" w poniższym kodzie), używam funkcji reprojectImageTo3D() do konwersji informacji o obrazie rozbieżności na współrzędną XYZ 3D, a następnie przekonwertuję wyniki na tablicę "pcl: : PointXYZRGB "wskazuje, że można je wyświetlić w przeglądarce chmur punktów PCL. Po wykonaniu wymaganej konwersji, co dostaję jako chmurę punktów, jest głupia piramida, która nie ma żadnego sensu. Przeczytałem i wypróbowałem wszystkie sugerowane metody w następujących linkach:

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

i żaden z nich nie działał !!!

Poniżej umieszczono część konwersji mojego kodu, byłoby bardzo mile widziane, jeśli możesz mi powiedzieć, co mi brakuje:

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

proszę sprawdzić zdjęcia, które podałeś, wyglądają tak samo – alexisrozhkov

+0

Niestety, mój zły. Przesłałem odpowiednie ramki! –

Odpowiedz

11

Po jakiejś pracy i rozeznanie znalazłem moją odpowiedź i jestem udostępnianie go tutaj, aby inni czytelnicy mogli z niego korzystać.

Nic nie było nie tak z algorytmem konwersji z obrazu różnicowego do 3D XYZ (i ostatecznie do chmury punktów). Problem polegał na odległości obiektów (które robiłem zdjęcia) od kamer i ilości informacji dostępnych dla algorytmów StereoBM lub StereoSGBM w celu wykrycia podobieństw między dwoma obrazami (parą obrazów). Aby uzyskać odpowiednią chmurę punktów 3D, wymagany jest dobry obraz różnicy i aby uzyskać dobry obraz różnicy (zakładając, że wykonano dobrą kalibrację), upewnij się, że:

1- Powinno wystarczyć wykrywalne i możliwe do odróżnienia wspólne funkcje dostępne między dwiema ramkami (prawa i lewa ramka). Powodem jest to, że algorytmy StereoBM lub StereoSGBM szukają wspólnych cech pomiędzy dwiema ramkami i mogą być łatwo oszukane przez podobne rzeczy w dwóch ramkach, które niekoniecznie muszą należeć do tych samych obiektów. Osobiście uważam, że te dwa pasujące algorytmy mają dużo miejsca na ulepszenia. Uważaj więc na to, co oglądasz za pomocą swoich aparatów.

2- Obiekty zainteresowania (te, które są zainteresowane posiadaniem ich modelu chmury punktów 3D) powinny znajdować się w pewnej odległości od kamer. Im większa jest linia podstawowa (linia podstawowa to odległość między dwiema kamerami), tym dalej mogą znajdować się obiekty zainteresowania (cele).

Hałaśliwy i zniekształcony obraz różnic nigdy nie generuje dobrej chmury punktów 3D. Jedną rzeczą, którą możesz zrobić, aby poprawić swoje obrazy różnic, jest użycie pasków narzędzi w swoich aplikacjach, aby móc dopasować parametry StereoSBM lub StereoSGBM, dopóki nie zobaczysz dobrych wyników (wyraźny i płynny obraz różnicy). Poniższy kod jest małym i prostym przykładem generowania ścieżek (napisałem to tak prosto, jak to tylko możliwe). Zastosuj zgodnie z wymaganiami:

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

Jeśli nie uzyskasz właściwych wyników i płynnego obrazu różnicowego, nie rozczaruj się. Spróbuj użyć przykładowych obrazów OpenCV (tego z pomarańczową lampą biurkową) za pomocą swojego algorytmu, aby upewnić się, że masz prawidłową linię, a następnie spróbuj robić zdjęcia z różnych odległości i baw się przy pomocy parametrów StereoBM/StereoSGBM, aż uzyskasz coś przydatny. Użyłem w tym celu własnej twarzy, a ponieważ miałem bardzo małą linię bazową, zbliżyłem się bardzo do moich aparatów fotograficznych (tutaj jest link do mojego trójwymiarowego obłoku punktu widzenia, i hej, nie waż się śmiać !!!) 1. Byłem bardzo szczęśliwy widząc siebie w formie chmury punktów 3D po tygodniu zmagań. Nigdy nie byłem tak szczęśliwy, widząc siebie przedtem !!! ;)

Powiązane problemy