在漫长地研究代码之后,还是选择了书中的官网代码,首先找到 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)中间存在一个其他物体。当我我绕着草坪上的一个喷头拍摄时,出现如下结果:
还有另一次的运行结果:
两个结果中的多个喷头在现实中其实只有一个,而远点的拼接效果都还不错,可是近点的喷头“分身”了。感觉应该是拼接时图像是根据远处的特征匹配进行透视变换,导致近点的景物无法合在一起,所以出现了重影,两次结果主要差在左侧图的拼接,说明该算法可能产生多种拼接结果。