全景拼接
- 一、图像拼接
-
- 1.图像拼接是什么?
- 1.2图像拼接的技术支持
-
- 1.2.1 APAP算法
- 1.2.2 拼接裂缝用最大流量和最小切割
- 1.2.3 multi-band blending实现图像融合
- 1.3用python完成简单的图像拼接
-
- 1.3.1实验代码
- 1.3.2实验内容与分析
- 1.3.3实验总结和解决问题
一、图像拼接
1.图像拼接是什么?
图像拼接(Image Stitching)它是一种利用真实图像形成全景空间的技术。它将多个图像拼接成大型图像或360度全景图像。图像拼接技术包括计算机视觉、计算机图形学、数字图像处理和一些数学工具。图像拼接的基本步骤主要包括相机校准、传感器图像畸变校正、图像投影变换、匹配点选择、全景图像拼接(集成)、亮度和颜色的平衡处理等。本文主要从匹配点的选择和具体全景拼接技术的实现来讨论。
1.2图像拼接的技术支持
在之前的博文中有关,这里就不赘述了。这一次,将其应用于图像的全景拼接,并根据特征点进行匹配,使用这些匹配点来估计单应矩阵(使用之前博客中提到的)(该算法用于优化sift算法减少了错误的特征匹配),即通过一个相关性和另一个匹配方法将其中一个。单应矩阵H,将原图像中的任何像素点坐标转换为新坐标点,转换后的图像为适合拼接的结果图像。 可简单分为以下步骤:
根据以上全景拼接中使用的方法,除了我之前章中介绍的相关方法和除了知识点,本次重点技术介绍是相关的是的,即如何叠加和拼接两个特征匹配后相似度高的图像对齐特征点,以某种方式找到两个图像,通过该方法对拼接后的图像进行处理,使拼接后的图像在人眼视觉效果上更加柔和。
1.2.1 APAP算法
图像匹配是为了改变图像,使改变后的图像在常见的坐标系中对齐。图像匹配是一个非常重要的步骤,以便进行图像对比和更精细的图像分析。这里使用的主要算法是APAP算法。 这边引用了csdn有关博主对APAP我认为解释算法有助于理解算法的基本过程和实现。
https://blog.csdn.net/warrenwg/article/details/49759779
1.提取两张图片sift特征点 2.匹配两张图片的特征点,引用匹配过程(Distinctive Image Features from Scale-Invariant Keypoints) 3.匹配后,仍有许多错误点。此时,使用论文(Accelerated Hypothesis Generation for Multi-Structure Robust Fitting)提到的RANSAC筛选特征点对的改进算法。筛选后的特征点基本上可以一一对应。 4.使用DLT算法(Multiple View Geometry p92提到),估计透视转换矩阵的剩余特征点。 5.因为获得的透视变换矩阵是基于整体特征点,即刚性单应性矩阵完成匹配。为了提高准确性,。 Apap虽然匹配可以更好地完成,但它非常依赖于特征点对,并且存在局限性。如果图像高频信息较少,特征点对过少,匹配将完全失效,大规模图像匹配,效果不是很好,。
1.2.2 拼接裂缝用最大流量和最小切割
作为解决图论问题的经典方法,我没想到这种方法可以用于图像处理的拼接问题,即图形切割。在我看来,下面的博客很容易理解,推荐参考。 最大流最小切割
1.2.3 multi-band blending实现图像融合
在图像拼接过程中,根据所采集的样本在拍照角度和曝光度上的不同,会导致拼接后的图像灰度情况层次不齐,虽然在视觉效果上拼接后的图片很好的重合,但是人眼感受到的拼接带来的光效痕迹还是过于明显,所以需要特定的处理解决这种不自然。此时可采用blending方法。multi-band blending(多波段融合,又称拉普拉斯金字塔融合)是目前图像融合的好方法。人们可以通过这种方法更好地整合样本图像,即通俗地说 拉普拉斯金字塔分别用于构建集成图像(拉普拉斯算子可以提取图像的高频信息,在拉普拉斯金字塔中,上层图像越高),然后按照某些规则集成同一层图像,通常是Alpha blending/Feathering;不同层次的图像(不同频率段的图像)融合不同规则,高频部分blend slowly,低频部分blend quickly; 基本步骤:
1.根据图像A和B拉普拉斯金字塔的建立LA和LB;
2.从蒙版M的选择中建立高斯金字塔GM;
3.使用GM从LA和LB构成金字塔金字塔LS:
LS = GM * LA (1-GM)* LB
4.折叠LS获得最终集成图像的金字塔
这里我参考了一篇关于拉普拉斯金字塔融合的博文,推荐参考阅读。 https://blog.csdn.net/u014485485/article/details/89516028
让我们开始测试拼接。
1.3用python完成简单的图像拼接
1.3.1实验代码
# -*- coding: utf-8 from pylab import * from numpy import * from PIL import Image from scipy.spatial import Delaunay # If you have PCV installed, these imports should work from PCV.geometry import homography, warp from PCV.localdescriptors import sift featname = [ 'E:/thirddown/computervision/data/ransac/AP/1/'+ str(i + 1) + '.sift' for i in range(5)]
imname = ['E:/thirddown/computervision/data/ransac/AP/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 # im1 到 im2 的单应性矩阵
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)
imsave('example.jpg', array(im_42, "uint8"))
figure()
imshow(array(im_42, "uint8"))
axis('off')
show()
1.3.2实验内容与分析
①针对固定点位拍摄多张图片,以中间图片为中心,实现图像的拼接融合
数据集①
从实验结果来看,最开始的时候没有看清理解代码,导致拼接出来的图片有很多黑屏和错配,后来发现是代码逻辑要求我们的数据集合,。修改过后即可以正确拼接。为了拼接处理速度变快,我将图片的像素从原来的2448x3264改为1000x1333。大体上看这张全景图像的拼接算是比较成功,出来中央有一条拼接缝的光线曝光度相差明显之外没有很大的不足,但是放大来看,为了使特征匹配符合,也有一定的错位。 数据集② 由于曝光度问题,导致拼接后的图像色彩有差异,但是总体来说,拼接效果答题良好,除了特征点匹配较为密集的建筑物上有少许偏倚,答题拼接良好。因为图像的伸缩变换,导致一些像素信息丢失,放大看有写地方失真。 ②2. 针对同一场景(需选取视差变化大的场景,也就是有近景目标),更换拍摄位置,分析拼接结果 从实验结果来看,对于有主图物的拼接,效果很好,图上拼接部分除了明显的肉眼差异,中间的红圈部分的拼接几乎不可视,是很优秀的一次实验测试,五张图片的最右张样本图因为有的关系,导致拼接没有很拟合,但是主要建筑物这个是算法的局限性。相对于数据集②,在同一场景拍摄,有主图物的特征匹配明显的拼接效果更好。
1.3.3实验小结与问题解决
关于我所使用的全景拼接算法局限性很大,对于处于统一地点的拍摄,旋转镜头越稳定,没有上下或者尺度上的偏倚和光线上的曝光度不一致的情况下,拼接效果才会比较好,即。从上面的测试中我也发现了许多问题,比如拼接时发生错拼现象,这些都是特征处理时发生的错配较多引起的,所以一个好的特征提取匹配算法是全景拼接效果好的基础。同时代码中有个参数delta。这个参数是针对你拍摄图像时,你相对平移的距离的变量,当你拍摄近景时候,这个参数尽量该小,远景相反。dpi是图像精细度的变量,可以通过修改来改变图像的分辨率,数值越大表示图像越精细,即分辨率越高。
这个问题出现说明采集的图片无法达到匹配要求,因为算法局限性,该图像拼接只能对等水平等尺度的图片进行较好的拼接,所以应该重新采集过样本数据集。 图片太大导致内存运行不足溢出,同比修改样本集的像素大小,但是同样的像素修改过后会影响拼接的成功程度。
由于所写代码局限性数据集图片的名字要改为1.jpg,2.jpg依次类推,这段代码可以进行适当修改,便于遍历数据集。
数据集大小尺寸必须统一。