具体实施方式
下面通过具体实施方式结合附图2对本发明进行详细说明。
立体匹配方法通过匹配两个不同的摄像机视图的像素点,从而获得像素点的视差图和深度信息。这两个视图必须要有一定的重叠区域(否则无法进行匹配),通常可以通过数码相机或者摄像机得到。
在局部立体匹配方法中,为了提高匹配的准确性,需要以像素点为中心构建一个匹配窗口,匹配的时计算匹配窗口内的总的匹配代价。由于在深度不连续的地方,会出现“Foreground flattening”现象,因此动态调整匹配窗口至关重要。
请参考图1,在本发明的一种实施例中,我们通过步骤step1~step8,最终获得了精确的稠密视差图,整个过程包括图像的采集、摄像机的校正、边缘轮廓的提取、匹配窗口的构建、匹配代价的计算、WTA策略、一致性检测、视差值的传递和视差图的优化等部分。具体步骤如下:
Step1:图像的采集和摄像机的标定。
1.图像的采集。通过数码相机或摄像机采集图像,图像之间要有一定的重叠区域。
2.摄像机的标定。得到两台摄像机之间几何关系。
Step2:调整摄像机间的角度和距离,输出行对准的校正图像(左图像和右图像)。行对准指的是两图像在同一个平面上,并且图像的每一行是严格对齐(具有相同的方向和y坐标)。
Step3:通过Canny边缘提取方法提取左右图像的边缘轮廓。Canny边缘提取方法是目前公认性能最好的边缘提取方法之一。我们将提取到的边缘轮廓上的像素点的灰度值设为255,将其它像素点的灰度值设为0,这样就得到了以灰度值255和0标识的边缘轮廓图I1。
Step4:利用Step3中得到的边缘轮廓构造动态变化的匹配窗口。在局部立体匹配中一个关键的因素是如何根据像素周围的信息动态调整匹配窗口的大小,从而使得在匹配窗口中的所有像素具有相同或像素的视差值。本步骤通过边缘分割来构造动态的匹配窗口,原理图如附图3。
对于左图中的任意像素点p(x,y),我们将它周围的像素点分为两类:内点和外点,所有内点(包括像素点p本身)构成像素点p的匹配窗口。接着我们要做的就是寻找像素点p周围的所有内点,方法如下:
1.我们以像素点p为起始点,首先在正y轴(竖直向上的方向)寻找内点。将遇到的所有像素点q(x,y’)标记为内点,直到如下两种情况之一出现为止:一是发现像素点q为边缘轮廓上的一个像素点;二是像素点p和像素点q的距离(因为p和q的横坐标相同,他们的距离就是y轴上的距离)大于L(L是用来限制匹配窗口的最大值,可以设定为10)。同样,在负y轴(竖直向下的方向)上以像素点p为起始点来寻找内点。将遇到的所有像素点q标记为内点,直到上面介绍过的两种情况之一的出现为止。
在具体实施的时候,我们可以根据边缘轮廓图I1中p(x,y)周围的像素点的灰度值来判断是否为边缘点:若q(x,y’)的灰度值为255,则说明q是一个边缘点,此时满足上面情况,内点标记停止;若q(x,y’)的灰度值为0,则说明不是边缘点,应该标记为内点。
2.通过上面的方法,我们已经得到了以像素点p为中心的在竖直方向(y轴)上所有的内点q1,q2,q3...。接下来我们通过y轴方向上的内点构造水平方向上的内点:以这些内点为起始点(例如q1(x,y’),我们在水平向左(x轴负方向)和水平向右(x轴正方向)上将遇到的所以像素点标记为内点,直到如下两种情况之一出现为止:一是发现像素点s(x’,y’)为边缘轮廓上的一个像素点;二是像素点s和像素点q1之间的距离(由于他们的纵坐标相同,他们的距离就是水平距离)大于L(与上面相同,设定为10)。
同样我们根据边缘轮廓图I1中q1(x,y’)周围的像素点的灰度值来判断是否为边缘点,与前面介绍的方法相同。
这样通过1和2我们标记处了像素点p周围的所有内点,包括竖直方向上的内点q1,q2,q3...和以它们为中心标记的水平内点s1,s2,s3...。这些内点构成了像素点p周围的匹配窗口。除去内点之外的所有像素点为外点。
在本实例中,我们可以选择一个二维数组来标识像素点p的匹配窗口:uchar mask[21][21](21=2*L+1)。当mask中的一个元素的值为1时代表的是一个内点,为0代表的是一个外点。一个可能的mask数组的值为:
Mask[21][21]={
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0},
{0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
可以看到Mask由值为0或者1的元素构成,所有为1的元素是像素p的内点,从而它们构成像素点p的匹配窗口。注意:像素点p对应Mask二维数组中的Mask[10][10], 匹配窗口是以像素点p为中心,在p的周围像素点中找到的。
Step5:在局部匹配窗口中计算匹配代价。匹配窗口内的匹配代价的计算方法有很多种, 如SAD(sum of absolute differences), SSD(sum of squared differences),STAD(sum oftruncated differences)。在本实例中为了提高性能,我们选择STAD方法来计算匹配代价,它的计算公式如下:
Step6:利用WTA选择最优的视差值。对于左图中的像素点p,我们需要在右图中的搜索范围为[0,dmax)(dmax是可能出现的最大的视差值)内寻找匹配代价最小的像素点q(x-d,y),并把此时的视差值d作为像素点p的视差值。不断重复这个过程,我们就能够找到左图像中所有像素点的视差值。
Step7:一致性检测。有上一步得到的视差值中存在着很多错误的匹配点,这是由于遮挡、低纹理和高纹理因素的影响所导致的。这一步我们采用一致性检测来消除这些错误匹配的点,从而得到可信度较高的、可以认为是正确的视差值种子点。具体而言就是:对于左图中的每一个像素点p(x,y),我们找到右图中的匹配点q(x-d1,y),它的视差值为d1;然后以右图中像素点q(x-d1,y)为基准,找到左图中与之最匹配的匹配点p’(x-d1+d2,y),如果p就是p’,这意味着d1==d2,那么我们就说像素点p通过了一致性检测,我们将其标记为视差种子点;否则,我们便将其标记为非种子点。
Step8:将种子点的视差值传递给非种子点。由Step7将左图中所有的像素点分为两类:视差种子点和非视差种子点。视差种子点的视差值具有很高的可信度,我们将其视为正确的视差值。而通过视差种子点构成的视差图是稀疏的视差图,我们需要将这些种子点的视差值传递给周围的非视差种子点,从而构成了稠密的视差图。
有学者提出通过插值法来实现:非种子点的视差值通过周围最近邻的种子点的视差值的插值方法来得到,并对深度不连续的区域和遮挡区域进行特殊处理(选取较小的视差值作为它的非种子点的视差值)。本发明采用另外一种新的视差值传递方法,它采用颜色差异比较来进行传递,具有更好的实现效果。
对于左图中的每一个非种子点p,我们在它水平方向的两端寻找最近邻的种子点(此处我们假设SL,SR分别为左边最近邻种子点和右边最近邻种子点),SL和SR的视差值分别为dL,dR。
我们首先比较dL和dR的大小,如果dL<dR,说明像素点p位于深度信息不连续的区域,而且像素点p极有可能位于遮挡区域。此时我们将点p标记为处于遮挡区域,它的视差值为min(dL,dR)。
如果dL>dR,此时我们通过比较像素点p和SL和SR的颜色差异来选取最终的视差值。具体而言如下:如果p和SL的颜色差异较小,我们选择SL的视差值作为非种子点p的视差值;否则,我们选择SR的视差值作为非种子点p的视差值。
颜色差异的定义如下:它是两个像素点在RGB空间内的灰度值差值的绝对值之和。若两个像素点之间的颜色差异较小,则它们趋向于处于同一个深度平面内,因而具有相同或相似的视差值。通过比较p和左右邻近种子点的颜色差异,我们将颜色差异更小的种子点的视差值赋值给非种子点。
Step9:优化视差图。这一步对所得的稠密视差图进行优化。由上一步得到的视差图中仍然存在一些错误的视差值,这些错误的视差值一方面来自少量的错误种子点,另外一方面来自在种子点视差值传递过程中的一些错误的视差传递。我们采用基于投票方法的来消除这些错误匹配的像素点。
1.水平方向上进行投票。对于视差值不连续的区域(如p(x,y),q(x+1,y),p和q的视差值的差的绝对值大于一个阈值Td,Td我们设为2),我们以像素点p为中心构造分割段:
以p(x,y)为起始点,我们从左、右两个方向上检测像素点,如像素点q,如果p和q的颜色差异值小于阈值Tc(Tc在本实施例中取为10),我们标定q位分割段内的点。一旦发现p和q的颜色差异值大于等于阈值Tc,或者分割段的长度大于设定的最大值Ts(在本实施例中我们设定Ts为41),则停止检测。我们得到分割段[m,n]。注:m,m+1,m+2,...,n都为分割段内的像素点。
在分割段内的所有像素点内进行投票。具体实施如下:我们利用数组votes[dmax]来表示投票结果,votes[i](0<=i<dmax)代表视差值i所获得的总票数。
假设q为分割段内的一个像素点,q的视差值为D(q),那么votes[D(q)]++。
对于每个分割段内的像素点,我们统计视差值在它们中间出现的次数(频率),最后我们将搜索得到票数最多的视差值,将它赋值为像素点p的视差值。
2.竖直方向上进行投票。与水平方向上的投票过程是相同的,只不过是在竖直方向上进行。我们同样遇到视差值不连续的区域,我们首先构造分割段,分割段内的所有像素点与p点的颜色差异小于设定的阈值Tc;然后在分割段内进行投票,统计不同的视差值出现的频率;最后将像素点p的视差值通过拥有票数最多的视差值进行更新。
这两个过程重复2次,就可以基本上消除所有的错误匹配像素点了。
最后我们得到了精确的稠密的视差图。