计算视差

文章目录

  • 计算视差
    • NCC原理
    • 双目立体匹配的步骤
    • 实验
      • 目的
      • 给定图片
      • 实验代码
      • NCC 视差匹配结果
      • 更改窗口值进行多组实验
      • 实验小结

计算视差

NCC原理

归一化相关性,normalization cross-correlation,因此简称NCC,下文中笔者将用NCC来代替这冗长的名称。

NCC,顾名思义,就是用于归一化待匹配目标之间的相关程度,注意这里比较的是原始像素。通过在待匹配像素位置p(px,py)构建3*3邻域匹配窗口,与目标像素位置p’(px+d,py)同样构建邻域匹配窗口的方式建立目标函数来对匹配窗口进行度量相关性,注意这里构建相关窗口的前提是两帧图像之间已经校正到水平位置,即光心处于同一水平线上,此时极线是水平的,否则匹配过程只能在倾斜的极线方向上完成,这将消耗更多的计算资源。相关程度的度量方式由如下式子定义:
  在这里插入图片描述
  上式中的变量需要解释一下:其中p点表示图像I1待匹配像素坐标(px,py),d表示在图像I2被查询像素位置在水平方向上与px的距离。如下图所示:

计算视差_第1张图片
  左边为图像I1,右边为图像I2。图像I1,蓝色方框表示待匹配像素坐标(px,py),图像I2蓝色方框表示坐标位置为(px,py),红色方框表示坐标位置(px+d,py)。(由于画图水平有限,只能文字和图片双重说明来完成了~)
  
  Wp表示以待匹配像素坐标为中心的匹配窗口,通常为3*3匹配窗口。
  
  没有上划线的I1表示匹配窗口中某个像素位置的像素值,带上划线的I1表示匹配窗口所有像素的均值。I2同理。
  
  上述公式表示度量两个匹配窗口之间的相关性,通过归一化将匹配结果限制在 [-1,1]的范围内,可以非常方便得到判断匹配窗口相关程度:

若NCC = -1,则表示两个匹配窗口完全不相关,相反,若NCC = 1时,表示两个匹配窗口相关程度非常高。

我们很自然的可以想到,如果同一个相机连续拍摄两张图像(注意,此时相机没有旋转也没有位移,此外光照没有明显变化,因为基于原始像素的匹配方法通常对上述条件是不具备不变性的),其中有一个位置是重复出现在两帧图像中的。比如桌子上的一个可乐瓶。那么我们就可以对这个可乐瓶的位置做一下匹配。直观的看,第一帧中可乐瓶上某一个点,它所构成邻域窗口按理说应该是与第二帧相同的,就算不完全相同,也应该是具有非常高相关性的。

双目立体匹配的步骤

1、采集图像:通过标定好的双目相机采集图像,当然也可以用两个单目相机来组合成双目相机。

2、极线校正:校正的目的是使两帧图像极线处于水平方向,或者说是使两帧图像的光心处于同一水平线上。通过校正极线可以方便后续的NCC操作。
  2.1、由标定得到的内参中畸变信息中可以对图像去除畸变
  
  2.2、通过校正函数校正以后得到相机的矫正变换R和新的投影矩阵P,接下来是要对左右视图进行去畸变,并得到重映射矩阵
  
  2.3、根据上述得到的重映射参数map1,map2,需要进一步对原始图像进行重映射到新的平面中才能去除图像畸变,同样,实现方式仍是使用现有的OpenCV函数
  
  2.4、通过上述两步操作,成功地对图像去除了畸变,并且校正了图像极线。注意,在立体校正阶段需要设置alpha = 0才能完成对图像的裁剪,否则会有黑边。

3、特征匹配:匹配方法如上所述,右视图中与左视图待测像素同一水平线上相关性最高的即为最优匹配。完成匹配后,需要记录其视差d,即待测像素水平方向xl与匹配像素水平方向xr之间的差值d = xr - xl,最终可以得到一个与原始图像尺寸相同的视差图D。

4、深度恢复:通过上述匹配结果得到的视差图D,可以很简单的利用相似三角形反推出以左视图为参考系的深度图。

实验

目的

1、实现NCC 视差匹配方法,即给定左右两张视图,根据NCC计算视差图

2、分析不同窗口值对匹配结果的影响,重点考查那些点(或者哪些类型的点)在不同窗口大小下的匹配精度影响

给定图片

计算视差_第2张图片
计算视差_第3张图片
计算视差_第4张图片

实验代码

stereo.py

import numpy as np
from scipy.ndimage import filters
def plane_sweep_ncc(im_l,im_r,start,steps,wid):
	""" 使用归一化的互相关计算视差图像 """
	m,n = im_l.shape
	# 保存不同求和值的数组
	mean_l = np.zeros((m,n))
	mean_r = np.zeros((m,n))
	s = np.zeros((m,n))
	s_l = np.zeros((m,n))
	s_r = np.zeros((m,n))
	# 保存深度平面的数组
	dmaps = np.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/np.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 = np.zeros((m,n))
	mean_r = np.zeros((m,n))
	s = np.zeros((m,n))
	s_l = np.zeros((m,n))
	s_r = np.zeros((m,n))
	# 保存深度平面的数组
	dmaps = np.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)

main.py

import stereo
import numpy as np
from PIL import Image
import imageio
im_l = np.array(Image.open('C:/Users/Artor/PycharmProjects/PCV_1/data1/1.jpg').convert('L'),'f')
im_r = np.array(Image.open('C:/Users/Artor/PycharmProjects/PCV_1/data1/2.jpg').convert('L'),'f')
# 开始偏移,并设置步长
steps = 12
start = 4
# ncc 的宽度
wid = 9
res = stereo.plane_sweep_ncc(im_l,im_r,start,steps,wid)
imageio.imsave('data1/depth1.png',res)

NCC 视差匹配结果

计算视差_第5张图片

更改窗口值进行多组实验

1、窗口值为50
计算视差_第6张图片

2、窗口值为30
计算视差_第7张图片

3、窗口值为20
计算视差_第8张图片

4、窗口值为15
计算视差_第9张图片

5、窗口值为9
计算视差_第10张图片
6、窗口值为6
计算视差_第11张图片
7、窗口值为3
计算视差_第12张图片

实验小结

窗口值越小,图像中物体轮廓更清晰,但同时细节点会减少,匹配代价区分度过低,匹配精度越低

窗口值越大,细节点越多,但同时噪点也会更多,匹配区分度逐渐清晰,但过大时任意出现错误匹配

所以窗口值不宜过大或过小,适中即可

在不同窗口大小下的匹配精度影响:
可以发现,物体边界点在不同窗口大小下的匹配精度影响较大,

你可能感兴趣的:(计算机视觉,计算机视觉,python)