立体匹配算法SGBM

SGBM算法,作为一种全局匹配算法,立体匹配的效果明显好于局部匹配算法,但是同时复杂度上也要远远大于局部匹配算法。


原文链接:https://blog.csdn.net/renshengrumenglibing/article/details/8525328SGBM的基本原理

 



SGBM的基本步骤涉及:预处理、代价计算、动态规划以及后处理
 

预处理

Step1:SGBM采用水平Sobel算子,把图像做处理,公式为:

                Sobel(x,y)=2[P(x+1,y)-P(x-1,y)]+ P(x+1,y-1)-P(x-1,y-1)+ P(x+1,y+1)-P(x-1,y+1)

Step2:用一个函数将经过水平Sobel算子处理后的图像上每个像素点(P表示其像素值)映射成一个新的图像:PNEW表示新图像上的像素值。映射函数:
    


预处理实际上是得到图像的梯度信息。经预处理的图像保存起来,将会用于计算代价。

 预处理参数

1:preFilterCap:水平sobel预处理后,映射滤波器大小默认为15

int ftzero =max(params.preFilterCap, 15) | 1;

opencv测试例程test_stereomatching.cpp中取63。

代价计算

代价有两部分组成:

           1经过预处理得到的图像的梯度信息经过基于采样的方法得到的梯度代价

           2原图像经过基于采样的方法得到的SAD代价

      上述两个代价都会在SAD窗口内进行计算。

立体匹配算法SGBM_第1张图片 图二Reference support window (Np)and target support window (Npd)when dp=d标题标题

基于采样的方法,参考论文:DepthDiscontinuities by Pixel-to-Pixel Stereo 在计算代价的时候,用基于采样的方法效果会好一些。

代价计算参数

2:SADWindowSize:计算代价步骤中SAD窗口的大小。由源码得,此窗口默认大小为5。

SADWindowSize.width= SADWindowSize.height = params.SADWindowSize > 0 ?params.SADWindowSize : 5;

注:窗口大小应为奇数,一般应在3x3到21x21之间。

3:minDisparity:最小视差,默认为0。此参数决定左图中的像素点在右图匹配搜索的起点。int 类型

4:numberOfDisparities:视差搜索范围,其值必须为16的整数倍(CV_Assert( D % 16 == 0 );)。最大搜索边界= numberOfDisparities+ minDisparity。int 类型
 

动态规划

动态规划算法本身存在拖尾效应,视差突变处易产生错误的匹配,利用动态规划进行一维能量累积,会将错误的视差信息传播给后面的路径上。半全局算法利用多个方向上的信息,试图消除错误信息的干扰,能明显减弱动态规划算法产生的拖尾效应

半全局算法试图通过影像上多个方向上一维路径的约束,来建立一个全局的马尔科夫能量方程,每个像素最终的匹配代价是所有路径信息的叠加,每个像素的视差选择都只是简单通过 WTA(Winner Takes All)决定的。多方向能量聚集如下图所示:

在每个方向上按照动态规划的思想进行能量累积,然后将各个方向上的匹配代价相加得到总的匹配代价,如下式所示:

式中L为当前路径累积的代价函数,P1、P2为像素点与相邻点视差存在较小和较大差异情况下的平滑惩罚,P1

动态规划参数

默认4条路径,其中动态规划很重要两个参数P1,P2控制视差变化平滑性的参数。P1、P2的值越大,视差越平滑。P1是相邻像素点视差增/减 1 时的惩罚系数;P2是相邻像素点视差变化值大于1时的惩罚系数。P2必须大于P1。需要指出,在动态规划时,P1和P2都是常数。opencv测试例程test_stereomatching.cpp中是这样设定的:

P1 =8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;

P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;

cn是图像的通道数, SADWindowSize是SAD窗口大小,数值为奇数。

可以看出,当图像通道和SAD窗口确定下来,SGBM的规划参数P1和P2是常数。
 

后处理

opencvSGBM的后处理包含以下几个步骤:

Step1:唯一性检测:视差窗口范围内最低代价是次低代价的(1 + uniquenessRatio/100)倍时,最低代价对应的视差值才是该像素点的视差,否则该像素点的视差为0。其中uniquenessRatio是一个常数参数。

Step2:亚像素插值:

       插值公式:

Step3:左右一致性检测:误差阈值disp12MaxDiff默认为1,可以自己设置。

OpencvSGBM计算右视差图的方式:通过得到的左视察图计算右视差图

通过得到的左视察图计算右视差图标题

这个时候dispR[X-d]是d还是d+n?

实际上,dispR[X-d]的确定方式是比较dispL中X和X+n出的最小代价,选代价最小的对应的视差作为最优视差。

确定右图视差后,通过这样一个措施来确定左视察图中的像素视差是否有效

| dispR[X-d]-dispL[X]|

如果这个条件成立,就是误匹配点。这个条件成立,为什么就是误匹配点呢?

实际上这个条件(LRcheck)检测的大都是遮挡点,比如图1中,左视差图X和X+n处按照图一规则都会映射到右视差图的X-d处,若在左视差图中,X位置是遮挡点,那么左视差图X位置的最小代价一定会比X+n处大(因为X处根本找不到匹配,所谓最小代价也是很大的),这样dispR[X-d]=d+n。

现在开始用条件1来检测左视差图的误匹配点

先解释一下条件1左侧的条件:检测到X处(遮挡误匹配点),发现dispR[x-d]=d+n,并不是d。因此就会符合条件1中的dispR[X-d]-dispL[X]|

实际上这个条件是想解决一个这样的事情:当左图多个点同时匹配到右图中同一个点时,如何选择正确的匹配关系,毕竟左右图像素应该是一对一的。

解决方法:认为多对匹配关系中,匹配代价最低的是正确匹配关系,然后用条件1选出正确的匹配关系。

亲测把条件1变成dispR[X-d]-dispL[X]|

再解释一下条件1右侧的条件:

条件1的另一部分(| dispR[X-d-1]-dispL[X]-1|

综上,在左视察图中,如果一个像素点是遮挡误匹配点,那么就会符合条件1。因而就会被检测出来。

 

Step4:连通区域的检测:简述:对左右一致性检测后的视差图再一次检测误匹配点,根据与当前处理的视差点满足连通条件的像素点个数来判断当前处理的视差点是否是误匹配点,个数小于一个阈值就认为是误匹配点。

方法:循环遍历每一个像素点,对每一个视差像素点d而言,检测其周围(上下左右)的视差是否满足这样的条件(称为视差连通条件):

1, 首先是LRcheck后,视差有效的点

2, 和中心视差值的(变化)绝对值不超过speckleRange。注:speckleRange是一个常数参数,可以自己设定。Opencv例程中speckleRange=10.

对于一个视差点:

Step1:当上下左右(以下简称周围)点至少有一个视差点满足视差连通条件后,再分别以它们为起点(称为传播),检测其周围(前向传播的点不算,比如,Pixel2是通过Pixel1传播过来的,即Pixel2肯定是Pixel1周围的点。再以Pixel2为起点检测周围的视差点是否满足视差连通条件时,Pixel1虽然也是Pixel2周围的视差点,但不算满足视差连通条件)的视差点是否满足视差连通条件。

Step2:每检测到一个新的连通点,其相应点的标志位置1,,计数器加一,直到对于每一个新的连通点,其周围的点(标志位置1的点也不算满足视差连通条件)都不满足视差连通条件。停止计数。

Step3:判断计数值(即和当前处理的视差点的连通区域的像素点个数)>speckleWindowSize?(注:speckleWindowSize是一个常数参数,可以自己设定。Opencv例程中speckleRange=100。)若大于,视差值认为有效,否则认为当前视差值是噪点。

连通区域检测有助于去除经LR和唯一性检测后残余的噪点,效果比较理想。
 

后处理参数

7:uniquenessRatio:唯一性检测参数。对于左图匹配像素点来说,先定义在numberOfDisparities搜索区间内的最低代价为mincost,次低代价为secdmincost。如果满足

即说明最低代价和次第代价相差太小,也就是匹配的区分度不够,就认为当前匹配像素点是误匹配的。

opencv测试例程test_stereomatching.cpp中,uniquenessRatio=10。int 类型

8:disp12MaxDiff:左右一致性检测最大容许误差阈值。int 类型

opencv测试例程test_stereomatching.cpp中,disp12MaxDiff =1。

9:speckleWindowSize:视差连通区域像素点个数的大小。对于每一个视差点,当其连通区域的像素点个数小于speckleWindowSize时,认为该视差值无效,是噪点。

opencv测试例程test_stereomatching.cpp中,speckleWindowSize=100。

10:speckleRange:视差连通条件,在计算一个视差点的连通区域时,当下一个像素点视差变化绝对值大于speckleRange就认为下一个视差像素点和当前视差像素点是不连通的。

opencv测试例程test_stereomatching.cpp中,speckleWindowSize=10。
 

总结:

 

opencv sgbm修改自Heiko Hirschmuller的《Stereo Processing by Semi-global Matching and Mutual Information》,与原方法不同点:

没有实现原文中基于互信息的匹配代价计算,而是采用BT算法(“Depth Discontinuities by Pixel-to-Pixel Stereo” by S. Birchfield and C. Tomasi);
默认运行单通道DP算法,只用了5个方向,而fullDP使能时则使用8个方向(可能需要占用大量内存);
增加了一些BM算法中的预处理和后处理程序;

//引入概率公式
//引入CBT的插值方法
//加上相邻匹配点位置之间的限制

blockSize(SADWindowSize) 越小,也就是匹配代价计算的窗口越小,视差图噪声越大;blockSize越大,视差图越平滑;太大的size容易导致过平滑,并且误匹配增多,体现在视差图中空洞增多;
惩罚系数控制视差图的平滑度,P2>P1,P2越大则视差图越平滑;
八方向动态规划较五方向改善效果不明显,主要在图像边缘能够找到正确的匹配;

 


 

你可能感兴趣的:(三维重建)