【精选】立体匹配视差图生成的PCL点云分层、放射状等杂乱效果的解决方法 您所在的位置:网站首页 opencv点云三维重建 【精选】立体匹配视差图生成的PCL点云分层、放射状等杂乱效果的解决方法

【精选】立体匹配视差图生成的PCL点云分层、放射状等杂乱效果的解决方法

2023-11-20 09:17| 来源: 网络整理| 查看: 265

背景

    博主最近在学习三维重建中的立体匹配,在OpenCV中使用sgbm和bm算法时,碰到了一个棘手的问题,PCL点云出现分层的效果,让我百思不得其解,csdn翻了好多页,也没比较明确的解答(可能我的问题比较笨吧…)。在我翻了不少博客、代码例程和向前辈请教之后,最后修改了一些细节,算是能显示出点云图。 在这里插入图片描述

    在搜索解决方法时,发现还有挺多人碰到过类似的问题,这种感受很难受,就像你检查了很多遍,感觉没什么问题 代码就该这样写,但效果就是出不来,搁置不前,原地打转。所以我觉得,我还是记录下解决这个问题的过程,给以后掉进坑里的老铁们有一个参考的方向(本菜鸡真的在这个问题上耽误了好多时间),不说废话了,进入正题——

问题1:点云分层、断层

在这里插入图片描述

    如果出现以上类似效果,PCL点云像是很多2d平面图像层叠出来的问题,首先给出结论:转换点云时使用的视差图格式不对。     以OpenCV-sgbm为例,先调sgbm中的参数、至视差图既平滑又少空洞。     在阅读网上许多代码后发现,用于计算距离的视差图(CV_32F)和用于肉眼看的视差图(CV_8U)使用的格式不同,并且用于计算的视差图无需进行裁剪和归一化,这些只是为了显示的可读性和美观。所以,在对sgbm进行compute之后得到视差图disparity_sgbm,除以16得到用于计算的视差图disparity(除以16是因为每个像素值由一个16bit表示,其中低位的4位存储的是视差值得小数部分,所以真实视差值应该是该值除以16)。

cv::Mat disparity_sgbm, disparity, disparityCV_8U; sgbm->compute(rectifyImageL, rectifyImageR, disparity_sgbm); disparity_sgbm.convertTo(disparity, CV_32F, 1.0 / 16.0f); //用来测距

    将compute后的视差图,转为8位,得到可视的视差图disparityCV_8U,可以作为sgbm调参的直观依据,没有后续的作用了。

disparity_sgbm.convertTo(disparityCV_8U, CV_8U, 255 / (NumDisparities * 16.)); //用来调参直观参考 imshow("disparityCV_8U",disparityCV_8U);

    转换了正确的视差图格式之后,在计算点云时还要注意计算深度值的取点语句,数据类型也要对应好。

…… for (int i = 0; i PointXYZRGB p; double d = disparity.ptr(i)[j]; //注意数据类型 ……

    ok,关于点云分层、深度不连续的问题就解决啦,附上以上代码涉及到的两个知识点:图像格式(矩阵类型)和convertTo函数,配合阅读有助于深入认识。

图像格式(矩阵类型)

type()=0CV_8U八位无符号整型 (uchar)0–2551CV_8S八位有符号整型 (schar)-128–1272CV_16U十六位无符号整型 (ushort)0–655353CV_16S十六位有符号整型 (short)-32768–327674CV_32S三十二位有符号整型 (int)0–655355CV_32F三十二位浮点数 (float)0.0–1.06CV_64F六十四位浮点数 (double)0.0–1.0

在这里插入图片描述

convertTo函数 xxx.convertTo(dst, type, scale, shift)

dst:目的矩阵; type:需要的输出矩阵类型,或者更明确的,是输出矩阵的深度,如果是负值(常用-1)则输出矩阵和输入矩阵类型相同。转换位深度本质上就是对原深度下的数据做线性变换,使原位深度下的最小值和最大值分别对应转换后位深度下的最小值和最大值。 scale:范围比例因子;eg. 原来的图是255的灰度图,转成float型数据并归一化到0~1,那么就是scale=1.0/255 shift:将输入数组元素按比例缩放后添加的值;

    目前OpenCV主要只支持单通道和3通道的图像,并要求其深度为8bit和16bit无符号(即CV_16U),所以其他是不支持的,比如说float型等。     如果Mat类型数据的深度不满足上面的要求,则需要使用convertTo()函数来进行转换。convertTo()函数负责转换数据类型不同的Mat,即可以将类似float型的Mat转换到imwrite()函数能够接受的类型。

问题2:点云放射、发散、锥形,总之不能看

在这里插入图片描述 在这里插入图片描述     如果出现以上类似效果,PCL点云是发散、放射、圆锥形的问题,先上结论:点云可能是对的,但发散出来大多都是无效点,除掉即可。     这个问题太过于细节,以致于排查时无从下手,反而去检查了许多点云坐标的计算和PCL的设置语句,也花了不少时间。其实仔细观察这个问题和上一类还不一样,这里的点云锥顶部份比较稠密,而且分层也不是那么规律。再考虑到相机硬件本身的局限性,基线的长度决定了测距的有效范围,超过范围的点误差就会很大,这些点也是没有意义的。     所以,解决的方法也很简单,在计算点云的双for循环中添加以下语句,把视差值小于80或者深度大于60cm的点剔除掉即可。(这里的数字不一定适配你的硬件,自行修改)

if (d


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有