当前位置:  开发笔记 > 编程语言 > 正文

如何使用OpenCV 3.0 StereoSGBM和PCL生成一对立体图像的有效点云表示

如何解决《如何使用OpenCV3.0StereoSGBM和PCL生成一对立体图像的有效点云表示》经验,为你挑选了1个好方法。

我最近开始使用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::Ptr pointcloud(new   pcl::PointCloud());
    Mat xyz;
    reprojectImageTo3D(disp, xyz, Q, false, CV_32F);
    pointcloud->width = static_cast(disp.cols);
    pointcloud->height = static_cast(disp.rows);
    pointcloud->is_dense = false;
    pcl::PointXYZRGB point;
    for (int i = 0; i < disp.rows; ++i)
        {
            uchar* rgb_ptr = Frame_RGBRight.ptr(i);
            uchar* disp_ptr = disp.ptr(i);
            double* xyz_ptr = xyz.ptr(i);

            for (int j = 0; j < disp.cols; ++j)
            {
                uchar d = disp_ptr[j];
                if (d == 0) continue;
                Point3f p = xyz.at(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);

Ehsan Masnav.. 14

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

从视差图像到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 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点云状态.我以前见过自己从未如此幸福!;)



1> Ehsan Masnav..:

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

从视差图像到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 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点云状态.我以前见过自己从未如此幸福!;)

推荐阅读
echo7111436
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有