我最近开始使用OpenCV 3.0,我的目标是从一组立体相机中捕获一对立体图像,创建一个合适的视差图,将视差图转换为3D点 Cloud ,最后在一个点 Cloud 中显示结果点 Cloud . 使用PCL的点 Cloud 查看器 .
我已经进行了相机校准,结果校准RMS为0.4
您可以在下面的链接中找到我的图像对(左图)1和(右图)2 . 我正在使用StereoSGBM来创建视差图像 . 我也使用轨迹条来调整StereoSGBM函数参数,以获得更好的视差图像 . 不幸的是,我可以't post my disparity image since I am new to StackOverflow and don'有足够的声誉发布两个以上的图像链接!
获取视差图像(下面的代码中的“disp”)后,我使用reprojectImageTo3D()函数将视差图像信息转换为XYZ 3D坐标,然后将结果转换为“pcl :: PointXYZRGB”点的数组这样它们就可以在PCL点 Cloud 查看器中显示出来 . 在执行所需的转换后,我得到的点 Cloud 是一个愚蠢的金字塔形状的点 Cloud ,没有任何意义 . 我已阅读并尝试了以下链接中的所有建议方法:
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);
1 回答
做了一些工作和一些研究后,我找到了答案,我在这里分享,以便其他读者可以使用 .
从视差图像到3D XYZ(最终到点 Cloud )的转换算法没有任何问题 . 问题是物体(我正在拍摄照片)与摄像机之间的距离以及可用于StereoBM或StereoSGBM算法的信息量,以检测两个图像(图像对)之间的相似性 . 为了获得适当的3D点 Cloud ,需要具有良好的视差图像,并且为了获得良好的视差图像(假设您已经执行了良好的校准),请确保以下内容:
1-两个框架(右框架和左框架)之间应该有足够的可检测和可区分的共同特征 . 原因在于StereoBM或StereoSGBM算法在两个帧之间寻找共同特征,并且它们很容易被两个帧中的类似事物欺骗,这两个帧可能不一定属于相同的对象 . 我个人认为这两种匹配算法有很大的改进空间 . 所以要注意你用相机看的东西 .
2-感兴趣的对象(您有兴趣拥有3D点 Cloud 模型的对象)应与摄像机保持一定距离 . 基线越大(基线是两个摄像机之间的距离),您感兴趣的对象(目标)就越远 .
嘈杂和失真的视差图像永远不会产生良好的3D点 Cloud . 您可以做的一件事就是改善视差图像,在应用程序中使用跟踪条,这样您就可以调整StereoSBM或StereoSGBM参数,直到您看到良好的结果(清晰平滑的视差图像) . 下面的代码是关于如何生成跟踪条的一个简单的小例子(我写的尽可能简单) . 根据需要使用:
如果你没有得到正确的结果和平滑的视差图像,那么你就不敢笑!!!)1 . 经过一周的挣扎,我很高兴看到自己处于3D点 Cloud 状态 . 我以前见过自己从未如此幸福! ;)