【计算机视觉实验三】图像拼接

一、图像映射与全景拼接

1.1 简介

首先是在连续图像对间使用SIFT特征寻找匹配对应点对,SIFT是具有较强稳健性的描述子,能够比其他描述子产生更少的错误点,但是该方法仍不是很完美;使用RANSAC算法估计出图像间的单应性矩阵,判定哪些点对是正确的,哪些点对是错误的,即使用一个阈值来决定哪些单应性矩阵是合理的;然后将所有的图像扭曲到一个公共的图像平面上。

        通常,这里的公共平面为中心图像平面。一种方法是创建一个很大的图像,比如将图像中全部填充0,使其和中心图像平行,然后将所有的图像扭曲到上面。由于我们所有的图像是由照相机水平旋转拍摄的,因此我们可以使用一个较简单的步骤:将中心图像左边或者右边的区域填充为0,以便为扭曲的图像腾出空间。
图像拼接的几何原理:全景融合的 3D 几何解释,图像被投影到共同的拼接平面上(同一坐标系), 在拼接平面上实现全景融合。在拼接的应用中,其实可以简化理解为 2D图像的变换,叠加过程。
 

1.2基础流程

① 针对某个场景拍摄多张/序列图像

② 计算第二张图像与第一张图像之间的变换关系

③ 将第二张图像叠加到第一张图像的坐标系中

④ 变换后的融合/合成

⑤ 在多图场景中,重复上述过程

1.3计算图像之间的变换结构

• 提取特征点

• 生成描述子

• 特征匹配

• 计算变换结构?

1.4图像拼接的几何原理

 

 全景融合的 3D 几何解释

– 图像被投影到共同的拼接平面上(同一坐标系)

– 在拼接平面上实现全景融合

在拼接的应用中,其实可以简化理解为 2D图像的变换, 叠加过程 

1.5变换类型选择

•将两幅图像叠加在一起,需要采用什么模型?

• translation?(位移)

• rotation?(旋转)

• scale?(尺度/大小)

• affine?(仿射)

• Perspective?(透视)

1.6 2D 图像变换原理

 

1.7 图像映射流程

①针对两张 / 多张图像提取特征
②特征匹配
③根据图像变换特点,选取合适的变换结构
④根据 DLT 等方法计算变换结构
⑤采用正向 / 逆向映射,利用插值方式实现图像映 射变换

1.8 图像拼接整体流程

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

二、全景拼接测试

2.1 代码

 
import matplotlib.pyplot as plt
from numpy import *
from PIL import Image
 
from PCV.geometry import homography, warp
from PCV.localdescriptors import sift
from PCV.tools import reviseSize
 
# 批量修改图像尺寸
path = "D:\\DLsite\\picture\\"
reviseSize.startAction(path,2000,1800)  # 设置图像的宽、高
 
# 设置数据文件夹的路径
featname = [path + str(i + 1) + '.sift' for i in range(5)]
imname = [path + str(i + 1) + '.jpg' for i in range(5)]
 
# 提取特征并匹配使用sift算法
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])
 
# 可视化匹配
for i in range(4):
    im1 = array(Image.open(imname[i]))
    im2 = array(Image.open(imname[i + 1]))
    plt.figure()
    sift.plot_matches(im2, im1, l[i + 1], l[i], matches[i], show_below=True)
 
 
# 将匹配转换成齐次坐标点的函数
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
 
 
# 估计单应性矩阵
model = homography.RansacModel()
 
fp, tp = convert_points(1)
H_12 = homography.H_from_ransac(fp, tp, model)[0]  # im1 到im2 的单应性矩阵
 
fp, tp = convert_points(0)
H_01 = homography.H_from_ransac(fp, tp, model)[0]  # im0 到im1 的单应性矩阵
 
tp, fp = convert_points(2)  # 注意:点是反序的
H_32 = homography.H_from_ransac(fp, tp, model)[0]  # im3 到im2 的单应性矩阵
 
tp, fp = convert_points(3)  # 注意:点是反序的
H_43 = homography.H_from_ransac(fp, tp, model)[0]  # im4 到im3 的单应性矩阵
 
# 扭曲图像
delta = 2000  # 用于填充和平移
 
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)
 
plt.figure()
plt.imshow(array(im_42, "uint8"))
plt.axis('off')
plt.show()

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值