一般来说,通过立体视觉获得深度图需要校准,矫正,立体匹配,三角化四个过程。
图中红实线和绿实线分别是左右拍摄的极线,极线约束指的是左图极线(红实线)上的点,只能映射到右图极线(绿实线)上。
找对应匹配点的下一步工作就是要去寻找在右图中他可能存在的那条线极线了。
如果能将左右摄完美对齐,且他们的内参(焦距等)完全一致,就可将左右摄像头的极线校正成行相同的平行线。因此,左图上任意一点,在右图中只能映射到与其对应的相同行上,即两点行坐标V相同。这样就完美解决了寻找极线的问题。3
B Z = p p ′ Z − f = B − ( X R − W 2 ) − ( W 2 − X T ) Z − f = B + X T − X R Z − f \frac{B}{Z}=\frac{pp'}{Z-f}=\frac{B-(X_R-\frac{W}{2})-(\frac{W}{2}-X_T)}{Z-f}=\frac{B+X_T-X_R}{Z-f} ZB=Z−fpp′=Z−fB−(XR−2W)−(2W−XT)=Z−fB+XT−XR
B ∗ f X R − X T = B ∗ f d \frac{B*f}{X_R-X_T}=\frac{B*f}{d} XR−XTB∗f=dB∗f
由上述公式发现在B, f不变的情况下,Z越大,d越小,即越远视差越小。f, Z不变的情况下,B越大,d越大。这其实意味着基线越大,看的越远。
目前立体匹配算法是计算机视觉中的一个难点和热点,算法很多,但是一般的步骤是:
①匹配代价计算
匹配代价计算是整个立体匹配算法的基础,实际是对不同视差下进行灰度相似性测量。常见的方法有灰度差的平方SD(squared intensity differences),灰度差的绝对值AD(absolute intensity differences)等。另外,在求原始匹配代价时可以设定一个上限值,来减弱叠加过程中的误匹配的影响。以AD法求匹配代价为例,可用下式进行计算,其中T为设定的阈值。
C ( x t , y t ) C(x_t,y_t) C(xt,yt)=
∣ I L ∣ ( x t ) − ∣ I R ( y t ) ∣ , ∣ I L ∣ ( x t ) − ∣ I R ( y t ) ∣ < T |I_L|(x_t)-|I_R(y_t)|, |I_L|(x_t)-|I_R(y_t)|
T , ∣ I L ∣ ( x t ) − ∣ I R ( y t ) ∣ > T T,|I_L|(x_t)-|I_R(y_t)|>T T,∣IL∣(xt)−∣IR(yt)∣>T
②匹配代码叠加
一般来说,全局算法基于原始匹配代价进行后续算法计算。而区域算法则需要通过窗口叠加来增强匹配代价的可靠性,根据原始匹配代价不同,可分为:
sum of Absolute differences(SAD):
C ( x , y , d ) = ∑ x ∈ S ∣ I R ( x , y ) − I ( x + d ) , y ∣ C(x,y,d)=\sum_{x∈S}^{}|I_R(x,y)-I_(x+d),y| C(x,y,d)=∑x∈S∣IR(x,y)−I(x+d),y∣
sum of Squared differences(SSD):
C ( x , y , d ) = ∑ x ∈ S ∣ I R ( x , y ) − I ( x + d ) , y ∣ 2 C(x,y,d)=\sum_{x∈S}^{}|I_R(x,y)-I_(x+d),y|^{2} C(x,y,d)=∑x∈S∣IR(x,y)−I(x+d),y∣2
sum of truncated absolute differences(STAD):
C(x,y,d)=min{ ∑ x ∈ S ∣ I R ( x , y ) − I ( x + d ) , y ∣ , T \sum_{x∈S}^{}|I_R(x,y)-I_(x+d),y|,T ∑x∈S∣IR(x,y)−I(x+d),y∣,T}
③视差获取
对于区域算法来说,在完成匹配代价的叠加以后,只需在一定范围内选取叠加匹配代价最优的点(SAD和SSD取最小值,NCC取最大值)作为对应匹配点。
n c c ( I 1 , I 2 ) = ∑ x ( I 1 ( x ) − u 1 ) ( I 2 ( x ) − u 2 ) ∑ x ( I 1 ( x ) − u 1 ) 2 ∑ x ( I 2 ( x ) − u 2 ) 2 ncc(I_1,I_2)=\frac{\sum_{x}^{}(I_1(x)-u_1)(I_2(x)-u_2)}{\sqrt{\sum_{x}^{}(I_1(x)-u_1)^{2}\sum_{x}^{}(I_2(x)-u_2)^{2}}} ncc(I1,I2)=∑x(I1(x)−u1)2∑x(I2(x)−u2)2∑x(I1(x)−u1)(I2(x)−u2)
④视差细化
大多数立体匹配算法计算出来的视差都是一些离散的特定整数值,可满足一般应用的精度要求。但在一些精度要求比较高的场合,如精确的三维重构中,就需要在初始视差获取后采用一些措施对视差进行细化,如匹配代价的曲线拟合、图像滤波、图像分割等。
分析:物体越近,视差越大,结果区域越明亮;相反,物体越远视差越小,结果区域越暗沉
②不同窗口值对匹配结果的影响
取①中的数据二。
wid=3:
wid=5:
wid=7:
wid=9:
wid=11:
分析:
(1)窗口值较小时,在弱纹理区域,窗口内像素值相似,相邻区域的相似度函数值差异不显著。窗口包含的纹理区域太小,区分度不足。在重复纹理区域内像素值接近。这些影响都容易产生导致结果产生错误。
(2)窗口值较大时,由于立体匹配中存在遮挡问题,在边缘处背景容易被错分成前景,造成前景放大。
(3)随着窗口值的增大,结果逐渐变得清晰,匹配精度变高。尤其是从3到9的过程极为明显,wid=9和wid=11的差距较小。根据实验结果可以发现wid = 9是比较适合的窗口值。
stereo.py:
from numpy import *
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(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)
ncc.py:
import stereo
import scipy.misc
from PIL import Image
from pylab import *
im_l = array(Image.open('D:/zq/scene1.row3.col3.ppm').convert('L'),'f')
im_r = array(Image.open('D:/zq/scene1.row3.col4.ppm').convert('L'),'f')
# 开始偏移,并设置步长
steps = 12
start = 4
# ncc 的宽度
wid = 9
res = stereo.plane_sweep_ncc(im_l,im_r,start,steps,wid)
imsave('depth.png',res)
问题1:
这个问题说明此处需要缩进,只需在出现错误的那一行,按空格或Tab(但不能混用)键缩进即可。
问题2:
这个问题好像是spicy的版本问题。可以选择降低版本来解决,但是尝试了一下直接使用imsave函数发现也可以输出结果。
问题3:
这个问题一开始一直解决不了,百度也没有得到答案。后来觉得可能是自己加的定义语句中的from array import array这句的问题。查找了以前写过的有使用array的代码,将这句语句替换成from PIL import*即可。
1.立体匹配技术被普遍认为是立体视觉中最困难也是最关键的问题,主要有以下因素的影响: 光学失真和噪声(亮度、色调、饱和度等失衡),平滑表面的镜面反射,投影缩减,透视失真,低纹理,重复纹理,透明物体,重叠和非连续。
2.大尺寸窗口有利于解决弱纹理,孔径问题,重复纹理。小尺寸窗口利于解决前景放大问题。