双目立体匹配之视差优化
本文是自己的一篇学习笔记,记录自己学习立体匹配过程中的问题及总结,在此分享,转载请附原文链接
视差优化
上一篇文章介绍了代价聚合,本文主要对视差优化的方法进行阐述。其实在代价聚合求出代价矩阵S后,接下来的操作是进行视差计算,但这一部分相对简单(主要采用了赢家通吃算法),在双目立体匹配步骤第三节已经介绍,这里不过多阐述。
视差优化,顾名思义,就是让视差图表现的效果更好!!!让效果更好,首先我们应该知道造成视差不好的原因是什么,所谓对症下药,事半功倍。其实原因很简单,就是代价聚合时匹配代价计算的不都准确,导致出现了错误的视差,而造成这种现象的原因往往是由影像噪声、遮挡、弱纹理或重复纹理等产生的。既然产生了错误的视差,那我们肯定是想办法修改这些错误的视差——我们采用的方法是:先剔除这些可恶的错误匹配点,让这些点成为无效点,然后再来填补这些无效点。
说到这里,我们就先来介绍剔除这些错误匹配点的方法。
左右一致性检查
左右一致性检查是目前视差优化最常用的方法,几乎所有的视差优化都会用到此方法。其是基于视差的唯一性约束,即每个像素只存在一个正确视差。其基本思想是:我们从代价聚合这步已经得到了左图像的视差图,现将左右图像互换位置,即左图像变成右图像,右图像变成左图像,这时候再重新做一次立体匹配,会得到新的左图像(原右图像)的视差图,这时比较左右图像同名点的视差,看视差是否一致,若一致,则满足一致性检查,否则不满足,这时就把不满足的点给剔除掉。实际上,我们对比较左右图像同名点的视差有一定的容忍程度,即不需要两者视差一致才保留,而是若两个视差值之间的差值若小于一定阈值(一般为1个像素),则满足唯一性约束被保留,反之则不满足唯一性约束而被剔除。一致性检查的公式如公式1所示:
这里的b指的是左视图,m指的是右视图,p和q为同名点对。
这就是左右一致性检查,是不是发现还挺简单的。像上面这种交换左右图像然后共进行两次立体匹配的一致性检查方法被称为外部型检查。需要注意的是,在对左右对调后,左右图像重叠区在两边,不符合原先算法的设定,所以这里我一般会在对调后,把左右影像的像素来个水平镜像翻转,这样两张影像的重叠区到了中间。我们可以通过下图看看左右图像对调后重叠区域的差异:
外部型检查这种方法逻辑清晰,但是进行两次立体匹配会消耗大量的时间。那有没有效率比较高的算法呢?…enmmm…我这么说那必定是有的,下面就来详细的介绍一下这种神奇的方法——内部型检查。好吧…其实也并不神奇,内部型检查法就是直接通过左影像的代价数组,来推算右影像的代价数组,从而计算右影像的视差图。看出来没有,这里没有做两次立体匹配的过程,这就大大的提高了效率。是不是听懂了,但好像也不懂,下面给出具体的操作,首先给出计算右影像代价的公式:
右影像( i , j )视差为d的代价 = 左影像( i , j + d )视差为d的代价
不知道能不能理解,现做如下解释:对于右影像的像素( i , j ),根据视差值d可算出左影像的对应像素位置为( i , j + d ),然后把左影像( i , j + d )同样视差值d下的代价值取出来作为右影像( i , j )在视差d下的代价值。
根据上面的公式,我们可以将右影像每个像素的所有候选视差d的代价值Cost ( i , j , d )都得到,进而寻找最小代价值对应的视差,最终得到右影像视差图。
计算出右视差图后,执行一致性检查:根据左影像视差图可以算出像素(ileft,jleft)在右影像中的匹配像素是(ileft,jleft-d),若(ileft,jleft-d)的视差刚好也近似等于d,则满足一致性。
读到这里会不会有这样的疑问呢:既然右影像的代价是根据左影像代价计算的,那算出来同名点的视差不会完全一致吗?有问题我认为非常好,起码说明我们在思考!!!
其实会产生这个疑问还是对代价计算的过程不清楚,代价计算是要计算出某点对于各个视差下的代价值。我们通过下图解释一下:现我们知道左图的A点像素为(i,j),其在右图中的匹配像素是A’(i,j-d),那么现在A’相对于A的视差的确为d,但这可以作为A’最终的视差嘛,显然这是不一定的,因为该点对应的匹配代价不一定是最低的,还要看其它视差下的代价值,最终选取一个最小的代价值所对应的视差作为该点的视差。如果你还没理解的化,那一定是我表述的不够清楚,再多读几篇看看能否理解我所想表达的含义。
剔除小连通域
剔除小连通域是指剔除掉视差图中连通的极小块区域,其在图像上一般表现为一些极不协调的一些小块,如下图红框中白色区域所示:
其主要的思想是判断同一个连通区域内的视差与邻域视差的差值,若差值大于规定的阈值,则将其剔除,将该块区域都视为无效的视差区域。
唯一性检测
唯一性检测是指对每个像素计算最小代价和次最小代价的值,若两者相对差小于一定阈值,则被剔除。其实这里也非常容易理解,举个例子,在寻找某个像素点的视差时,那么这时候会在代价矩阵中寻找代价最小的点,这时候发现最小的代价是20,但是还有一个次最小的代价是21,这两个代价相差很小,往往又因为代价计算是受噪声等因素影响的,所以这两个代价极其相近的点我们不能准确的说哪一个才对应着最优的视差,这时候我们就把这种不好抉择的点给剔除掉。这就是视差的唯一性检测。
上面介绍了几种剔除错误匹配点的方法,其实做这些的目的都是为了进行视差优化,下面再介绍一种视差优化的方法。
子像素拟合
我们通过代价矩阵得到的视差图是整像素精度的,这在许多应用中都是无法满足需求的。这时候我们需要对得到的视差图进行子像素拟合,让视差图的精度进一步提高。子像素拟合?怎么拟合?挺起来好像挺高大上的,但是…额…好像没有什么技术含量,你们肯定一看就懂。好了,下面通过下图来解释一下:
图中是某个像素在各个视差下的匹配代价,我们发现代价值最小的点在视差为18时取得,但这时我们不把该像素的视差定为18,而是在其左右各取一个代价指,将其记录下来,形成上图右边的三个条形图,然后利用这三个条形图进行一个一元二次拟合,曲线的最低点所对应的横坐标就是视差的子像素的位置。
我们将上图抽象出来,即知道三点的坐标(三个条形图的横坐标d和纵坐标cost),求做一个二次拟合曲线的极值点,如下图所示:
这个dsub也非常容易推导,我们设这个一元二次曲线的方程为 ,该方程有三个未知数,而我们知道三个点的坐标,即可求出这三个未知数的值。而且我们知道一元二次方程的最小值是在x=- 时取到,那么这个x就是dsub的值。
文章的一开始就提到我们要先剔除那些可恶的错误匹配点,让这些点成为无效点,然后再来填补这些无效点。现在那些错误匹配点已经基本填补,下面来介绍视差填充。
视差填充
下面直接进入主题,我们该怎么进行是视差填充呢?我们很自然的可能会想到:我们可以用无效视差周围的视差来对其进行填补。我想这种方法是可行的,但的确考虑的不周全,我们可以想想看,如果某一个像素p在左视图中可见,但在右视图中却不可见(即为遮挡区域),被遮挡的像素点p是位于背景图像的,该点的视差应该比较小(根据 z= ),而且p点应位于视差的非连续区域,即一侧是前景(视差大),一侧是背景(视差小)。因此我们在选择像p点这种被遮挡点的视差时,应该尽量选择背景像素的视差,即相对较小的视差。
通过上面的分析,我们在视差填补时应该先判断一些点是被遮挡点还是普通误匹配点(视差连续),然后根据不同的分类采取不同的分类策略。那么怎么判断某些像素是不是属于遮挡区呢?通过以下方法判断:
(1)像素p是通过各种优化操作而判定的无效像素。
(2)左影像像素p在右影像上的匹配像素为q = p − d,像素q在右视差图上的值为dr,通过dr找到左影像的匹配点p’,获取p’的视差d’,若d’>d,则p为遮挡区。
第二条有点绕,多读几篇理解以下,这里也给出一个另一种解释,看能不能辅助理解:假设q是通过视差d找到的同名点,如果在左影像存在另外一个像素p’ 也和q是同名点而且它的视差比d要大,那么p就是遮挡区。
既然上面已经知道了怎么判断哪些点是遮挡点,那么接下来就是如何为遮挡点和误匹配点分配合适的视差。我们采用如下方法:对于遮挡区像素,因为它的身份是背景像素,所以它是不能选择周围的前景像素视差值的,应该选择周围背景像素的视差值。由于背景像素视差值比前景像素小,所以在收集周围的有效视差值后,应选择较小的几个,具体哪一个呢?SGM作者选择的是次最小视差。对于误匹配像素,它并不位于遮挡区,所以周围的像素都是可见的,而且没有遮挡导致的视差非连续的情况,它就像一个连续的表面凸起的一小块噪声,这时周围的视差值都是等价的,没有哪个应选哪个不应选,这时取中值就很适合。选取合适视差的公式表示如下:
最后,我们可以来看以下视差填充视差图的区别,可以看出视差填充前的许多黑色的无效点在视差填充后都消失了。
咻咻咻咻~~duang~~点个赞呗
参考文章:
https://ethanli.blog.csdn.net/article/details/105897391
上一篇:双目立体匹配之代价聚合
- 点赞
- 收藏
- 关注作者
评论(0)