Python计算机视觉-创建全景图

时间:2024-04-13 12:11:10

1.全景拼接原理简介

一张普通照片所提供的图像信息只是我们视野中的一部分,两张甚至多张同一位置拍摄的相邻图像是单应性相关的,那么把他们拼接在一起就能看到我们视野中的全部景象,于是全景图就诞生了!

1.1 流程

实际情况中,创建全景图的步骤大致分为三步:图像获取、图像配准、图像融合
两张待配准的图像处于不同的坐标系中,配准的目的就是将他们投影到拼接平面(即同一坐标系下)对齐。拼接的前提是,我们的图片集中图片之间要有共视区域,这样我们才能在各图像之间提取特征并寻找匹配点,然后在尽量去除错配点对的情况下,根据匹配点计算图像间的映射关系,最后将图像根据映射关系拼接以获得更宽广的可视面积,多次进行配准拼接融合步骤,就得到了我们所需的全景图。

1.2 RANSAC

其中对于特征点的提取,传统方法有SIFT、Surf、Orb描述子可用,接下来我们使用的就是之前刚学习的SITF描述子,它具有较高的准确度。
那匹配中错配的点对如何处理?最小二乘法可以综合地去拟合匹配点中的所有点对,但如果噪声点数量太多怎么办,很明显最小二乘会很大程度受噪声影响导致不良的筛选结果。好在有一个既简单易理解又十分强大的算法——RANSAC(Random Sample Consensus)随机一致性采样。

RANSAC是根据一个包含异常数据的数据集计算数据的数学模型参数,从而得到有效样本数据的算法。
核心思想是:
(1) 给定一个区间阈值;
(2) 随机选取数据集中的两个点;
(3) 根据两点构造直线计算解析式 y=ax+b
(4) 根据阈值,计算位于直线附近区间内的点的数量;
(5) 循环步骤(2)-(4),找到包含最大点数量的点集作为筛选结果,求解单应性矩阵。

1.3 关于拼接图像

使用RANSAC算法计算出图像间单应性矩阵,我们选取中心的图像作为公共平面,将中心图像左右的区域以0填充,这样就可以将扭曲后的图像拼接到腾出的空间当中。

2.创建全景图

课本中对于创建全景图的源码如下:
使用五张图像作为图像集进行拼接

from pylab import *
from numpy import *
from PIL import Image

# If you have PCV installed, these imports should work
from PCV.geometry import homography, warp
from PCV.localdescriptors import sift

"""
This is the panorama example from section 3.3.
"""

# set paths to data folder
featname = ['./images/1/'+str(i+1)+'.sift' for i in range(5)]
imname = ['./images/1/'+str(i+1)+'.jpg' for i in range(5)]

# extract features and match
l = {}
d = {}
for i in range(5):
    sift.process_image(imname[i],featname[i])
    l[i],d[i] = sift.read_features_from_file(featname[i])

matches = {}
for i in range(4):
    matches[i] = sift.match(d[i+1],d[i])

# visualize the matches (Figure 3-11 in the book)
for i in range(4):
    im1 = array(Image.open(imname[i]))
    im2 = array(Image.open(imname[i+1]))
    figure()
    sift.plot_matches(im2,im1,l[i+1],l[i],matches[i],show_below=True)


# function to convert the matches to hom. points
def convert_points(j):
    ndx = matches[j].nonzero()[0]
    fp = homography.make_homog(l[j+1][ndx,:2].T) 
    ndx2 = [int(matches[j][i]) for i in ndx]
    tp = homography.make_homog(l[j][ndx2,:2].T) 
    
    # switch x and y - TODO this should move elsewhere
    fp = vstack([fp[1],fp[0],fp[2]])
    tp = vstack([tp[1],tp[0],tp[2]])
    return fp,tp


# estimate the homographies
model = homography.RansacModel() 

fp,tp = convert_points(1)
H_12 = homography.H_from_ransac(fp,tp,model)[0] #im 1 to 2 

fp,tp = convert_points(0)
H_01 = homography.H_from_ransac(fp,tp,model)[0] #im 0 to 1 

tp,fp = convert_points(2) #NB: reverse order
H_32 = homography.H_from_ransac(fp,tp,model)[0] #im 3 to 2 

tp,fp = convert_points(3) #NB: reverse order
H_43 = homography.H_from_ransac(fp,tp,model)[0] #im 4 to 3    


# warp the images
delta = 2000  # for padding and translation

im1 = array(Image.open(imname[1]), "uint8")
im2 = array(Image.open(imname[2]), "uint8")
im_12 = warp.panorama(H_12,im1,im2,delta,delta)

im1 = array(Image.open(imname[0]), "f")
im_02 = warp.panorama(dot(H_12,H_01),im1,im_12,delta,delta)

im1 = array(Image.open(imname[3]), "f")
im_32 = warp.panorama(H_32,im1,im_02,delta,delta)

im1 = array(Image.open(imname[4]), "f")
im_42 = warp.panorama(dot(H_32,H_43),im1,im_32,delta,2*delta)


figure()
imshow(array(im_42, "uint8"))
axis('off')
show()


运行时报错,同样对于Python3需要对print语句进行语法转换:
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
从左向右序列的图片集会出现错乱拼接的情况,于是我接下来都改用从右向左的图像序列。

2.1 室外景深落差较小的情况

第一组拼接:
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
第二组拼接:
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图

2.2 室外景深落差较大的情况

Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图

2.3 室内图像拼接

Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图
Python计算机视觉-创建全景图

2.4 小结

(1) RANSAC算法即使是在大量噪声干扰的情况下也能鲁棒地获得模型参数,ransac模型类RansacModel中的fit() 方法接受ransac.py选择的至少四个对应点对从而拟合一个单应性矩阵。get_error() 方法对每个对应点对使用该单应性矩阵,返回相应的距离平方和,从而判定错误点对。距离的阈值和最小期望的点对数目可以在**H_from_ransac()**函数当中指定,而最大迭代次数决定此次点对筛选的时间效率和准确度,太少会导致拟合模型中正确结果被剔除留下错误结果,太多占用大量运行时间。

(2) 扭曲图像时 delta 值的选取对结果图的效果起决定性作用,delta 值太大会使得全景图中有大量多余的0填充部分,太小则扭曲失真,完全达不到拼接的目的。另外在拍摄图像时相机应尽量保持在同一位置,同一水平线上移动,每次取景的位移基本相同则可以得到较好的全景效果。

(3) 各幅图像由于曝光不同在单个图像的拼接边界上存在边缘效应,能明显发现明暗区别,可在图像融合时用 graph cut、multy-band blend等方法得到更好的过渡效果。