OpenCV基于点阵结构光的深度图三维重建算法
来源:互联网 发布:微信公众号淘宝客 编辑:程序博客网 时间:2024/06/01 10:05
System Status: 2 IR cameras(OV9281) + 1 laser projector(HEPTAGON LIMA2.0-SD-0)
Using Active Stereo method, not coded structure light( coding and decoding) or ToF.
1. OpenCV Stereo BM/SGBM
BM算法原理简介
Step1.使用立体相机标定参数对当前StereoCamera出图进行校准,校准后的同一目标点处于相同的水平线上,校准后的图像为left_rectify& right_rectify;
Step2.图像预滤波,使用水平sobel算子对图像进行处理,产生新的滤波后图像P_new
Step3.计算SAD(sum ofabsolute difference) cost,上述代价是在SAD窗口中计算得到;
Step4.唯一性检验:视差窗口范围内最低代价是次低代价的(1+ uniquenessRatio/100)倍时,最低代价对应的视差值才是该像素点的视差,否则该像素点处视差为0;
Step5.左右一致性检验:左图找到的匹配点,与匹配点在左图中的匹配点为同一点才判断合法,否则为误匹配点。
StereoBM参数说明:
预处理参数:
preFilterCap –水平sobel滤波器大小,一般设置31;
SADWindowSize –计算代价的SAD窗口大小:一般设置9;
minDisparity –最小视差,默认为0,此参数决定左图中的像素点在右图匹配搜索的起点。
numberOfDisparity –视察搜索范围,其值必须是16的整数倍,最大搜索边界= numberOfDisparity + minDisparity;
uniquenessRatio –唯一性检测参数,最低代价/次低代价> (1 +uniquenessRatio/100),该像素为有效点;
disp12MaxDiff –左右一致性检测最大容许误差阈值,默认为1;
speckleWindowSize –视差连通区域像素点个数大小,对于每一视差点,当连通区域的像素点个数小于speckleWindowSize时,认为该视差值无效,是噪点;
SpeckleRange –视差连通条件,在计算一个视差点的连通区域时,当下一像素点的视差变化绝对值大于SpeckleRange就认为下一像素点和当前像素点是不连通的。
这里,结合BM开发经历,列出一些自己认为比较重要的参数:
numberOfDisparities -- 最重要,与需要处理场景内容的深度紧密相关,该值越大,处理的深度范围越广,但是视差误匹配会概率性增多;
SADWindowSize -- 一般选取5,7,9,11等,不同取值结果差异大;
uniquenessRatio -- 最低代价与次低代价的比率,该值越大,则该像素点所得视差值越(苛刻)可靠,视差图空洞较多;
speckleWindowSize -- 视差连通区域像素个数的数量,该值越大,面积较小离散斑点被筛除;
speckleRange -- 视差连通条件,当一个像素与相邻下一个像素视差变化超过该值时,则认为它们是不连通的。
关于BM/SGBM算法的使用与参数设置在很多博客中都有讲到,给出一个SGBM参数详细解释的博客地址点击打开链接
关于BM算法解决视差图黑边的代码:
Mat img1p, img2p;if (STEREO_BM == alg){ copyMakeBoarder(img1, img1p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE); copyMakeBoarder(img2, img2p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE); img1 = img1p; img2 = img2p;}if (STEREO_BM == alg){ bm->compute(img1, img2, disp); disp = disp.colRange(numberOfDisparities, img1p.cols);}2. Laser Pattern
laser pattern投射到1.5m左右人体表面状态:
HEPTAGON LIMA2.0-SD-0 laser pattern:
HEPTAGON laser datasheet:
3. 空洞修复算法
holefilling算法流程
Input:disp –待修复视差图Output:dstDisp -修复后视差图
Step1.找到disp中未计算深度的空点,空点集合设为Ω;
Step2.遍历每一空点Ω(e),根据其邻域信息δ(e)判断其是否处于空洞中,如果δ(e)内包含一半以上的深度有效像素(validPixel),则认为其为空洞点;
Step3.使用方形滤波器对空洞点进行填补,利益滤波器与有效像素的加权值补充空洞点处深度值,得到dstDisp;
Step4.根据设定的迭代次数(iteration)来,置disp =dstDisp,并重复上述步骤,直至迭代完成,输出结果修复后的dstDisp,并据此生成深度数据。
滤波器及权重设置
采用类似高斯权重设置的方法设置该滤波器权重,离目标像素越远的有效像素,对该空洞点视差值填补的贡献越小。
filterSize滤波器大小选择
滤波器目前可选取5x5, 7x7, 9x9, 11x11.
validPixel有效像素点数选择
例如:使用5x5的滤波器时,需要对空点周边的24个像素值进行深度有效像素点数量的判断,通常认为,空洞点周边应被有效点所环绕,所以此时有效像素点数至少设置为滤波器包含像素一半以上才合理,可设置为validPixel =12;使用其他size滤波器时,有效像素点数设置也应大于滤波器包含像素一半。
iteration迭代次数选择
针对不同的滤波器大小,收敛至较好效果时的迭代次数不一样,需要根据具体场景分析设定。
Source code
void holefilling(Mat _dispSrc, Mat* _dispDst){ int64 t = getTickCount(); if (CV_8UC1 != _dispSrc.type()) { _dispSrc.convertTo(_dispSrc, CV_8UC1); } Mat dispBw; threshold(_dispSrc, dispBw, dispMin, 255, THRESH_BINARY); dispBw.convetTo(dispBw, CV_32F, 1.0/255); Mat dispValid; _dispSrc.convertTo(dispValid, CV_32F); int margin = filterSize/2; Mat dispFilt = _dispSrc; for (int i = margin; i < dispBw.rows; i++) { for (int j = margin; j < dispBw.cols; j++) { if (0 == dispBw.at<float>(i, j)) { Mat filtMat = dispBw(Range(i - margin, i + margin + 1), Range(j - margin, j + margin + 1)); Scalar s = sum(filtMat); if (s[0] > validPixel) { Mat tmpWeight; multiply(filtMat, domainFilter, tmpWeight); Scalar s1 = sum(tmpWeight); Mat valid = dispValid(Range(i - margin, i + margin + 1), Range(j - margin, j + margin + 1)); Mat final; multiply(tmpWeight, valid, final); Scalar s2 = sum(final); dispFilt.at<unsigned char>(i, j) = (unsigned char)(s2[0] / s1[0]); } } else { dispFilt.at<unsigned char>(i, j) = (unsigned char)(dispValid.at<unsigned char>(i, j)); } } } *dispDst = dispFilt; t = getTickCount() - t; printf("Time Elapsed t : %fms\n", t1*1000/getTickFrequency);}
4. 深度图去噪
Source code
static int depthDenoise(Mat _dispSrc, Mat* _dispDenoise){ Mat contourBw; threshold(_dispSrc, contourBw, dispMin, 255, THRESH_BINARY); vector<vector<Point>> contours; findContours(contourBw, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); double minArea = 10000*scale; for (int i = contours.size() - 1; i >= 0; i--) { double area = countourArea(contours[i]); if (area < minArea) { contours.erase(contours.begin() + i); } } Mat contourDisp(_dispSrc.size(), CV_8UC1, Scalar(0)); drawContours(contourDisp, contours, Scalar(1), -1); multiply(_dispSrc, contourDisp, *_dispDenoise); return 0;}
- OpenCV基于点阵结构光的深度图三维重建算法
- 基于结构光的相移法三维重建matlab
- 基于光流的室外场景三维重建
- 基于结构光的深度测距structure light coding
- 基于深度相机的三维重建技术
- 一种基于OpenCV的三维重建实现方案
- 多频外差法三维重建 结构光三维重建
- 高精度单目结构光三维重建
- python+opencv实现基于图片序列的三维重建
- 基于OpenCV和VTK的冠脉三维重建
- 【视觉-结构光三维重建-理论篇】结构光 三维重建----论文调研3
- 结构光:投影仪的标定(OpenCV)
- 【opencv学习】lucas金字塔光流算法的实现——基于opencv3.0+vs2013+windows10
- 基于PCL的三维重建——随机采样一致性算法
- 基于VTK的图像三维重建
- 基于Kinect的室内三维重建
- opencv基于光流匹配
- 7.结构光:投影仪的标定(OpenCV)
- 设计模式之七:原型模式
- 一些常用的C++11新增特性
- drupal上传利用脚本
- H5新特性WebStorage相关用法详解
- 设置maxsize的自动扩展数据文件在达到maxsize后是否会继续扩展
- OpenCV基于点阵结构光的深度图三维重建算法
- 输出和输入
- android框架基础之模板方法模式
- IIS重写-正则或的写法
- PHP - 自动加载
- 正则--match和exec方法
- 合作开放
- mysql 触发器 实例
- 编译错误:Could not get unknown property 'release' for SigningConfig container