全景图像拼接的实现

在漫长地研究代码之后,还是选择了书中的官网代码,首先找到 PCV\PCV-master\PCV\tools 文件夹下的ransac.py文件,打开并找到90行,在print后日常加括号以及重装PCV。
全景图像拼接的实现
然后官方代码如下:

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 = ['zs'+str(i+1)+'.sift' for i in range(5)] 
imname = ['zs'+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()


官方运行结果如下:
全景图像拼接的实现
可以看出连接处很丝滑,不像我的失败结果:
全景图像拼接的实现
确实过程中也经历了很多问题。毕竟代码都一样,那应该就是图片的问题了。

1、室内全景图

这里感谢一下我的妈妈,在我经历了无数次拍摄宿舍内全景图拼接失败之后,我感觉可能是因为宿舍比较小以及多处结构相同的问题,出现了拼接混乱甚至图片反着拼接的问题(参考上面的失败结果,大致一样悲惨)。不得已求助老妈在家里帮我拍摄了一组图片,结果一下就好起来了,如下:
全景图像拼接的实现全景图像拼接的实现
全景图像拼接的实现
全景图像拼接的实现
全景图像拼接的实现
前四张图对应的是五张原图之间的四处特征匹配结果,也就是拼接位置,最后一张为全景图。可以明显观察到,中间位置的全景图比较正常,而两边则是被拉伸地比较长,比较模糊。

2、室外全景图(景深落差小)

个人理解景深落差小就是站在一个位置正常拍摄周围的景物。下面是站在集美大学的大草坪上拍摄的图片:
全景图像拼接的实现
全景图像拼接的实现
全景图像拼接的实现
全景图像拼接的实现
全景图像拼接的实现
我曾经拍过一组广角角比较大的图,也就是两两图像之间相同景物的部分比较少,结果失败了,同样是出现了拼接混乱以及反向拼接的问题,所以我减少了每次拍照的旋转角度,最终结果还是不错的,就是有点糊,可能是我图像分辨率比较低吧。下面这张是同学拍的放在我这里运行出来的全景图,相对比较清晰,应该是手机问题吧~(此图为集美大学中山纪念馆以及中间的大草坪)
全景图像拼接的实现

3、室外全景图(景深落差大)

对于景深落差大的理解,我是真的不知道如何取材说明,听到了各种各样的理解。根据不同理解也做了不同的测试(毕竟我也不知道是哪种解释)
1)景深是拍摄距离。我将上述的五张图中的第二张替换为了中山纪念馆的近景照,如下:
全景图像拼接的实现
关于图二与图一和图三的特征匹配结果比较正常
全景图像拼接的实现
全景图像拼接的实现
但是拼接的全景图结果出现了黑色的没有拼接的部分,而那张近景照被扭曲地很厉害,旋转拉伸角度也不是理想中的样子,分析了一下应该是特征匹配后进行透视变换的时候由于近景照的特征点相对位置与其他图不同,所以导致了单应性矩阵不太理想,所以透视变换不太理想,结果拼接不成功。
全景图像拼接的实现
2)景深是远点模糊。所以我同样将第二张图替换成了下面这张:
全景图像拼接的实现
结果直接报错:全景图像拼接的实现
翻译过来就是不符合匹配标准。分析了一下应该是对于第二张图来说,中山纪念馆的位置没有其他图和它之间存在特征匹配,所以无法继续运行。
3)中间存在一个其他物体。当我我绕着草坪上的一个喷头拍摄时,出现如下结果:
全景图像拼接的实现
全景图像拼接的实现
全景图像拼接的实现
全景图像拼接的实现
全景图像拼接的实现
还有另一次的运行结果:
全景图像拼接的实现
两个结果中的多个喷头在现实中其实只有一个,而远点的拼接效果都还不错,可是近点的喷头“分身”了。感觉应该是拼接时图像是根据远处的特征匹配进行透视变换,导致近点的景物无法合在一起,所以出现了重影,两次结果主要差在左侧图的拼接,说明该算法可能产生多种拼接结果。

4、总结

  1. 所有图像都采用2000*1500的分辨率,每次运行时间10分钟左右,如果想让运行时间快一点就调小分辨率。
  2. 室内和室外最大的差别在于拼接后全景图左右两边的拉伸程度,室外的景相对拉伸较小,而室内拉伸较大;还有全景图中间部分感觉室外的比较自然,室内的有点被挤压变形。
  3. 景深落差小的全景图显然是比较理想的,而景深落差大的全景图会因为特征点的匹配问题出现各种奇怪的错误。(如果知道景深概念的人请一定评论告诉我!!!折磨我一下午了!!!)
  4. 多次运行相同的图片产生的结果不同,这些不同大多出现在了拼接不理想的结果中,应该是因为特征匹配的问题导致每次求出的单应性矩阵不同,图片会进行不同的透视变换,所以拼接结果不同。
  5. 其他一些关于全景优化的问题暂时还没有延伸探讨,所以全景图还是会存在一些瑕疵。