簡體   English   中英

如何使用OpenCV 3.0 StereoSGBM和PCL生成一對立體圖像的有效點雲表示

[英]How to generate a valid point cloud representation of a pair of stereo images using OpenCV 3.0 StereoSGBM and PCL

我最近開始使用OpenCV 3.0,我的目標是從一組立體相機中捕獲一對立體圖像,創建一個合適的視差圖,將視差圖轉換為3D點雲,最后在一個點雲中顯示結果點雲。使用PCL的點雲查看器。

我已經進行了相機校准,結果校准RMS為0.4

您可以在下面的鏈接中找到我的圖像對(左圖) 1和(右圖) 2 我正在使用StereoSGBM來創建視差圖像。 我也使用軌跡條來調整StereoSGBM函數參數,以獲得更好的視差圖像。 不幸的是,我不能發布我的差異圖像,因為我是StackOverflow的新手並且沒有足夠的聲譽來發布兩個以上的圖像鏈接!

獲取視差圖像(下面的代碼中的“disp”)后,我使用reprojectImageTo3D()函數將視差圖像信息轉換為XYZ 3D坐標,然后將結果轉換為“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);

做了一些工作和一些研究后,我找到了答案,我在這里分享,以便其他讀者可以使用。

從視差圖像到3D XYZ(最終到點雲)的轉換算法沒有任何問題。 問題是物體(我正在拍攝照片)與攝像機之間的距離以及可用於StereoBM或StereoSGBM算法的信息量,以檢測兩個圖像(圖像對)之間的相似性。 為了獲得適當的3D點雲,需要具有良好的視差圖像,並且為了獲得良好的視差圖像(假設您已經執行了良好的校准),請確保以下內容:

1-兩個框架(右框架和左框架)之間應該有足夠的可檢測和可區分的共同特征。 原因在於StereoBM或StereoSGBM算法在兩個幀之間尋找共同特征,並且它們很容易被兩個幀中的類似事物欺騙,這兩個幀可能不一定屬於相同的對象。 我個人認為這兩種匹配算法有很大的改進空間。 所以要注意你用相機看的東西。

2-感興趣的對象(您有興趣擁有3D點雲模型的對象)應與攝像機保持一定距離。 基線越大(基線是兩個攝像機之間的距離),您感興趣的對象(目標)就越遠。

嘈雜和失真的視差圖像永遠不會產生良好的3D點雲。 您可以做的一件事就是在您的應用程序中使用跟蹤條,以便您可以調整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 。經過一周的掙扎,我很高興看到自己處於3D點雲狀態。 我以前見過自己從未如此幸福! ;)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM