OpenCV三种立体匹配求视差图算法总结
http://blog.csdn.net/mailang2008/article/details/5873883
对OpenCV中涉及的三种立体匹配算法进行代码及各自优缺点总结:
首先我们看一下BM算法:
该算法代码:
- CvStereoBMState *BMState = cvCreateStereoBMState();
- int SADWindowSize=15;
- BMState->SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 9;
- BMState->minDisparity = 0;
- BMState->numberOfDisparities = 32;
- BMState->textureThreshold = 10;
- BMState->uniquenessRatio = 15;
- BMState->speckleWindowSize = 100;
- BMState->speckleRange = 32;
- BMState->disp12MaxDiff = 1;
- cvFindStereoCorrespondenceBM( left, right, left_disp_,BMState);
- cvNormalize( left_disp_, left_vdisp, 0, 256, CV_MINMAX );
其中minDisparity是控制匹配搜索的第一个参数,代表了匹配搜苏从哪里开始,numberOfDisparities表示最大搜索视差数uniquenessRatio表示匹配功能函数,这三个参数比较重要,可以根据实验给予参数值。
该方法速度最快,一副320*240的灰度图匹配时间为31ms,视差图如下。
第二种方法是SGBM方法这是OpenCV的一种新算法:
- cv::StereoSGBM sgbm;
- sgbm.preFilterCap = 63;
- int SADWindowSize=11;
- int cn = 1;
- sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 3;
- sgbm.P1 = 4*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
- sgbm.P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
- sgbm.minDisparity = 0;
- sgbm.numberOfDisparities = 32;
- sgbm.uniquenessRatio = 10;
- sgbm.speckleWindowSize = 100;
- sgbm.speckleRange = 32;
- sgbm.disp12MaxDiff = 1;
- sgbm(left , right , left_disp_);
- sgbm(right, left , right_disp_);
各参数设置如BM方法,速度比较快,320*240的灰度图匹配时间为78ms,视差效果如下图。
第三种为GC方法:
- CvStereoGCState* state = cvCreateStereoGCState( 16, 2 );
- left_disp_ =cvCreateMat( left->height,left->width, CV_32F );
- right_disp_ =cvCreateMat( right->height,right->width,CV_32F );
- cvFindStereoCorrespondenceGC( left, right, left_disp_, right_disp_, state, 0 );
- cvReleaseStereoGCState( &state );
该方法速度超慢,但效果超好。
各方法理论可以参考文献
BM、GC、SGBM三种算法的比较和BM在OpenCV3下的参数设置
模拟人的两只眼睛的Stereo相机最近变得很受欢迎。通过对stereo相机拍摄的左右两张图进行匹配找出视差图,可以还原物体的3D信息。立体匹配(Stereo matching)的步骤如下:
1: 预处理:亮度归一化,去噪,图像增强,滤波等等
2: 匹配Cost计算Cost aggregation
每个像素点的matching cost可用下图所示的两种方式表示
将所有像素的Cost加起来,选择和最小的方案。
3: 全局最优化
4: 后处理:Refinement 精化
一般基于像素点的匹配含有较大的噪音,所以人们更愿意使用基于局部或全局的匹配算法。常用的立体匹配算法可分为基于局部的匹配方法和基于全局的匹配方法。
(1)基于局部的匹配算法:块匹配,模板匹配,SIFT[1],SURF[2],AKAZE[3]
(2)基于全局的匹配算法:首先定义Cost Function,然后根据约束条件优化Cost Function.
- Dynamic Programming
- Scaling Optimization
- Graph Cuts
- Belief Propagation:Markov Random Field
一般的Cost Function如下:ED基于像素的亮度,Es基于像素邻居之间的Smoothness。
1:Graph Cut: 将每一个像素看作Graph中的一个Node,然后假设该图有L个不同的深度值,则添加L个
新的Node作为Label,然后求视差图的问题就变成了多重Labelling的问题了,具体Graph Cut参照文
献[4]。
2:Belief Propagation: 将图像看作马尔科夫随机场,则求视差问题变成了最大化联合后验概率的问题,
每一个像素对其深度值的猜测来自于其邻居给的信息,然后再把信息传给其他的邻居。每一个信息有 一个可靠度(概率)。最后经过多次循环深度值会收敛。
[1]Lowe, David G. (2004). "Distinctive
Image Features from Scale-Invariant Keypoints"
[2]Herbert Bay,Tinne Tuytelaars, and Luc Van Gool,SURF: Speeded Up Robust Features,ECCV,2006
[3]Pablo F. Alcantarilla, Adrien
Bartoli and Andrew J. Davison, KAZE
Features. In European Conference on Computer Vision (ECCV),
2012.
[4]Yuri Boykov and Vladimir Kolmogorov (2003),
"Computing Geodesics and Minimal Surfaces via Graph Cuts"
OpenCV提供了以下四种立体匹配算法的函数:
- Block Matching(BM) StereoBM
- Semi-Global Block Matching(SGBM) StereoSGBM
- Graph Cut(GC)cvStereoGCState()
- Dynamic Programming(DP)cvFindStereoCorrespondence()
计算量小速度快,而全局匹配计算量大速度慢,所以作者提出了SGBM算法[5]:
第一步对每一个Pixel使用块匹配BM进行匹配,得到了全部Pixel的disparity map。
第二步对Disparity map建立图,用Graph Cut对其进行全局优化。利用Rectification将二维转化为一维:
则对每一个像素的可能的Disparity值d,从以下4中里面选取一个最小值:
- 左相邻像素disparity取值为d时,其最小的cost值。
- 左相邻像素disparity取值为d-1时,其最小的cost值+惩罚1。
- 左相邻像素disparity取值为d+1时,其最小的cost值+惩罚1。
- 左相邻像素disparity取值为其他时,其最小的cost值+惩罚2。
要对每一种取值进行一次计算,计算量比SGBM要大得多。
[5]H. Hirschmuller, Stereo Processing by Semi-global Matching and Mutual Information,"IEEE Transactions
on Pattern Analysis and Machine
Intelligence, Vol. 30, Issue 2, pp. 328-341, Feb. 2008.
下图给出了各种不同算法的结果比较:
左右原图如下:
精度与速度统计图如下: