(1)采集图像:通过标定好的双目相机采集图像,当然也可以用两个单目相机来组合成双目相机。
(2)极线校正:校正的目的是使两帧图像极线处于水平方向,或者说是使两帧图像的光心处于同一水平线上。通过校正极线可以方便后续的NCC操作。
(3)特征匹配:右视图中与左视图待测像素同一水平线上相关性最高的即为最优匹配。完成匹配后,我们需要记录其视差d即待测像素水平方向xl与匹配像素水平方向xr之间的差值d=xr−xl,最终可以得到一个与原始图像尺寸相同的视差图D。
(4)深度恢复:通过上述匹配结果得到的视差图D,可以利用相似三角形反推出以左视图为参考系的深度图。计算原理如下图所示:
# -*- 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'C:\image\im3.png').convert('L'), 'f')
im_r = array(Image.open(r'C:\image\im4.png').convert('L'),'f')
# 开始偏移,并设置步长
steps = 40
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()
1、匹配窗口较小时会出现很多不连续的点,误匹配较多;而窗口较大时,图像边缘特征变得很模糊。在该实验中我们关注较多的是深度图中目标的位置特征,而对其边缘特征要求不是很精确,所以9x9的窗口已经可以满足要求。
2、从不同窗口大小运行得到的结果对比可以得出:当窗口越小,得到的视差图中的细节越多但存在的噪声也越多。然而随着窗口逐渐变大,所得到的视差图稳健性越高,细节越少。
3、对比在图像中轮廓明显和不明显的物品:在窗口较小时,对图像中平滑的物体的位置处理较粗糙,视差图中该种物体的位置有较多亮点且分辨不出大致形状,比如说图像中左边部分的两种画。但轮廓较明显的物体的边缘部分,比如说图像中的桌子以及玩偶,它们的形状轮廓有大致的体现。
从上述两幅视差图对比可知道,当步长越大时,视差图中的细节表现得越少但稳健性较高;当步长越小时,视差图中的细节较多且明显但稳健性低