计算机视觉ch3 图像到图像映射——全景拼接

文章目录

    • 何为全景拼接
    • sift匹配
    • 图像配准
    • python实现
    • 问题总结

何为全景拼接

将两幅或多幅具有重叠区域的图像,合并成一张大图
→基础流程:

  1. 针对某个场景拍摄多张/序列图像
  2. 计算第二张图像与第一张图像之间的变换关系 (sift匹配)
  3. 将第二张图像叠加到第一张图像的坐标系中 (图像映射)
  4. 变换后的融合/合成
  5. 在多图场景中,重复上述过
    总结起来就是 特征点的提取与匹配、图像配准、图像融合。

sift匹配

利用Sift提取图像的局部特征,在尺度空间寻找极值点,并提取出其位置、尺度、方向信息。
具体步骤可以参考之前的博文:

https://blog.csdn.net/weixin_44059188/article/details/90698704

图像配准

图片匹配就是找到图像之间所有重叠的部分,将其拼接后就能得到一幅全景图
它是一种确定待拼接图像间的重叠区域以及重叠位置的技术,是整个图像拼接的核心
本文采用的是基于特征点的图像配准方法,即通过匹配点对构建图像序列之间的变换矩阵,从而完成全景图像的拼接
RANSAC算法
首先随机地选择两个点,用两个点确定一条直线,称在这条直线一定范围内的点为这条直线的支撑。这样的随机选择重复数次,然后,具有最大支撑集的直线被确认为是样本点集的拟合。在拟合的误差距离范围内的点被认为是内点,它们构成一致集,反之则为外点。
根据算法描述,可以很快判断,如果只有少量外点,那么随机选取的包含外点的初始点集确定的直线不会获得很大的支撑,值得注意的是,过大比例的外点将导致RANSAC算法失败。
在直线拟合的例子中,由点集确定直线至少需要两个点;而对于透视变换,这样的最小集合需要有4个点。

Homography
在图片拼接的过程中,需要进行一些简单的单应性变换才可以进行比较平稳的拼接,具体的内容可以参考:

https://blog.csdn.net/weixin_44059188/article/details/90922045

python实现

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

# set paths to data folder
featname = [str(i+1)+'.txt' for i in range(2)]
imname = [str(i+1)+'.jpg' for i in range(2)]

# extract features and match
l = {}
d = {}
for i in range(2):
    sift.process_image(imname[i],featname[i])
    l[i],d[i] = sift.read_features_from_file(featname[i])

matches = {}
for i in range(1):
    matches[i] = sift.match(d[i+1],d[i])

# visualize the matches (Figure 3-11 in the book)
for i in range(1):
    im1 = array(Image.open(imname[i]))
    im2 = array(Image.open(imname[i+1]))
    figure()
    sift.plot_matches(im1,im2,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 

# warp the images
delta = 2000 # for padding and translation

im1 = array(Image.open(imname[0]), "uint8")
im2 = array(Image.open(imname[1]), "uint8")
im_12 = warp.panorama(H_01,im1,im2,delta,delta)

figure()
imshow(array(im_12, "uint8"))
axis('off')
show()

场景1:近景(有层次感)
素材:
计算机视觉ch3 图像到图像映射——全景拼接_第1张图片
sift匹配:
计算机视觉ch3 图像到图像映射——全景拼接_第2张图片计算机视觉ch3 图像到图像映射——全景拼接_第3张图片
计算机视觉ch3 图像到图像映射——全景拼接_第4张图片计算机视觉ch3 图像到图像映射——全景拼接_第5张图片
结果:

场景2:远景
素材:
计算机视觉ch3 图像到图像映射——全景拼接_第6张图片
结果:

虽然场景2的拼接效果也不理想但是可以明显的看出是远高于近景拍摄的素材拼接效果的。
场景3:室内
素材:
计算机视觉ch3 图像到图像映射——全景拼接_第7张图片
结果:

问题总结

全景拼接的一个关键点就是sift特征点的匹配,只有寻找到正确且数量较多的特征点,在后续的拼接中才能更好的完成,拼接的更自然。而原始图片的像素值很大程度上决定了特征点的寻找,像素值太低,将导致寻找到的特征点过少,不利于后续的拼接效果。而像素值过高会导致代码的运行时间过长,加重算法的负荷。建议的像素点是在800×800以内。

你可能感兴趣的:(全景拼接)