计算机视觉--立体视觉

文章目录

      • 1、立体视觉
        • 1.1 固定窗口的视差图计算
        • 1.2 NCC算法
      • 2、实验过程
        • 2.1 实验结果展示
          • 2.1.1 实验数据
          • 2.1.2 不同窗口值下的匹配结果
        • 2.2 小结
        • 2.3 源代码

1、立体视觉

1.1 固定窗口的视差图计算

原理:
深度信息可以通过计算1幅图像和其它图像的特征位置的像素差获得。视差图和深度图很像,因为视差大的像素离摄像机近,而视差小的像素离摄像机远。按以米为单位来计算摄像机距物体多远需要额外的计算。
计算视差图的标准方法是用简单的块匹配。我们选择右边图像中的1块小区域,并在左边图像中搜索匹配最近的像素区域。同理,当搜索右边图像时,我们从和左边图像的模板相同的坐标处开始,向左和向右搜索至最大距离。视差为右边图像的小区域和左边图像的最近匹配区域的中心像素的水平距离。
视差图计算的步骤:
1、块比较
寻找“最近匹配块”,简单的方法叫差的绝对值的和(SAD)。在计算深度图之前,先将两幅图像转换为灰度图像(像素值为0到255)。
2、图像修正
注意到我们仅在水平方向而没在垂直方向上搜索匹配块。这里用到的图像都是已修正的,左图的特征将会在右图同一像素行上。
3、搜索范围和方向
块匹配算法要求我们指定从模板位置器我们想搜索多远,这应该基于希望在图像中找到的最大视差。
4、模板大小
更大的模板产生的深度图噪声小,然而计算代价高。模板太大会丢失物体边缘上的细节。
5、图像边缘上的模板形状
裁剪模板至最大。默认模板大小为7x7个像素。但对于左上角(行1,列1),我们不能包含填满模板,所以只用44的模板。对2行1列的像素,我们用54的模板。块大小同理。
6、子像素估计
块匹配计算得到的视差值为整数,对应像素偏移。如果可能在最近匹配块和它的邻居间插入来微调视差值至“子像素”位置。之前我们仅用最小代价的位置作为视差,但现在我们考虑最小代价和两个相邻代价值。我们用这3个值拟合抛物线,并解析抛物线的最小值来获得子像素的位置。即抛物线的横轴为像素横坐标,纵轴为代价,代价最低的点应该是抛物线的极点。实际计算得到的极点是估计值。
7、平滑和图像金字塔
通过考虑相邻像素的视差来提高视差图的精度。采用动态规划。图像金字塔来加速块匹配的过程。它涉及到对图像下采样来来在粗糙尺度上快速搜索,然后在更细尺度上提精搜索。

1.2 NCC算法

原理:
归一化相关性,简称NCC。就是用于归一化待匹配目标之间的相关程度,注意这里比较的是原始像素。通过在待匹配像素位置p(px,py)构建33邻域匹配窗口,与目标像素位置p’(px+d,py)同样构建邻域匹配窗口的方式建立目标函数来对匹配窗口进行度量相关性,注意这里构建相关窗口的前提是两帧图像之间已经校正到水平位置,即光心处于同一水平线上,此时极线是水平的,否则匹配过程只能在倾斜的极线方向上完成,这将消耗更多的计算资源。相关程度的度量方式由如下式子定义:
计算机视觉--立体视觉_第1张图片
其中p点表示图像I1待匹配像素坐标(px,py),d表示在图像I2被查询像素位置在水平方向上与px的距离。如下图所示:
计算机视觉--立体视觉_第2张图片
左边为图像I1,右边为图像I2。图像I1,蓝色方框表示待匹配像素坐标(px,py),图像I2蓝色方框表示坐标位置为(px,py),红色方框表示坐标位置(px+d,py)。
Wp表示以待匹配像素坐标为中心的匹配窗口,通常为3
3匹配窗口。
没有上划线的I1表示匹配窗口中某个像素位置的像素值,带上划线的I1表示匹配窗口所有像素的均值。I2同理。
上述公式表示度量两个匹配窗口之间的相关性,通过归一化将匹配结果限制在 [-1,1]的范围内,可以非常方便得到判断匹配窗口相关程度:
若NCC = -1,则表示两个匹配窗口完全不相关,相反,若NCC = 1时,表示两个匹配窗口相关程度非常高。
双目立体匹配流程如下:

  • 采集图像:通过标定好的双目相机采集图像,当然也可以用两个单目相机来组合成双目相机。
  • 极线校正:校正的目的是使两帧图像极线处于水平方向,或者说是使两帧图像的光心处于同一水平线上。通过校正极线可以方便后续的NCCNCCNCC操作。
    1)由标定得到的内参中畸变信息中可以对图像去除畸变。
    2)通过校正函数校正以后得到相机的矫正变换R和新的投影矩阵P,接下来是要对左右视图进行去畸变,并得到重映射矩阵。
  • 特征匹配:NCC做匹配的步骤啦,匹配方法如上所述,右视图中与左视图待测像素同一水平线上相关性最高的即为最优匹配。完成匹配后,我们需要记录其视差d,即待测像素水平方向xl与匹配像素水平方向xr之间的差值d = xr - xl,最终我们可以得到一个与原始图像尺寸相同的视差图D。
  • 深度恢复:通过上述匹配结果得到的视差图DDD,我们可以很简单的利用相似三角形反推出以左视图为参考系的深度图。计算原理如下图所示:
    计算机视觉--立体视觉_第3张图片
    如图,Tx为双目相机基线,f为相机焦距,这些可以通过相机标定步骤得到。而xr - xl就是视差d。通过公式 z = f * Tx / d可以很简单地得到以左视图为参考系的深度图了。

2、实验过程

2.1 实验结果展示

2.1.1 实验数据

左图:
计算机视觉--立体视觉_第4张图片
右图:
计算机视觉--立体视觉_第5张图片

2.1.2 不同窗口值下的匹配结果

窗口值为3:
计算机视觉--立体视觉_第6张图片
由上图可看出,窗口值为3的时候,基本可以看出雕塑、台灯、雕塑后面的摄像机、书桌上的物品、书架的大致轮廓,而书桌的轮廓却不太清晰,只能看出一点模模糊糊的轮廓,四周边角的视觉匹配效果也不太理想,可能是因为书桌部分地方亮度比较暗导致的。

窗口值为7:
计算机视觉--立体视觉_第7张图片
由上图可看出,窗口值为7的时候,雕塑、台灯、书桌上的物品、雕塑后面的摄像机的轮廓都变得更清晰了,书桌的轮廓也显露了出来。相比窗口值为3的时候的视觉匹配,窗口值为7的时候书架的轮廓反而变得不清晰了,但还是能看出一点点轮廓。

窗口值为11:
计算机视觉--立体视觉_第8张图片
由上图可看出,窗口值为11的时候,雕塑、书桌、书桌上的物品的大致轮廓依旧清晰,相比窗口值为7的时候的视觉匹配,窗口值为11的时候台灯、雕塑后面的摄像机的轮廓开始变得模糊,书架的轮廓更是完全看不见了。

2.2 小结

  • 由上图比较可看出,窗口值越大,部分物品的轮廓变得清晰(上图中的雕塑、台灯、书桌等),部分物品的轮廓反而越来越模糊(上图中的书架)。视觉匹配的效果可能会受亮度(书桌部分地方存在阴影、四周部分地方较暗导致轮廓不清晰,视觉匹配效果不佳),颜色(摄像机颜色较深导致窗口较小时轮廓不清晰)等因素的影响。
  • 窗口值越大,匹配点的数值越高,图像越清晰,但也不是窗口值越大越好,窗口值过大也会导致匹配点的数值减少,轮廓变得模糊。

2.3 源代码

# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
import cv2
from numpy import *
from numpy.ma import array
from scipy.ndimage import filters
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(np.roll(norm_l, -displ - start) * norm_r, wid, s) # 和归一化
        filters.uniform_filter(np.roll(norm_l, -displ - start) * np.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 np.argmax(dmaps, axis=2)


im_l = array(Image.open(r'C:\Users\mangowu\Desktop\test\scene1.row3.col3.ppm').convert('L'),'f')
im_r = array(Image.open(r'C:\Users\mangowu\Desktop\test\scene1.row3.col4.ppm').convert('L'),'f')
# 开始偏移,并设置步长
steps = 12
start = 4
# ncc 的宽度
wid = 9
res = plane_sweep_ncc(im_l,im_r,start,steps,wid)
import scipy.misc
scipy.misc.imsave('C:/Users/mangowu/Desktop/test/3.png',res)
show()

你可能感兴趣的:(计算机视觉--立体视觉)