计算机视觉 — 立体视觉
文章目录
-
-
- 一、原理
- 二、实验分析
- 三、总结
- 四、实验代码
-
一、原理
介绍
立体视觉是计算机视觉领域的一个重要课题,它的目的在于重构场景的三维几何信息。立体视觉的研究具有重要的应用价值,其应用包括移动机器人的自主导航系统,航空及遥感测量,工业自动化系统等。
一般而言,立体视觉的研究有如下三类方法:
(1) 直接利用测距器(如激光测距仪)获得程距(range data)信息,建立三维描述的方法;
(2) 仅利用一幅图象所提供的信息推断三维形状的方法;
(3) 利用不同视点上的,也许是不同时间拍摄的,两幅或更多幅图象提供的信息重构三维结构的方法。
整体流程
(1) 图象获取 (image acquisition)
用作立体视觉研究的图象的获取方法是多种多样的,在时间、视点、方向上有很大的变动范围,直接受所应用领域的影响。立体视觉的研究主要集中在三个应用领域中,即自动测绘中的航空图片的解释,自主车的导引及避障,人类立体视觉的功能模拟。不同的应用领域涉及不同类的景物,就场景特征的区别来分,可以划分成两大类,一类是含有文明特征(cultural features)的景物,如建筑、道路等; 另一类是含有自然特征的景物和表面(natural objects and surfaces), 如山、水、平原及树木等。不同类的景物的图象处理方法大不相同,各有其特殊性。
(2) 摄像机模型 (camera modeling)
摄像机模型就是对立体摄像机组的重要的几何与物理特征的表示形式,它作为一个计算模型,根据对应点的视差信息,用于计算对应点所代表的空间点的位置。摄像机模型除了提供图象上对应点空间与实际场景空间之间的映射关系外,还可以用于约束寻找对应点时的搜索空间,从而降低匹配算法的复杂性,减小误匹配率。
(3) 特征抽取 (feature acquisition)
几乎是同一灰度的没有特征的区域是难以找到可靠匹配的,因而,绝大部分计算机视觉中的工作都包括某种形式的特征抽取过程,而且特征抽取的具体形式与匹配策略紧密相关。在立体视觉的研究中,特征抽取过程就是提取匹配基元的过程。
(4) 图象匹配 (image matching)
图象匹配是立体视觉系统的核心,是建立图象间的对应从而计算视差的过程,是极为重要的。
(5) 深度计算 (distance(depth) determination)
立体视觉的关键在于图象匹配,一旦精确的对应点建立起来,距离的计算相对而言只是一个简单的三角计算而已。然而,深度计算过程也遇到了显著的困难,尤其是当对应点具有某种程度的非精确性或不可靠性时。粗略地说,距离计算的误差与匹配的偏差成正比,而与摄像机组的基线长成反比。加大基线长可以减少误差,但是这又增大了视差范围和待匹配特征间的差别,从而使匹配问题复杂化了。为了解决这一问题出现了各种匹配策略,如由粗到精策略,松驰法等。
(6) 内插 (interpolation)
在立体视觉的应用领域中,一般都需要一个稠密的深度图。基于特征匹配的算法得到的仅是一个稀疏而且分布并不均匀的深度图。在这种意义下,基于区域相关匹配的算法更适合于获得稠密的深度图,但是该方法在那些几乎没有信息(灰度均匀)的区域上的匹配往往不可靠。因此,两类方法都离不开某种意义的内插过程。最为直接的将稀疏深度图内插成稠密的深度图的方法是将稀疏深度图看作为连续深度图的一个采样,用一般的内插方法(如样条逼近)来近似该连续深度图。当稀疏深度图足以反映深度的重要变化时,该方法可能是合适的。如起伏地貌的航空立体照片的处理中用这种方式的内插也许是比较合适的。但是这种方法在许多应用领域中,尤其是在有遮掩边界的图象的领域中,就不适用了。
几何原理
对应于同一场景点的点对

极线校正
对极约束意味着一旦我们知道了立体视觉系统的对极几何之后,对两幅图像间匹配特征的二维搜索就转变成了沿着极线的一维搜索。
匹配代价计算(Cost Computation)
计算匹配代价,即计算参考图像上每个像素点IR§,以所有视差可能性去匹配目标图像上对应点IT(pd)的代价值,因此计算得到的代价值可以存储在一个h w d(MAX)的三维数组中,通常称这个三维数组为视差空间图(Disparity Space Image,DSI)。匹配代价时立体匹配的基础,设计抗噪声干扰、对光照变化不敏感的匹配代价,能提高立体匹配的精度。因此,匹配代价的设计在全局算法和局部算法中都是研究的重点。
匹配代价计算的目的是衡量待匹配像素与候选像素之间的相关性。两个像素无论是否为同名点,都可以通过匹配代价函数计算匹配代价,代价越小则说明相关性越大,是同名点的概率也越大。
每个像素在搜索同名点之前,往往会指定一个视差搜索范围D(Dmin ~ Dmax),视差搜索时将范围限定在D内,用一个大小为W×H×D(W为影像宽度,H为影像高度)的三维矩阵C来存储每个像素在视差范围内每个视差下的匹配代价值。矩阵C通常称为DSI(Disparity Space Image)。
匹配代价计算是整个立体匹配算法的基础,实际是对不同视差下进行灰度相似性测量。常见的方法有灰度差的平方SD(squared intensity differences),灰度差的绝对值AD(absolute intensity differences)等。另外,在求原始匹配代价时可以设定一个上限值,来减弱叠加过程中的误匹配的影响。以AD法求匹配代价为例,可用下式进行计算,其中T为设定的阈值。
C(x_i,y_i)= \begin{cases} \begin{vmatrix} I_L(x_i)-I_R(y_i)\end{vmatrix}, & \text {\begin{vmatrix} I_L(x_i)-I_R(y_i)\end{vmatrix}T} \end{cases}
这就是在参数设置中阈值的作用,在视差图中经常有黑色区域,就是和阈值的设置有关。
代价聚合(Cost Aggregation)
通常全局算法不需要代价聚合,而局部算法需要通过求和、求均值或其他方法对一个支持窗口内的匹配代价进行聚合而得到参考图像上一点p在视差d处的累积代价CA(p,d),这一过程称为代价聚合。通过匹配代价聚合,可以降低异常点的影响,提高信噪比(SNR,Signal Noise Ratio)进而提高匹配精度。代价聚合策略通常是局部匹配算法的核心,策略的好坏直接关系到最终视差图(Disparity maps)的质量。
代价聚合的根本目的是让代价值能够准确的反映像素之间的相关性。上一步匹配代价的计算往往只会考虑局部信息,通过两个像素邻域内一定大小的窗口内的像素信息来计算代价值,这很容易受到影像噪声的影响,而且当影像处于弱纹理或重复纹理区域,这个代价值极有可能无法准确的反映像素之间的相关性,直接表现就是真实同名点的代价值非最小。
视差图计算(Disparity Map Computation):
深度信息可以通过计算一幅图像和其它图像的特征位置的像素差获得。视差图和深度图很像,因为视差大的像素离摄像机近,而视差小的像素离摄像机远。按以米为单位来计算摄像机距物体多远需要额外的计算。
计算视差图的标准方法是用简单的块匹配(Block Matching)。我们选择右边图像中的一块小区域,并在左边图像中搜索匹配最近的像素区域。同理,当搜索右边图像时,我们从和左边图像的模板相同的坐标处开始,向左和向右搜索至最大距离。视差为右边图像的小区域和左边图像的最近匹配区域的中心像素的水平距离。
归一化相关性(normalization cross-correlation),用于归一化待匹配目标之间的相关程度,注意这里比较的是原始像素。通过在待匹配像素位置p(px,py)构建3*3邻域匹配窗口,与目标像素位置p’(px+d,py)同样构建邻域匹配窗口的方式建立目标函数来对匹配窗口进行度量相关性,注意这里构建相关窗口的前提是两帧图像之间已经校正到水平位置,即光心处于同一水平线上,此时极线是水平的,否则匹配过程只能在倾斜的极线方向上完成,这将消耗更多的计算资源。

二、实验分析
NCC 扫平面法重建的视差图
原图:

实验结果:

- wid = 3

2. wid = 5

-
wid = 7

-
wid = 9

-
wid = 11

-
wid = 13

小结
- 颜色较亮的像素离摄像机近,而颜色较暗的像素离摄像机远。
- 当窗口值较小时,结果图的点就越密集,噪声较多。
- 细节的效果不是特别好。
三、总结
- 从上述实验结果的分析可以得出,当wid = 9时,实验结果较为理想。
- 视差大的像素离摄像机近,而视差小的像素离摄像机远;即:视差越大,其灰度值也就越大,在视差图像的视觉效果上表现出来就是图像越亮,其视差越小,灰度值也越小,视差图像也就越暗。
- 当窗口值较小时,细节体现得较多,窗口值较大时,整体的轮廓会更明显,此时一些细节则不能被体现。
- 窗口值过小时,匹配代价区分度过低,在低纹理区域容易出现误匹配,匹配精度较低;随着窗口值增大,匹配区分度逐渐清晰,误匹配区域得到矫正,匹配精度随着窗口值增大而变高。但当窗口值过大时,在深度区域容易出现误匹配。因此窗口值的大小应适中,不宜过大也不宜过小。
- 与标准版本相比,高斯版本具有较少的噪声,但缺少很多细节信息。
四、实验代码
import stereo
import scipy.misc
from PIL import Image
from pylab import *
from scipy.ndimage import *
def plane_sweep_ncc(im_l,im_r,start,steps,wid):
#使用归一化的互相关计算视差图像 """
m,n = im_l.shape
# 保存不同求和值的数组
mean_l = zeros((m,n))
mean_r = zeros((m,n))
s = zeros((m,n))
s_l = zeros((m,n))
s_r = zeros((m,n))
# 保存深度平面的数组
dmaps = zeros((m,n,steps))
# 计算图像块的平均值
filters.uniform_filter(im_l,wid,mean_l)
filters.uniform_filter(im_r,wid,mean_r)
# 归一化图像
norm_l = im_l - mean_l
norm_r = im_r - mean_r
# 尝试不同的视差
for displ in range(steps):
# 将左边图像移动到右边,计算加和
filters.uniform_filter(roll(norm_l,-displ-start)*norm_r,wid,s) # 和归一化
filters.uniform_filter(roll(norm_l,-displ-start)*roll(norm_l,-displ-start),wid,s_l)
filters.uniform_filter(norm_r*norm_r,wid,s_r) # 和反归一化
# 保存 ncc 的分数
dmaps[:,:,displ] = s/sqrt(s_l*s_r)
# 为每个像素选取最佳深度
return argmax(dmaps,axis=2)
im_l = array(Image.open('C:/Users/Desktop/im1.ppm').convert('L'),'f')
im_r = array(Image.open('C:/Users/Desktop/im2.ppm').convert('L'),'f')
# 开始偏移,并设置步长
steps = 50
start = 4
# ncc 的宽度
wid = 13
res = stereo.plane_sweep_ncc(im_l,im_r,start,steps,wid)
imsave('depth.png',res)
python

