计算视觉——视差计算

  • 背景介绍

立体匹配也称作视差估计(disparity estimation),或者双目深度估计。其输入是一对在同一时刻捕捉到的,经过极线校正的左右图像 [公式] 和 [公式] 。而它的输出是由参考图像(一般以左图作为参考图像)中每个像素对应的视差值所构成的视差图 d。视差是三维场景中某一点在左右图像中对应点位置的像素级差距。当给定摄像机的基线距离 b 和焦距 f 之后,我们就可以从视差图中自动计算出深度 [公式] , [公式] 。所以深度和视差是可以互相转换,相互等价的。

立体匹配算法分为四个步骤:

  • 匹配代价计算(matching cost computation)
  • 代价聚合(cost aggregation)
  • 视差计算(disparity computation)
  • 视差精修(disparity refinement)

传统的视差估计算法主要分为两类:

  • 局部算法:主要基于滑动窗口来计算局部窗口内的匹配代价;
  • 全局算法:通过优化包括局部数据项和平滑项的能量函数来计算立体视图之间的相关性;

传统的视差估计算法对于各种应用场景都具有等价的视差估计能力,不会因为场景变化而产生较大的差异,因此有论文将传统方法估计的视差图作为带有噪声的标签来提升无监督视差估计的性能,本文后面会提到。随着深度学习的发展以及大规模合成/仿真数据的推动,CNN将上述四个步骤统一成一个端到端的网络,进一步提升了视差估计的性能。本文主要探讨的是自监督学习在基于卷积神经网络的视差估计算法中的应用情况。

  • NCC视差匹配方法

对于原始的图像内任意一个像素点(px,py) (p_x,p_y)(p x​ ,p y)构建一个n×n n\times nn×n的邻域作为匹配窗口。然后对于目标相素位置(px+d,py) (p_x+d, p_y)(p x+d,p y)同样构建一个n×n n\times nn×n大小的匹配窗口,对两个窗口进行相似度度量,注意这里的d dd有一个取值范围。对于两幅图像来说,在进行NCC NCCNCC计算之前要对图像处理,也就是将两帧图像校正到水平位置,即光心处于同一水平线上,此时极线是水平的,否则匹配过程只能在倾斜的极线方向上完成,这将消耗更多的计算资源。

NCC计算公式:

 

 

 其中NCC(P, d)得到的值得范围将在[-1, 1]之间。
Wp为之前提到的匹配窗口。
I(2, y)为原始图像的像素值。
Ii (PI, Py)为原始窗口内像素的均值。
I2(x + d, y)为原始图像在目标图像上对应点位置在方向上偏移d后的像素值。
2(P:+ d, Py)为目标图像匹配窗口像素均值。
.若NCC= -1,则表示两个匹配窗口完全不相关,相反,若NCC= 1时,表示两个匹配窗口相关程度非常高。

  • 代码

 

# -*- 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)

def plane_sweep_gauss(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.gaussian_filter(im_l,wid,0,mean_l)
 filters.gaussian_filter(im_r,wid,0,mean_r)
 # 归一化图像
 norm_l = im_l - mean_l
 norm_r = im_r - mean_r
 # 尝试不同的视差
 for displ in range(steps):
     # 将左边图像移动到右边,计算加和
     filters.gaussian_filter(np.roll(norm_l, -displ - start) * norm_r, wid, 0, s) # 和归一化
     filters.gaussian_filter(np.roll(norm_l, -displ - start) * np.roll(norm_l, -displ - start), wid, 0, s_l)
     filters.gaussian_filter(norm_r*norm_r,wid,0,s_r) # 和反归一化
     # 保存 ncc 的分数
     dmaps[:,:,displ] = s / np.sqrt(s_l * s_r)
 # 为每个像素选取最佳深度
 return np.argmax(dmaps, axis=2)

im_l = array(Image.open(r'jia/1.jpg').convert('L'), 'f')
im_r = array(Image.open(r'jia/2.jpg').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('depth.png',res)
show()

 

  • 实验结果及分析

当wid=2时,运行结果如下:

 

 

当wid=9时,运行结果:

 

 

wid=15时,运行结果如下:

 

 

可以看到当wid值较小的时候台灯的两根支架的细节信息是很丰富的,虽然当wid=2时整张图像很杂乱,无法抓住重点,截取出人头及脖子部分的部分可以看到其细节是很丰富的。

由于wid值影响了滤波结果,滤波结果影响了NCC的匹配度的计算。可以分析:当wid值较小,滤波结果仅仅只受自身和周围较少像素的影响,所以就会保留更多自身的特征性在,进行NCC的匹配计算视差的时候细节信息就会更丰富一些,但也可以看到当wid值较小的时候视差图是很杂乱的,无法直接观察出视差的区别。;在wid值较大的时候,可以考虑到周围像素的影响,可以使自身和周围像素更好地融合,得到的视差图的轮廓信息较为明显,易观察。

 

 

 

以上实验结果是两组图像分别实现均匀滤波器计算视差和高斯滤波器计算视差的方法,可以看出:
与均值滤波版本相比,高斯滤波版本具有较少的噪声,但缺少很多细节信息。 对于第一组图像来说均匀滤波器计算出的视差图较为容易观察一些,而对于第二组图像来说其均匀滤波器计算出的视差图太过杂乱,使用高斯滤波器计算的视差图较为平滑,减少了均匀滤波器的杂乱感更容易观察一些。
分析原因如下:
均匀滤波器给定正方形图像块中所有像素相同的权值,所以可以观察到使用均匀滤波器得到的视差图没有那么平滑。而高斯滤波器高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到,所以而后使用高斯滤波器替换均匀滤波器,可以看到产生了更加平滑视差图。

  • 总结

1.运行的结果与图片的质量有着相当大的关系,大幅度的图片运行时间久,而且得到的结果往往很模糊,尽量选择幅度较小的图片比较好

2.基于NCC用来比较两幅图像的相似程度可以有效降低光照对图像比较结果的影响,而且NCC最终结果在0到1之间,所以特别容易量化比较结果,只要给出一个阈值就可以判断结果的好与坏。但是NCC比较耗时,虽然可以通过调整窗口大小和每次检测的步长矩形部分优化,但是运行速度实在是太慢了。

3.当窗口值越小时,匹配出的图像的点就越密集,像素点就越密集。有轮廓的地方,颜色就越黑,应该是因为有轮廓的区域或者很黑的的区域与与原模板相同位置的反差越小,反之,颜色越白的区域白表示周围跟模板相同位置反差越大。

 

posted @ 2020-04-26 17:31  zzb1234  阅读(3048)  评论(0编辑  收藏  举报