计算机视觉——全景图像拼接

1.全景图像拼接

1.1 基本介绍

图像拼接技术就是将数张有重叠部分的图像(可能是不同时间、不同视角或者不同传感器获得的)拼成一幅无缝的全景图或高分辨率图像的技术。图像拼接在医学成像、计算机视觉、卫星数据、军事目标自动识别等领域具有重要意义。图像拼接的输出是两个输入图像的并集。
图像配准(image alignment)和图像融合是图像拼接的两个关键技术。图像配准是图像融合的基础,而且图像配准算法的计算量一般非常大,因此图像拼接技术的发展很大程度上取决于图像配准技术的创新。早期的图像配准技术主要采用点匹配法,这类方法速度慢、精度低,而且常常需要人工选取初始匹配点,无法适应大数据量图像的融合。图像拼接的方法很多,不同的算法步骤会有一定差异,但大致的过程是相同的。

1.2 基本原理

全景融合的3D 几何解释:

– 图像被投影到共同的拼接平面上(同一坐标系)
– 在拼接平面上实现全景融合

在图像拼接中首先利用SIFT算法提取图像特征进而进行特征匹配,继而使用RANSAC算法对特征匹配的结果进行优化,接着利用图像变换结构进行图像映射,最终进行图像融合。
在图像拼接过程中,运用SIFT局部描述算子检测图像中的关键点和特征,SIFT特征是基于物体上的一些局部外观的兴趣点而与影像的大小和旋转无关。对于光线、噪声、些微视角改变的容忍度也相当高,所以用来检测要拼接图像的特征及关键点就很有优势。而接下来即步骤三是找到重叠的图片部分,连接所有图片之后就可以形成一个基本的全景图了。匹配图片最常用的方式是采用RANSAC(RANdom SAmple Consensus, 随机抽样一致),用此排除掉不符合大部分几何变换的匹配。之后利用这些匹配的点来估算单应矩阵”(Homography Estimation),也就是将其中一张图像通过关联性和另一张匹配。
以上关于SIFT算法、RANSAC算法以及图像变换结构可见上一篇博客详解(计算机视觉——SIFT特征提取与检索)。

1.2.1 APAP算法

在图像拼接融合的过程中,受客观因素的影响,拼接融合后的图像可能会存在“鬼影现象”以及图像间过度不连续等问题。下图就是图像拼接的一种“鬼影现象”。解决鬼影现象可以采用APAP算法。
算法流程:

  1. 提取两张图片的sift特征点
  2. 对两张图片的特征点进行匹配
  3. 匹配后,使用RANSAC算法进行特征点对的筛选,排除错误点。筛选后的特征点基本能够一一对应
  4. 使用DLT算法,将剩下的特征点对进行透视变换矩阵的估计
  5. 由于得到的透视变换矩阵是基于全局特征点对进行的,即一个刚性的单应性矩阵完成配准。为提高配准的精度,Apap将图像切割成无数多个小方块,对每个小方块进行单应性矩阵变换,非常依赖于特征点对。若图像高频信息较少,特征点对过少,配准将完全失效,并且对大尺度的图像进行配准,其效果也不是很好,一切都决定于特征点对的数量。

1.2.2 寻找最佳拼接缝(Seam Finding)

在进行图像拼接中针对于鬼影现象可以很好地解决的的算法即为Seam Finding(寻找最佳拼接缝)。该算法的效果如下图:
在这里插入图片描述
可以看到Seam Finding算法可以很好地解决鬼影现象,算法主要原理运用了最大流最小割的思想。图是一个具有权值的有向结构,通常采用一些节点,一些有向连接线表示,这些节点是像素值,或其他特征点。寻找代价最小的分割,典型算法是最小割最大流算法。最大流几句诗将图内带权值看作带有流量值的管道,将最大量水从源点送到汇点。

如何寻找一条最佳拼接缝:

将匹配点最为接近的点作为拼接缝上的点,最终构造出拼接缝。

1.2.2 图像融合(multi-band bleing)

融合目的在于拼缝消除, Multi-Band能够达到比较好的融合效果,但是效率低,采用Laplacian(拉普拉斯)金字塔,通过对相邻两层的高斯金字塔进行差分,将原图分解成不同尺度的子图,对每一个之图进行加权平均,得到每一层的融合结果,最后进行金字塔的反向重建,得到最终融合效果过程。
由下图可知multi-band bleing的效果对于拼接之后的图像进行融合的效果是很好的。
在这里插入图片描述
思想:采用的方法是直接对带拼接的两个图片进行拉普拉斯金字塔分解,后一半对前一半进行融合。
步骤:
(1)首先计算当前待拼接图像和已合成图像的重叠部分。
在这里插入图片描述
(2)两幅图像的融合:分别构建图像A、B的高斯金字塔和拉普拉斯金字塔,然后进行加权融合。
在这里插入图片描述
(3)对加权后的拉普拉斯金字塔进行重构。
在这里插入图片描述

1.3 基本流程

图像拼接的基本流程如下:

  1. 根据给定图像/集,实现特征匹配
  2. 通过匹配特征计算图像之间的变换结构
  3. 利用图像变换结构,实现图像映射
  4. 针对叠加后的图像,采用APAP之类的算法,对齐特征点
  5. 通过图割方法,自动选取拼接缝
  6. 根据multi-band bleing策略实现融合

2.实验过程

2.1 实验代码

# ch3_panorama_test.py
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 = ['F:test4\\group1\\1\\' + str(i + 1) + '.sift' for i in range(3)]
imname = ['F:test4\\group1\\1\\' + str(i + 1) + '.jpg' for i in range(3)]
# extract features and match
l = {}
d = {}
for i in range(3): 
    sift.process_image(imname[i],featname[i])
    l[i],d[i] = sift.read_features_from_file(featname[i])
matches = {}
for i in range(2):
    matches[i] = sift.match(d[i+1],d[i])
    print(matches) 
# visualize the matches (Figure 3-11 in the book)
for i in range(2):
    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(0)
H_01 = homography.H_from_ransac(fp,tp,model)[0] #im 0 to 1 
tp,fp = convert_points(1) #NB: reverse order
H_21 = homography.H_from_ransac(fp,tp,model)[0] #im 2 to 1  
# warp the images
delta = 2000 # for padding and translation
im1 = array(Image.open(imname[0]), "uint8")
im2 = array(Image.open(imname[1]), "uint8")
im_01 = warp.panorama(H_01,im1,im2,delta,delta)
im1 = array(Image.open(imname[2]), "f")
im_21 = warp.panorama(H_21,im1,im_01,delta,delta)
figure()
imshow(array(im_21, "uint8"))
axis('off')
savefig("example5.png",dpi=300)
show()

2.2 固定点位拍摄实现图像拼接

2.2.1 实验结果

2.2.1.1 室外场景

数据集:
在这里插入图片描述
实验结果:
1.特征匹配结果:
在这里插入图片描述在这里插入图片描述
2.拼接结果:
在这里插入图片描述

2.2.1.2 室内场景

数据集
在这里插入图片描述
实验结果:
1.特征匹配结果:
在这里插入图片描述
2.拼接结果:
在这里插入图片描述

2.2.2 实验分析

  • 在实验过程中,原代码必须是五张图像才可运行,在进行多处修改之后可以针对三张图像、两张图像进行拼接。两组实验结果的效果都较好没有出现鬼影现象。
  • 观察第一组室外建筑物的拼接实验结果发现其第一张和第二张图像拼接效果很好基本不容易观察到拼接痕迹,在第二张和第三张进行拼接的时候发现建筑物的顶端发生错位,致使拼接后的建筑物有轻微侵倾斜且拼接痕迹很明显,考虑可以利用上课所讲到的图像融合(multi-band bleing)使得拼接后的图像拼接痕迹更平滑,不那么明显。
  • 观察第二组室内图像的拼接,其实验结果大致看是好的,若仔细查看可以发现拼接痕迹很严重,画框的拼接处可以明显地看到错位,沙发的拼接处也有错位的情况。针对第二组实验来说,其拼接结果运行多次,前几次很差基本是扭曲的且运行速度极慢,由前几次的实验经验中考虑到或许是因为图像本身像素过大,原像素为3024* 3024,后将其像素改为800* 800,实验效果有明显改观且运行时间也大大减少,得到结论:图像本身像素对于运行时间和实验效果都有很大的影响,图像像素要适当,不能太大也不能太小。
  • 对比室内和室外的场景的实验结果发现室外图像的拼接效果较好一些,我认为其原因为:室外场景提取到的特征点丰富,匹配点也比室内场景的丰富,即再进行拼接等一系列的操作时参考性更大,拼接效果自然更好一些。

2.3 视差变化大的场景实现图像拼接

2.3.1 实验结果

2.3.1.1 室外场景

数据集:
在这里插入图片描述
实验结果:
1.特征匹配结果:
在这里插入图片描述
在这里插入图片描述

2.拼接结果:
在这里插入图片描述

2.3.1.2 室内场景

数据集:
在这里插入图片描述
实验结果
1.特征匹配结果:
在这里插入图片描述
2.拼接结果:
在这里插入图片描述

2.3.2 实验分析

  • 以上两组实验由视差变化大的室内场景和室内场景做对比进行实验。在实验过程中,实验运行速度极慢,通过修改图像像素运行效率有了明显改观。
  • 观察第一组室外场景的实验结果,拼接效果本人觉得出神入化,忽略光照阴影的影响,我放大观察了很多细节,就连十字路口的车辆都拼接得完美无暇,视差大的室外场景的拼接效果真的非常出色。再对建筑物之间的拼接进行观察也并没有出现明显的倾斜情况,建筑物边缘的拼接处也并没有出现之前实验中出现的拼接错位现象,总之这一组实验结果是本次实验中最好的。思考原因:由于视差大,远景较为丰富的情况下,SIFT算法在进行提取特征的时候提取到了较多远景中的特征点,再进行拼接的时候有了更多的参考,所以实验结果才会效果好。
  • 观察第二组室内场景的实验结果出现了鬼影现象,进而仔细观察可以发现远处景物的拼接效果较好,基本没有明显的误差,而对于近处花草的拼接出现了较大的错误。思考:在进行图像拼接远处景物和远处景物拼接很好的情况下,没有考虑到近处景物的拼接,连带着一整块拼接上去了就发生了如上截图的鬼影现象。
  • 对于景深落差大,我认为当拍摄图像时,我们所需要拍摄的目标和我们的相机之间存在某个物体,比如雕塑,停放的车辆等。这样我们在旋转拍摄角度的时候,物体和目标之间在相机偏差的位置就会有变化,这样导致在拍摄的图像中目标和物体的位置就会有差距,这样的图像做全景图像的拼接就会有重影产生。

3.实验总结

在本次实验过程中得到如下总结:

  • 对比固定点位拍摄和视差变化大的场景可以得到结论:固定点位拍照的图像在进行拼接的时候没有发生鬼影现象,但较远处的拼接有略微偏差,而差变化大的场景在进行拼接时,其对于远景的拼接效果极好,细节处的拼接也处理得很到位。两种场景各有优劣。
  • 分别对比室内和室外场景得拼接结果可以得到结论:室外场景的拼接效果较好,其特征点丰富,在拼接时参考性很大;室内场景单一,特征点也较少,拼接的效果也较为不好。
  • 实验中,拼接图像的像素会影响运行速度,所以在拍摄图像上传到电脑后要进行处理,使得像素大小适当,这样对于运行时间会有较大的改变。
  • 代码中有个参数delta。这个参数是针对你拍摄图像时,你相对平移的距离的变量,当你拍摄近景时候,这个参数尽量该小,远景相反。
  • dpi是图像精细度的变量,可以通过修改来改变图像的分辨率,数值越大表示图像越精细,即分辨率越高。

4.实验中遇到的问题及解决方法

问题1
遇到报错如下:

Traceback (most recent call last):
  File "F:PJ.py", line 7, in <module>
    from PCV.geometry import homography, warp
  File "F:warp.py", line 128
    print 'warp - left'                      ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(print 'warp - left')?
[Finished in 4.7s]

解决方法:
由于本机python环境为3.6而代码里的书写规范不符合3.6的规范,打开报错的文件将print语句加上()即可。

问题2
遇到报错如下:

Traceback (most recent call last):
  File "F:PJ.py", line 7, in <module>
    from PCV.geometry import homography, warp
  File "F:warp.py", line 1, in <module>
    import matplotlib.delaunay as md 
ModuleNotFoundError: No module named 'matplotlib.delaunay'
[Finished in 4.8s]

解决方法:
因为PCV下面的warp.py里面的matplotlib.delaunay不再被使用了,所以把它换成一个相同功能的就可以:
①:把import matplotlib.delaunay as md 换成from scipy.spatial import Delaunay
②:warp.py里面的centers,edges,tri,neighbors = md.delaunay(x,y)换成tri= Delaunay(np.c_[x,y]).simplices就好啦

发布了13 篇原创文章 · 获赞 5 · 访问量 2183

猜你喜欢

转载自blog.csdn.net/weixin_45617915/article/details/105064948