python全景拼接

版权声明:集美大学 https://blog.csdn.net/weixin_43361953/article/details/88833398

一、原理

(一) RANSAC算法

在之前的博客中有介绍过,SIFT算法的描述子稳健性很强,比Harris角点要来得精确,但是它的匹配正确率也并不是百分百的,会受到一些噪声点的干扰,有时就会因为不同地方有类似的图案导致匹配错误。那么RANSAC算法便是用来找到正确模型来拟合带有噪声数据的迭代方法。RANSAC通过反复取样,也就是从整个观测数据中随机抽一些数据估算模型参数之后看和所有数据误差有多大,然后取误差最小视为最好以及分离内群与离群数据。基本的思想是,数据中包含正确的点和噪声点,合理的模型应该能够在描述正确数据点的同时摒弃噪声点。

举个简单的例子,直线的拟合便是RANSAC的一个标准化体现:
在这里插入图片描述

  1. 在所有的点中随机选择两个点。
  2. 根据这两个点作一条直线。
  3. 设定一个阈值,计算在这条线上的点的数量,记为inliners。
  4. 根据最大的inliners那条线进行后续计算。

同理,RANSAC算法可以应用到其它模块中,例如用于图像变换的单应性矩阵的计算。
在拼接的过程中,通过将响速和单应矩阵H相乘,然后对齐次坐标进行归一化来实现像素间的映射。通过查看H中的平移量,我们可以决定应该将该图像填补到左边还是右边。当该图像填补到左边时,由于目标图像中点的坐标也变化了,所以在“左边”情况中,需要在单应矩阵中加入平移。

(二) 全景拼接

在之前的一篇博客介绍过SIFT匹配的方法,这里就不多写了,这次将其应用到图像拼接上,根据特征点匹配的方式,则利用这些匹配的点来估算单应矩阵(使用上面的RANSAC算法,也就是把其中一张通过个关联性和另一张匹配的方法。通过单应矩阵H,可以将原图像中任意像素点坐标转换为新坐标点,转换后的图像即为适合拼接的结果图像。可以简单分为以下几步:
1.根据给定图像/集,实现特征匹配。
2.通过匹配特征计算图像之间的变换结构。
3.利用图像变换结构,实现图像映射。
4.针对叠加后的图像,采用APAP之类的算法,对齐特征点。(图像配准)
5.通过图割方法,自动选取拼接缝。
6.根据multi-band blending策略实现融合。

(1)图像配准
图像配准是对图像进行变换,使变换后的图像能够在常见的坐标系中对齐。为了能够进行图像对比和更精细的图像分析,图像配准是一步非常重要的操作。图像配准的方法有很多,可以参考这里所提到的:https://blog.csdn.net/shenshen211/article/details/51613566
这里以APAP算法为例:
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将图像切割成无数多个小方块,对每个小方块的变换矩阵逐一估计。
转载自:https://blog.csdn.net/warrenwg/article/details/49759779
(2)图割方法
关于图割方法,有一篇博文我觉得讲的较好理解,这里给出地址供大家参考:
https://imlogm.github.io/图像处理/mincut-maxflow/
论文参考:https://static.aminer.org/pdf/PDF/000/292/851/demonstration_of_segmentation_with_interactive_graph_cuts.pdf
这里只简单介绍一下最小割和最大流两个算法的概念。
1.关于最小割
如下图所示,这是一个有向带权图,共有4个顶点和5条边。每条边上的箭头代表了边的方向,每条边上的数字代表了边的权重。
在这里插入图片描述
G = < V, E >是图论中对图的表示方式,其中V表示顶点(vertex)所构成的集合,E表示边(edge)所构成的集合。顶点V的集合和边的集合E构成了图G(graph)。
什么是最小割?
现在要求剪短图中的某几条边,使得不存在从s到t的路径,并且保证所减的边的权重和最小。那么很明显,剪掉边”s->a”和边”b->t”。我们就能得到下图:
在这里插入图片描述
图中已不存在从s到t的路径,且所修剪的边的权重和为:2 + 3 = 5,为所有修剪方式中权重和最小的。我们把这样的修剪称为最小割。
2.关于最大流
什么是最大流?
还是看最上面那张图,因为s->a只能通过2,那么s->a->t这条路的流量被限制在了2,同理,s->b->t被b->t限制,最多只能通过3的流量,所以s->t的流量总和为2+3=5,为这条路的最大流。

(3) 图像融合-blending

其实图像拼接完会发现在拼接的交界处有明显的衔接痕迹,存在边缘效应,因为光照色泽的原因使得图片交界处的过渡很糟糕,所以需要特定的处理解决这种不自然。那么这时候可以采用blending方法。multi-band blending是目前图像融和方面比较好的方法。具体可以参考论文:
http://xueshu.baidu.com/usercenter/paper/show?paperid=90e9c78b74047776a82af68a9c836e71&site=xueshu_se&hitarticle=1
原始论文中采用的方法是直接对带拼接的两个图片进行拉普拉斯金字塔分解,而后一半对一半进行融合。在opencv内部已经实现了multi-band blending,但是本篇中没有做相关尝试。
相关参考:https://blog.csdn.net/real_myth/article/details/52343612

(二)运行结果与分析

1.遇到的问题与解决方案
(1)在这里插入图片描述
代码在生成sift文件后便停止运行报错,以上显示不符合合格的验收标准,换句话说,就是你的图片无法正确地匹配,使用的图片如下:
在这里插入图片描述
这里要说明的一点是,在这次测试中我使用的图片是沿着路段一路走下来拍摄的,并不是在原地转换角度拍摄得到的,而且拍摄出来的效果并不是很水平,有可能是导致报错的原因。我便重新拍摄了一组图片测试,看看具体原因。

(2)
这次测试的图片如下:
在这里插入图片描述
运行快结束时,出现了如下错误:
在这里插入图片描述
出现了MemoryError这个错误,这个错误通常是在处理大数据时因为内存不够而产生的,那么在这里我猜测是因为图片的规格超过了所能处理的范围,所以我便将图片的尺寸调小了一些,再次运行时发现问题解决,那么可以确定失败是受图片规格影响。

2.成功效果

(1)室外光线较足的情况
在这里插入图片描述
在这里插入图片描述
可以看到,图片的拼接成功率达到了90%,图片虽然拼接成功了,但是旁边却出现了黑色部分,这是因为图片无法填充满,可以试试拍摄时角度变化大一些。除此之外,可以看到在图片的拼接交界处有明显的“裂缝”,有色差,部分地方有一些歪斜,可以尝试通过上面所说的blending进行融合来达到更好的效果。

(2)室内光线较暗的情况

测试图片如下:
在这里插入图片描述
匹配效果如下:
在这里插入图片描述
结果1:
在这里插入图片描述
结果2:
在这里插入图片描述
这一组图片在靠窗位置光线较足,靠内位置光线较暗,存在一些光线的落差,可以看到在这次拼接完成的结果1有一些变形扭曲,拼接率有80%,虽然拼接上了但是效果并没有很好,同样的,仍存在黑边,但是相对上一组图片结果要来得少一些,拼接痕迹也较少。但是因为这张结果和原图区别较大,和算法有一些关系,我便重新拼接了一次,得到结果2,这次拼接中明显效果好了很多,但是总体的角度仍有一些扭曲,在这个结果上,我认为除了跟拍摄角度有关联之外,还可以在图片纠正上做一些改进处理,可以使得到的结果效果更好。若是想法有误希望大家可以指正讨论。

(3)室内室外情况对比
在这里插入图片描述

(三)代码

在这里给出python主程序代码,我使用的版本为python2.7,若是python3的版本还需要调整一些相关的包的导入和代码形式。

# -*- coding: utf-8 -*-
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 = ['image3/c'+str(i+1)+'.sift' for i in range(5)] #图片路径记得修改
imname = ['image3/c'+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 

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)


figure()
imshow(array(im_42, "uint8"))
axis('off')
savefig("example1.png",dpi=300)
show()

本次博文部分参考:《python计算机视觉编程》–Jan Erik Solem

猜你喜欢

转载自blog.csdn.net/weixin_43361953/article/details/88833398