2015-12-16 52 views
8

最近OpenCV 3.0で作業を開始しましたが、目標はステレオカメラからステレオ画像のペアをキャプチャし、適切な視差マップを作成し、視差マップを3D点群に変換し、最後に得られた点群をPCLを用いて点群ビューアに表示する。OpenCV 3.0を使用してステレオ画像のペアの有効な点群を生成する方法StereoSGBMとPCL

私はすでに、カメラキャリブレーションし、得られた較正RMSあなたは以下のリンクで私の画像ペア(左画像)1と(右の画像)2を見つけることができます0.4

で行ってきました。私は視差画像を作成するためにStereoSGBMを使用しています。また、より良い視差画像を得るために、トラックバーを使用してStereoSGBM関数のパラメータを調整しています。残念ながら、私はStackOverflowを初めて使用しており、2つ以上の画像リンクを投稿するには十分な評判がないので、視差画像を投稿することはできません!

視差画像(以下のコードでは「disp」)を取得した後、視差画像情報をXYZ 3D座標に変換するためにreprojectImageTo3D()関数を使用し、結果を「pcl: :PointXYZRGB "はPCLポイントクラウドビューアに表示できるようにポイントします。必要な変換を実行した後、私がポイントクラウドとして得ることは、意味を持たない愚かなピラミッド形状のポイントクラウドです。私は既に以下のリンクで提案されているすべての方法を読み、試しました:

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

それ以外はうまくいきました!

私は私のコードの変換部を提供するの下には、私が行方不明です何を私に言うことができるならば、それは非常に高く評価されるだろう:私は私の答えを見つけたと私はいくつかの仕事といくつかの研究を行った後

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

あなたが提供した画像を確認してください、彼らは同じように見える – alexisrozhkov

+0

申し訳ありません、私の悪い。私は右のフレームをアップロードしました! –

答えて

11

を他の読者が使用できるようにここで共有します。

視差画像から3D XYZ(最終的にはポイントクラウド)への変換アルゴリズムに問題はありませんでした。問題は、カメラへの物体の距離と、2つの画像(画像ペア)間の類似性を検出するためのStereoBMまたはStereoSGBMアルゴリズムで利用可能な情報の量でした。適切な3D点群を得るためには、良好な視差画像が必要であり、良好な視差画像を得るためには、以下の点を確認してください。 2つのフレーム(右フレームと左フレーム)の間で利用可能な、検出可能で区別可能な共通の特徴。その理由は、StereoBMまたはStereoSGBMアルゴリズムが2つのフレーム間の共通の特徴を探し、2つのフレーム内の同じオブジェクトによって必ずしも同じオブジェクトに属していない可能性があるためです。個人的には、これら2つのマッチングアルゴリズムには改善の余地がたくさんあると思います。カメラであなたが見ているものに注意してください。

2対象物(あなたが3D点群モデルに興味があるもの)は、カメラから一定の距離内にある必要があります。ベースラインが大きいほど(ベースラインは2台のカメラ間の距離です)、関心のある対象(ターゲット)はさらに大きくなります。

ノイズの多い歪んだ視差画像は、優れた3D点群を生成しません。視差画像を改善するために行うことの1つは、アプリケーションでトラックバーを使用することです。その結果、良好な結果が得られるまでStereoSBMまたはStereoSGBMパラメータを調整できます(明瞭で滑らかな視差画像)。以下のコードは、トラックバーを生成する方法についての簡単で小さな例です(私はできるだけシンプルに書いています)。必要に応じて使用:

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

適切な結果と滑らかな視差画像が得られない場合は、失望しないでください。あなたのアルゴリズムでOpenCVサンプル画像(オレンジ色の机のランプが付いているもの)を使用して、正しいパイプラインがあることを確認してから、別の距離から写真を撮り、何かを得るまでStereoBM/StereoSGBMパラメータで試してみてください有用。私はこの目的のために自分の顔を使っていました。私はベースラインが非常に狭かったので、私は自分のカメラにとても近づきました(ここで私の3D顔のポイント - 雲の画像へのリンクですね、ちょっと、笑っていません! )1。私は、1週間の苦労の後、3Dポイントクラウドの形で自分自身を見て非常に満足していました。私は前に自分自身を見るのが幸せになったことはありません! ;)

関連する問題