【python计算机视觉编程——5.多视图几何】

python计算机视觉编程——5.多视图几何

  • 5.多视图几何
    • 5.1 外极几何
      • 5.1.2 用Matplotlib绘制三维数据
      • 5.1.3 计算F:八点法
      • 5.1.4 外极点和外极线
    • 5.2 照相机和三维结构的计算
      • 5.2.1 三角部分
      • 5.2.2 由三维点计算照相机矩阵
      • 5.2.3 由基础矩阵计算照相机矩阵
    • 5.3 多视图重建
      • 5.3.1 稳健估计基础矩阵
      • 5.3.2 三维重建示例
    • sift文件
    • homography文件
    • 5.4 立体图像

5.多视图几何

5.1 外极几何

该网站可以下载图像点、三维点和照相机参数矩阵的数据集Visual Geometry Group - University of Oxford

from PIL import Image
matplotlib.rcParams['font.family'] = 'sans-serif'
matplotlib.rcParams['font.sans-serif'] = ['SimHei']  # 黑体字体
matplotlib.rcParams['axes.unicode_minus'] =False  # 显示负号
class Camera(object):
    def __init__(self,P):
        self.P=P      #照相机矩阵
        self.K=None   #标定矩阵
        self.R=None   #旋转矩阵
        self.t=None   #平移向量
        self.c=None   #照相机中心
    def project(self,X):
        x=np.dot(self.P,X)  #得到一个包含齐次坐标的投影结果 x
        for i in range(3):
            x[i]/=x[2]  # 以实现归一化。
        return x
    def factor(self):
        K,R=linalg.rq(self.P[:,:3]) # 将照相机矩阵 P 的左上 3x3 部分分解为上三角矩阵 K 和正交矩阵 R
        
        T=diag(sign(diag(K)))  # 构造对角矩阵 T,其对角线元素为 K 对角线元素的符号。
        if linalg.det(T)<0:  # 检查 T 的行列式是否为负。如果是,则调整 T 使得行列式为正。
            T[1,1]*=-1
            self.K=dot(K,T)
            self.R=dot(T,R)
            self.t=dot(linalg.inv(self.K),self.P[:,3])  # linalg.inv(self.K)用于计算标定矩阵 K 的逆矩阵
        return self.K,self.R,self.t
    def center(self):
        if self.c is not None:
            return self.c
        else:
            self.factor()
            self.c=-dot(self.R.T,self.t)  # 将平移向量转化为相机坐标系原点在世界坐标系中的位置
            return self.c
im1=array(Image.open('images/001.jpg'))
im2=array(Image.open('images/002.jpg'))

points2D=[loadtxt('2D/00'+str(i+1)+'.corners').T for i in range(3)]

points3D=loadtxt('3D/p3d').T

corr=genfromtxt('2D/nview-corners',dtype='int')

P=[Camera(loadtxt('2D/00'+str(i+1)+'.P')) for i in range(3)]
X = vstack( (points3D, ones(points3D.shape[1])))
x = P[0].project(X)

# 在视图1中绘制点
figure(figsize=(10, 10))
subplot(121)
imshow(im1)
plot(points2D[0][0], points2D[0][1],'*')
axis('off')
title('视图 1 与图像点')
subplot(122)
imshow(im1),plot(x[0],x[1],'r.')
axis('off')
title('视图 1 与投影的三维点')
# savefig('./output/test1.jpg')
show()

在这里插入图片描述

5.1.2 用Matplotlib绘制三维数据

from mpl_toolkits.mplot3d import Axes3D
from pylab import *
import numpy as np
%matplotlib notebook
fig=figure()
# ax=fig.gca(projection="3d")
ax = fig.add_axes(Axes3D(fig))

X,Y,Z=axes3d.get_test_data(0.25)
ax.plot(X.flatten(),Y.flatten(),Z.flatten(),'o')

ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')
show()

在这里插入图片描述

%matplotlib notebook
fig=figure()
ax = fig.add_axes(Axes3D(fig))
ax.plot(points3D[0],points3D[1],points3D[2],'k.')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5.1.3 计算F:八点法

def compute_fundamental(x1, x2):
    """使用归一化的八点算法,从对应点(x1,x2 3×n的数组)中计算基础矩阵
        每行由如下构成:
        [x'*x, x'*y' x', y'*x, y'*y, y', x, y, 1]"""

    n = x1.shape[1]
    if x2.shape[1] != n:
        raise ValueError("Number of points don't match.")

    # 创建方程对应的矩阵
    A = zeros((n,9))
    for i in range(n):
        A[i] = [x1[0, i] * x2[0, i], x1[0, i] * x2[1, i], x1[0, i] * x2[2, i],
                x1[1, i] * x2[0, i], x1[1, i] * x2[1, i], x1[1, i] * x2[2, i],
                x1[2, i] * x2[0, i], x1[2, i] * x2[1, i], x1[2, i] * x2[2, i]]
    
    # 计算线性最小二乘解
    U,S,V = linalg.svd(A)
    F = V[-1].reshape(3,3)
    
    # 受限F
    # 通过将最后一个奇异值置0,使秩为2
    U,S,V = linalg.svd(F)
    S[2] = 0
    F = dot(U, dot(diag(S), V))
    
    
    return F

5.1.4 外极点和外极线

def compute_epipole(F):
    """从基础矩阵F中计算右极点(可以使用F.T获得左极点)"""

    # 返回F的零空间(Fx=0)
    U,S,V = linalg.svd(F)
    e = V[-1]
    return e/e[2]
def plot_epipolar_line(im,F,x,epipole=None,show_epipole=True):
    m,n=im.shape[:2]
    line=dot(F,x)
    t=linspace(0,n,100)
    lt=array([(line[2]+line[0]*tt)/(-line[1]) for tt in t])
    
    ndx=(lt>=0)&(lt<m)
    plot(t[ndx],lt[ndx],linewidth=2)
    
    if show_epipole:
        if epipole is None:
            epipole=compute_epipole(F)
        plot(epipole[0]/epipole[2],epipole[1]/epipole[2],'r*')
%matplotlib notebook
ndx = (corr[:,0]>=0) & (corr[:,1]>=0)

#获得坐标,并将其用齐次坐标表示
x1 = points2D[0][:,corr[ndx,0]]
x1 = vstack((x1,ones(x1.shape[1])))
x2 = points2D[1][:,corr[ndx,1]]
x2 = vstack((x2,ones(x2.shape[1])))

#计算F
F = compute_fundamental(x1,x2)

#计算极点
e = compute_epipole(F)

#绘制图像
figure()
imshow(im1)

#分别绘制每条线,这样会绘制出很漂亮的颜色
for i in range(5):
    plot_epipolar_line(im1,F,x2[:,i],e)
axis('off')
savefig('plot_epipolar_line.jpg')


figure()
imshow(im2)

#分别绘制每个点,这样绘制出和线同样的颜色
for i in range(5):
    plot(x2[0,i],x2[1,i],'o')
axis('off')
show()

在这里插入图片描述

在这里插入图片描述

5.2 照相机和三维结构的计算

5.2.1 三角部分

from mpl_toolkits.mplot3d import Axes3D
from pylab import *
from PIL import Image
matplotlib.rcParams['font.family'] = 'sans-serif'
matplotlib.rcParams['font.sans-serif'] = ['SimHei']  # 黑体字体
matplotlib.rcParams['axes.unicode_minus'] =False  # 显示负号
import os
def triangulate_point(x1,x2,P1,P2):
    M=zeros((6,6))
    M[:3,:4]=P1
    M[3:,:4]=P2
    M[:3,4]=-x1
    M[3:,5]=-x2
    
    U,S,V=linalg.svd(M)
    X=V[-1,:4]
    return X/X[3]
def triangulate(x1,x2,P1,P2):
    
    n=x1.shape[1]
    if x2.shape[1]!=n:
        raise ValueError("Number of points don`t match.")
    X=[triangulate_point(x1[:,i],x2[:,i],P1,P2) for i in range(n)]
    return array(X).T

这里还需要用到之前的Camera类

class Camera(object):
    def __init__(self,P):
        self.P=P      #照相机矩阵
        self.K=None   #标定矩阵
        self.R=None   #旋转矩阵
        self.t=None   #平移向量
        self.c=None   #照相机中心
    def project(self,X):
        x=np.dot(self.P,X)  #得到一个包含齐次坐标的投影结果 x
        for i in range(3):
            x[i]/=x[2]  # 以实现归一化。
        return x
    def factor(self):
        K,R=linalg.rq(self.P[:,:3]) # 将照相机矩阵 P 的左上 3x3 部分分解为上三角矩阵 K 和正交矩阵 R
        
        T=diag(sign(diag(K)))  # 构造对角矩阵 T,其对角线元素为 K 对角线元素的符号。
        if linalg.det(T)<0:  # 检查 T 的行列式是否为负。如果是,则调整 T 使得行列式为正。
            T[1,1]*=-1
            self.K=dot(K,T)
            self.R=dot(T,R)
            self.t=dot(linalg.inv(self.K),self.P[:,3])  # linalg.inv(self.K)用于计算标定矩阵 K 的逆矩阵
        return self.K,self.R,self.t
    def center(self):
        if self.c is not None:
            return self.c
        else:
            self.factor()
            self.c=-dot(self.R.T,self.t)  # 将平移向量转化为相机坐标系原点在世界坐标系中的位置
            return self.c
%matplotlib notebook

ndx = (corr[:,0]>=0) & (corr[:,1]>=0)

#获得坐标,并将其用齐次坐标表示
x1 = points2D[0][:,corr[ndx,0]]
x1 = vstack((x1,ones(x1.shape[1])))
x2 = points2D[1][:,corr[ndx,1]]
x2 = vstack((x2,ones(x2.shape[1])))

Xtrue=points3D[:,ndx]
Xtrue=vstack((Xtrue,ones(Xtrue.shape[1])))

Xest=triangulate(x1,x2,P[0].P,P[1].P)
print(Xest[:,:3])
print(Xtrue[:,:3])

fig=figure()
ax = fig.add_axes(Axes3D(fig))
ax.plot(Xest[0],Xest[1],Xest[2],'ko')
ax.plot(Xtrue[0],Xtrue[1],Xtrue[2],'r.')
axis('equal')

show()

在这里插入图片描述

在这里插入图片描述

5.2.2 由三维点计算照相机矩阵

def compute_P(x,X):
    n=x.shape[1]
    if X.shape[1]!=n:
        raise ValueError("Number of points don`t match.")
    M=zeros((3*n,12+n))
    for i in range(n):
        M[3*i,0:4]=X[:,i]
        M[3*i+1,4:8]=X[:,i]
        M[3*i+2,8:12]=X[:,i]
        M[3*i:3*i+3,i+12]=x[:,i]
    U,S,V=linalg.svd(M)
    return V[-1,:12].reshape((3,4))
corr=corr[:,0]
ndx3D=where(corr>=0)[0]
ndx2D=corr[ndx3D]

x=points2D[0][:,ndx2D]
x=vstack((x,ones(x.shape[1])))
X=points3D[:,ndx3D]
X=vstack((X,ones(X.shape[1])))

Pest=Camera(compute_P(x,X))

print(Pest.P/Pest.P[2,3])
print(P[0].P/P[0].P[2,3])

xest=Pest.project(X)

figure()
imshow(im1)
plot(x[0],x[1],'bo')
plot(xest[0],xest[1],'r.')
axis('off')

show()

在这里插入图片描述

在这里插入图片描述

5.2.3 由基础矩阵计算照相机矩阵

def compute_P_from_fundamental(F):
    e=compute_epipole(F.T)
    Te=skew(e)
    return vstack((dot(Te,F.T).T,e)).T
def skew(a):
    return array([[0,-a[2],a[1]],[a[2],0,-a[0]],[-a[1],a[0],0]])
def compute_P_from_essential(E):
    U,S,V=svd(E)
    if det(dot(U,V))<0:
        V=-V
    E=dot(U,dot(diag([1,1,0]),V))
    Z=skew([0,0,-1])
    W=array([[0,-1,0],[1,0,0],[0,0,1]])
    
    P2=[vstack((dot(U,dot(W,V)).T,U[:,2])).T,
       vstack((dot(U,dot(W,V)).T,-U[:,2])).T,
       vstack((dot(U,dot(W.T,V)).T,U[:,2])).T,
       vstack((dot(U,dot(W.T,V)).T,-U[:,2])).T]
    return P2

5.3 多视图重建

5.3.1 稳健估计基础矩阵

class RansacModel(object):
    def __init__(self,debug=False):
        self.debug=debug
    def fit(self,data):
        data=data.T
        x1=data[:3,:8]
        x2=data[3:,:8]
        
        F=compute_fundamental_normalized(x1,x2)
        return F
    def get_error(self,data,F):
        data=data.T
        x1=data[:3]
        x2=data[3:]
        Fx1=dot(F,x1)
        Fx2=dot(F,x2)
        denom=Fx1[0]**2+Fx1[1]**2+Fx2[0]**2+Fx2[1]**2
        err=(diag(dot(x1.T,dot(F,x2))))**2/denom
        return err
 def compute_fundamental_normalized(x1, x2):
    n = x1.shape[1]
    if x2.shape[1] != n:
        raise ValueError("Number of points don't match.")
    # normalize image coordinates
    x1 = x1 / x1[2]
    mean_1 = np.mean(x1[:2], axis=1)
    S1 = np.sqrt(2) / np.std(x1[:2])
    T1 = np.array([[S1, 0, -S1 * mean_1[0]], [0, S1, -S1 * mean_1[1]], [0, 0, 1]])
    x1 = np.dot(T1, x1)
    x2 = x2 / x2[2]
    mean_2 = np.mean(x2[:2], axis=1)
    S2 = np.sqrt(2) / np.std(x2[:2])
    T2 = np.array([[S2, 0, -S2 * mean_2[0]], [0, S2, -S2 * mean_2[1]], [0, 0, 1]])
    x2 = np.dot(T2, x2)
   
    # compute F with the normalized coordinates
    F = compute_fundamental(x1, x2)
    # print (F)
    # reverse normalization
    F = np.dot(T1.T, np.dot(F, T2))

    return F / F[2, 2]
def random_partition(n,n_data):
    """return n random rows of data (and also the other len(data)-n rows)"""
    all_idxs = np.arange( n_data )
    np.random.shuffle(all_idxs)
    idxs1 = all_idxs[:n]
    idxs2 = all_idxs[n:]
    return idxs1, idxs2
def ransac(data, model, n, k, t, d, debug=False, return_all=False):
    iterations = 0
    bestfit = None
    besterr = np.inf
    best_inlier_idxs = None
    while iterations < k:
        maybe_idxs, test_idxs = random_partition(n, data.shape[0])
        maybeinliers = data[maybe_idxs, :]
        test_points = data[test_idxs]
        maybemodel = model.fit(maybeinliers)
        test_err = model.get_error(test_points, maybemodel)
        also_idxs = test_idxs[test_err < t]  # select indices of rows with accepted points
        alsoinliers = data[also_idxs, :]
        if debug:
            print('test_err.min()', test_err.min())
            print('test_err.max()', test_err.max())
            print('numpy.mean(test_err)', np.mean(test_err))
            print('iteration %d:len(alsoinliers) = %d' %(iterations, len(alsoinliers)))
        if len(alsoinliers) > d:
            betterdata = np.concatenate((maybeinliers, alsoinliers))
            bettermodel = model.fit(betterdata)
            better_errs = model.get_error(betterdata, bettermodel)#重新计算总的error
            thiserr = np.mean(better_errs)
            if thiserr < besterr:
                bestfit = bettermodel
                besterr = thiserr
                best_inlier_idxs = np.concatenate((maybe_idxs, also_idxs))
        iterations += 1
    if bestfit is None:
        raise ValueError("did not meet fit acceptance criteria")
    if return_all:
        return bestfit, {'inliers': best_inlier_idxs}
    else:
        return bestfit
def F_from_ransac(x1,x2,model,maxiter=5000,match_theshold=1e-4):
# def F_from_ransac(x1,x2,model,maxiter=5000,match_theshold=1e-6):
    data = vstack((x1,x2))
    F,ransac_data = ransac(data.T,model,8,maxiter,match_theshold,20,return_all=True)
    return F, ransac_data['inliers']

5.3.2 三维重建示例

  • sift文件

def process_image(imagename, resultname, params="--edge-thresh 10 --peak-thresh 5"):
    if imagename[-3:] != 'pgm':
        im = Image.open(imagename).convert('L')
        im.save('tmp.pgm')
        imagename = 'tmp.pgm'
    cmmd = str(".\sift.exe " + imagename + " --output=" + resultname + " " + params)
    os.system(cmmd)
    print('processed', imagename, 'to', resultname)
def read_features_from_file(filename):
    f=loadtxt(filename)
    return f[:,:4],f[:,4:]
def match(desc1,desc2):
    desc1=array([d/linalg.norm(d) for d in desc1])
    desc2=array([d/linalg.norm(d) for d in desc2])
    dist_ratio=0.6
    desc1_size=desc1.shape
    matchscores=zeros((desc1_size[0],1),'int')
    desc2t=desc2.T
    for i in range(desc1_size[0]):
        dotprods=dot(desc1[i,:],desc2t)
        dotprods=0.9999*dotprods
        indx=argsort(arccos(dotprods))
        if arccos(dotprods)[indx[0]]<dist_ratio*arccos(dotprods)[indx[1]]:
            matchscores[i]=int(indx[0])
    return matchscores
def match_twosided(desc1,desc2):
    matches_12=match(desc1,desc2)
#     print(matches_12.shape)
    matches_21=match(desc2,desc1)
    ndx_12=matches_12.nonzero()[0] #获取的是与desc2匹配的desc1的索引值
    for n in ndx_12:
        if matches_21[int(matches_12[n])]!=n:  # matches_12[n]是desc1中第n个描述符在desc2中的匹配索引
            matches_12[n]=0
    return matches_12
  • homography文件

def make_homog(points): 
    return np.vstack((points,np.ones((1,points.shape[1]))))
def H_from_points(fp,tp):
    if fp.shape!=tp.shape: # 确保源点 (fp) 和目标点 (tp) 的形状相同。如果形状不匹配,抛出异常。
        raise RuntimeError('number of points do not match')
    # 归一化源点:计算源点的均值m和标准差maxstd。创建归一化矩阵C1,用于将源点fp进行归一化处理,以减小计算中的数值误差。
    m=np.mean(fp[:2],axis=1)  # 计算源点的均值 m,对每个坐标分量进行均值计算
    maxstd=max(np.std(fp[:2],axis=1))+1e-9    # 计算源点的标准差 maxstd,加一个小偏移量以避免除零错误  
    C1=np.diag([1/maxstd,1/maxstd,1])   # 创建归一化矩阵 C1,用于缩放坐标
    C1[0][2]=-m[0]/maxstd  # 设置 C1 矩阵的平移部分
    C1[1][2]=-m[1]/maxstd  # 设置 C1 矩阵的平移部分
    fp=np.dot(C1,fp)       # 应用归一化矩阵 C1 到源点 fp
        
        
    # 归一化目标点:类似地,对目标点进行归一化处理,计算均值和标准差,并应用归一化矩阵 C2。
    m=np.mean(tp[:2],axis=1)
    maxstd=max(np.std(tp[:2],axis=1))+1e-9
    C2=np.diag([1/maxstd,1/maxstd,1])
    C2[0][2]=-m[0]/maxstd
    C2[1][2]=-m[1]/maxstd
    tp=np.dot(C2,tp)
        
        
    nbr_correspondences=fp.shape[1]
    A=np.zeros((2*nbr_correspondences,9)) #构建矩阵A,用于求解单应性矩阵。每对点提供两个方程,总共 2 * nbr_correspondences 行。
    for i in range(nbr_correspondences):
        A[2*i]=[-fp[0][i],-fp[1][i],-1,0,0,0,
                tp[0][i]*fp[0][i],tp[0][i]*fp[1][i],tp[0][i]]
        A[2*i+1]=[0,0,0,-fp[0][i],-fp[1][i],-1,
                    tp[1][i]*fp[0][i],tp[1][i]*fp[1][i],tp[1][i]]
    U,S,V=np.linalg.svd(A) # 使用奇异值分解 (SVD)求解矩阵A的最小特征值对应的向量。取V的最后一行(对应于最小特征值),重塑为3x3矩阵 H
    H=V[8].reshape((3,3))
#     反归一化
    H=np.dot(np.linalg.inv(C2),np.dot(H,C1))# 使用逆归一化矩阵将计算得到的单应性矩阵从归一化坐标系转换回原始坐标系,并进行归一化处理。
#     归一化,然后返回
    return H/H[2,2]
class RansacModel(object):
    """ 用于测试单应性矩阵的类,其中单应性矩阵是由网站 http://www.scipy.org/Cookbook/RANSAC 上
    的 ransac.py 计算出来的
    """

    def __init__(self,debug=False):
        self.debug=debug 
    def fit(self,data):

        """ 计算选取的 4 个对应的单应性矩阵 """
        # 将其转置,来调用 H_from_points() 计算单应性矩阵
        data = data.T
        # 映射的起始点
        fp = data[:3,:4]
        # 映射的目标点
        tp = data[3:,:4]
        # 计算单应性矩阵,然后返回
        return H_from_points(fp,tp)

    def get_error(self, data, H):
        """ 对所有的对应计算单应性矩阵,然后对每个变换后的点,返回相应的误差 """
        data = data.T
        # 映射的起始点
        fp = data[:3]
        # 映射的目标点
        tp = data[3:]
        
        # 变换fp
        fp_transformed = dot(H,fp)
        
        # 归一化齐次坐标
        for i in range(3):
            fp_transformed[i]/=fp_transformed[2]

        # 返回每个点的误差
        return sqrt( sum((tp-fp_transformed)**2,axis=0) )
K=array([[2394,0,932],[0,2398,628],[0,0,1]])
im1=array(Image.open('alcatraz1.jpg'))
process_image('alcatraz1.jpg','im1.sift')
l1,d1=read_features_from_file('im1.sift')

im2=array(Image.open('alcatraz2.jpg'))
process_image('alcatraz2.jpg','im2.sift')
l2,d2=read_features_from_file('im2.sift')

matches=match_twosided(d1,d2)
ndx=matches.nonzero()[0]

x1=make_homog(l1[ndx,:2].T)
ndx2=[int(matches[i]) for i in ndx]
x2=make_homog(l2[ndx2,:2].T)
x1n=dot(inv(K),x1)
x2n=dot(inv(K),x2)
model=RansacModel()
E,inliers=F_from_ransac(x1n,x2n,model)
P1=array([[1,0,0,0],[0,1,0,0],[0,0,1,0]])
P2=compute_P_from_essential(E)
ind=0
maxres=0
for i in range(4):
    X=triangulate(x1n[:,inliers],x2n[:,inliers],P1,P2[i])
    d1=dot(P1,X)[2]
    d2=dot(P2[i],X)[2]
    if sum(d1>0)+sum(d2>0)>maxres:
        maxres=sum(d1>0)+sum(d2>0)
        ind=i
        infront=(d1>0)&(d2>0)
    X=triangulate(x1n[:,inliers],x2n[:,inliers],P1,P2[ind])
    X=X[:,infront]
# 绘制X的投影 import camera
# 绘制三维点
cam1 = Camera(P1)
cam2 = Camera(P2[ind])
x1p = cam1.project(X)
x2p = cam2.project(X)

    # 反K归一化
x1p = dot(K, x1p)
x2p = dot(K, x2p)
figure()
imshow(im1)
gray()
plot(x1p[0], x1p[1], 'o')
plot(x1[0], x1[1], 'r.')
axis('off')
figure()
imshow(im2)
gray()
plot(x2p[0], x2p[1], 'o')
plot(x2[0], x2[1], 'r.')
axis('off')
show()

在这里插入图片描述
在这里插入图片描述

5.4 立体图像

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)
        
        dmaps[:,:,displ]=s/sqrt(s_l*s_r)
    return argmax(dmaps,axis=2)
def plane_sweep_gauss(im_l,im_r,start,steps,wid):
    m,n = im_l.shape
    # arrays to hold the different sums
    mean_l = zeros((m,n))
    mean_r = zeros((m,n))
    s = zeros((m,n))
    s_l = zeros((m,n))
    s_r = zeros((m,n))
    # array to hold depth planes
    dmaps = zeros((m,n,steps))
    # compute mean
    filters.gaussian_filter(im_l,wid,0,mean_l)
    filters.gaussian_filter(im_r,wid,0,mean_r)
    # normalized images
    norm_l = im_l - mean_l
    norm_r = im_r - mean_r
    # try different disparities
    for displ in range(steps):
        # move left image to the right, compute sums
        filters.gaussian_filter(roll(norm_l,-displ-start)*norm_r,wid,0,s) # sum nominator
        filters.gaussian_filter(roll(norm_l,-displ-start)*roll(norm_l,-displ-start),wid,0,s_l)
        filters.gaussian_filter(norm_r*norm_r,wid,0,s_r) # sum denominator
    # store ncc scores
    dmaps[:,:,displ] = s/sqrt(s_l*s_r)
    # pick best depth for each pixel
    return argmax(dmaps,axis=2)

ppm文件可从该网站获取

Index of /stereo/data/scenes2001/data/tsukuba (middlebury.edu)

im_l=array(Image.open('scene1.row3.col3.ppm').convert('L'),'f')
im_r=array(Image.open('scene1.row3.col4.ppm').convert('L'),'f')

steps=12
start=4

wid=9

res_ncc=plane_sweep_ncc(im_l,im_r,start,steps,wid)
import cv2
cv2.imwrite('depth_ncc.png',res_ncc)
im_l=array(Image.open('scene1.row3.col3.ppm').convert('L'),'f')
im_r=array(Image.open('scene1.row3.col4.ppm').convert('L'),'f')


steps=12  # 视差步数
start=4
wid=9    # 窗口宽度

res_gauss=plane_sweep_gauss(im_l,im_r,start,steps,wid)


import cv2
cv2.imwrite('depth_gauss.png',res_gauss)
# 显示视差图
subplot(121)
imshow(im_l)

subplot(122)
imshow(res_ncc, cmap='jet')
colorbar()

show()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值