图像拼接技术就是将数张有重叠部分的图像(可能是不同时间、不同视角或者不同传感器获得的)拼成一幅无缝的全景图或高分辨率图像的技术。图像拼接在医学成像、计算机视觉、卫星数据、军事目标自动识别等领域具有重要意义。图像拼接的输出是两个输入图像的并集。
图像配准(image alignment)和图像融合是图像拼接的两个关键技术。图像配准是图像融合的基础,而且图像配准算法的计算量一般非常大,因此图像拼接技术的发展很大程度上取决于图像配准技术的创新。早期的图像配准技术主要采用点匹配法,这类方法速度慢、精度低,而且常常需要人工选取初始匹配点,无法适应大数据量图像的融合。图像拼接的方法很多,不同的算法步骤会有一定差异,但大致的过程是相同的。
全景融合的3D 几何解释:
– 图像被投影到共同的拼接平面上(同一坐标系)
– 在拼接平面上实现全景融合
在图像拼接中首先利用SIFT算法提取图像特征进而进行特征匹配,继而使用RANSAC算法对特征匹配的结果进行优化,接着利用图像变换结构进行图像映射,最终进行图像融合。
在图像拼接过程中,运用SIFT局部描述算子检测图像中的关键点和特征,SIFT特征是基于物体上的一些局部外观的兴趣点而与影像的大小和旋转无关。对于光线、噪声、些微视角改变的容忍度也相当高,所以用来检测要拼接图像的特征及关键点就很有优势。而接下来即步骤三是找到重叠的图片部分,连接所有图片之后就可以形成一个基本的全景图了。匹配图片最常用的方式是采用RANSAC(RANdom SAmple Consensus, 随机抽样一致),用此排除掉不符合大部分几何变换的匹配。之后利用这些匹配的点来估算单应矩阵”(Homography Estimation),也就是将其中一张图像通过关联性和另一张匹配。
以上关于SIFT算法、RANSAC算法以及图像变换结构可见上一篇博客详解(计算机视觉——SIFT特征提取与检索)。
在图像拼接融合的过程中,受客观因素的影响,拼接融合后的图像可能会存在“鬼影现象”以及图像间过度不连续等问题。下图就是图像拼接的一种“鬼影现象”。解决鬼影现象可以采用APAP算法。
算法流程:
在进行图像拼接中针对于鬼影现象可以很好地解决的的算法即为Seam Finding(寻找最佳拼接缝)。该算法的效果如下图:
可以看到Seam Finding算法可以很好地解决鬼影现象,算法主要原理运用了最大流最小割的思想。图是一个具有权值的有向结构,通常采用一些节点,一些有向连接线表示,这些节点是像素值,或其他特征点。寻找代价最小的分割,典型算法是最小割最大流算法。最大流几句诗将图内带权值看作带有流量值的管道,将最大量水从源点送到汇点。
如何寻找一条最佳拼接缝:
将匹配点最为接近的点作为拼接缝上的点,最终构造出拼接缝。
1.2.3 图像融合(multi-band bleing)融合目的在于拼缝消除, Multi-Band能够达到比较好的融合效果,但是效率低,采用Laplacian(拉普拉斯)金字塔,通过对相邻两层的高斯金字塔进行差分,将原图分解成不同尺度的子图,对每一个之图进行加权平均,得到每一层的融合结果,最后进行金字塔的反向重建,得到最终融合效果过程。
由下图可知multi-band bleing的效果对于拼接之后的图像进行融合的效果是很好的。
思想:采用的方法是直接对带拼接的两个图片进行拉普拉斯金字塔分解,后一半对前一半进行融合。
步骤:
(1)首先计算当前待拼接图像和已合成图像的重叠部分。
(2)两幅图像的融合:分别构建图像A、B的高斯金字塔和拉普拉斯金字塔,然后进行加权融合。
(3)对加权后的拉普拉斯金字塔进行重构。
图像拼接的基本流程如下:
根据给定图像/集,实现特征匹配 通过匹配特征计算图像之间的变换结构 利用图像变换结构,实现图像映射 针对叠加后的图像,采用APAP之类的算法,对齐特征点 通过图割方法,自动选取拼接缝 根据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.拼接结果:
数据集
实验结果:
1.特征匹配结果:
2.拼接结果:
数据集:
实验结果:
1.特征匹配结果:
2.拼接结果:
数据集:
实验结果
1.特征匹配结果:
2.拼接结果:
在本次实验过程中得到如下总结:
对比固定点位拍摄和视差变化大的场景可以得到结论:固定点位拍照的图像在进行拼接的时候没有发生鬼影现象,但较远处的拼接有略微偏差,而差变化大的场景在进行拼接时,其对于远景的拼接效果极好,细节处的拼接也处理得很到位。两种场景各有优劣。 分别对比室内和室外场景得拼接结果可以得到结论:室外场景的拼接效果较好,其特征点丰富,在拼接时参考性很大;室内场景单一,特征点也较少,拼接的效果也较为不好。 实验中,拼接图像的像素会影响运行速度,所以在拍摄图像上传到电脑后要进行处理,使得像素大小适当,这样对于运行时间会有较大的改变。 代码中有个参数delta。这个参数是针对你拍摄图像时,你相对平移的距离的变量,当你拍摄近景时候,这个参数尽量该小,远景相反。 dpi是图像精细度的变量,可以通过修改来改变图像的分辨率,数值越大表示图像越精细,即分辨率越高。 4.实验中遇到的问题及解决方法问题1
遇到报错如下:
Traceback (most recent call last):
File "F:PJ.py", line 7, in
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
from PCV.geometry import homography, warp
File "F:warp.py", line 1, in
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就好啦