【计算机视觉】图像全景拼接
图像全景拼接
- 相关原理介绍
- 步骤
- 相关代码
- 运行结果
- 总结
- 其他方法简介
(一)相关原理介绍
图像全景拼接涉及到了SIFT特征匹配和RANSAC算法。
1、SIFT特征匹配
为了匹配特征点,为后续图像拼接做准备。(详细原理请看https://blog.csdn.net/weixin_42578378/article/details/88620645)
2、RANSAC算法
RANSAC是RANdom SAmple Consensus的简称,它是根据一组包含异常数据的样本数据集,通过迭代的方法计算出数据的数学模型参数,得到有效样本数据的非确定性的算法。它可以在一组包含“外点”的数据集中,采用不断迭代的方法,寻找最优参数模型,而这些不符合最优模型的点,便被定义为“外点”。
在图像拼接中采用SIFT进行图像的特征匹配时,经常会出现匹配错误的连线,这会导致图像拼接的时候出现偏差,便不能成功拼接图像,这时候使用RANSAC算法。
RANSAC算法会从匹配的数据集中随机抽出几个样本并保证抽出的样本之间不共线,计算出样本单应性矩阵,然后利用这个模型测试所有的匹配数据,并计算满足这个模型数据点的个数与投影误差(即代价函数),若此模型为最优模型,则对应的代价函数最小。这样便可以剔除匹配错误的特征点匹配对,采用不断迭代的方法,寻找到一个较为稳健的单应性矩阵,并且使得满足该矩阵的数据点个数最多。
(二)步骤
图像全景拼接的整体流程如下
1、根据给定的图像集,实现图像之间的特征匹配;
2、通过匹配特征,计算图像之间的变换结构;
3、利用图像的变换结构,实现图像间的映射;
4、针对叠加后的图像,采用相应算法,对齐特征点;
5、通过图割的方法,自动选取拼接缝;
6、图像进行融合。
(三)相关代码
#RANSAC算法拼接3张图片
from pylab import *
from numpy import *
from PIL import Image
from PCV.geometry import homography, warp
from PCV.localdescriptors import sift
featname = ['F:/1python/PythonWork/Chapter2SIFT/ps'+str(i+1)+'.sift' for i in range(3)]
imname = ['F:/1python/PythonWork/Chapter2SIFT/ps'+str(i+1)+'.jpg' for i in range(3)]
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])
# 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(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
# warp the images
delta = 500 # 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)
figure()
imshow(array(im_02, "uint8"))
axis('off')
savefig("ps.jpg",dpi=300)
show()
(四)运行结果
1、室内图像
图片采集自我个人宿舍的一角。图片大致实现了全景拼接,但是在中间还存在了一定的误差,可以明显看到图片没有特别准确的拼接在一起。
2、室外景深落差大的图像
图像采集自集美大学。这三幅图像因为特征明确,也没有太多偏差太大的匹配点,所以最后拼接的结果还算令人满意,我们也能够隐约看见图像拼接缝。
3、室外景深落差小的图像
该图像采集自集美大学。虽然可以看到拼接效果还算可以,也有拼接缝。
(五)总结
观察实验结果图,我们可以看到拍摄于室内的图像,由于东西太多太过繁杂,就会对匹配的结果产生一定程度的影响,这也是算法的一个缺点。拍摄于室外景深落差大的图像,拼接的效果较好。
针对本次图像全景拼接实验的过程,我们需要注意很多细节:
(1)拍摄图像时人需要站在同一个位置上,并且采用从右到左的顺序,使手机保持在同一水平线上拍摄,这样最后处理的效果比较好。
(2)尽量拍摄场景清晰,有较明显特征的图像,避免图像内容繁杂,影响拼接结果。
(3)因为要进行SIFT的特征匹配,所以要注意将sift.exe和vd.ll文件以及所采集的图像和代码应该放在同一个文件夹中。
(4)实验中,为了图像美观以及方便阅览,我们需要自行调整代码中delta的值,使得最后的拼接图像呈现一个合理的大小。
(5)出现 ValueError: did not meet fit acceptance criteria 的错误,这是由于拍摄的图像水平落差比较大,你需要重新拍摄一组图像。
(六)其他方法简介
RANSAC算法虽然能够实现图像的全景拼接,但是还是存在这一些问题,比如图像曝光呀、图像扭曲过度等。而OpenCV提供了stitching算法,使用很方便,不用考虑太多的细节,并且处理后的图像也比RANSAC算法处理后的图像美观些。