目录
一、引入
1.1 特征匹配
在上篇博客中已经对图像到图像的映射(SIFT算法,Harris角点检测算法等)、地理标记图像进行了详细的介绍,引路:【Python计算机视觉】图像到图像的映射(单应性变换、图像扭曲)
1.2 问题:Bad Example
1.2.1 “鬼影”
- 鬼影问题:图像拼接后出现重影;
- “鬼影”的产生原因:图像映射是全局的单应性变换,但是图像场景中各个物体往往具有不同的深度,如果采用处于不同深度物体的特征点进行全局单应性变换,由于此时图像中的物体无法满足近似于同一平面的条件,计算得到的单应性矩阵会有较大的误差,仅仅由一个全局的单应性变换无法完全描述两幅图像之间的变换关系。
1.2.2 错误匹配的干扰
- 在进行SIFT特征点匹配时,往往会出现一个问题:如果图像的噪声太大,就会使得特征点的匹配发生了偏差,匹配到了错误的点,这种不好的匹配效果,会对后面的图像拼接产生很大的影响。
- ①错配特征带来的影响。
- ②结构化影响。
1.3 解决:Simple Example
1.3.1 拟合消除噪声点
要消除特征点的噪声,可以通过拟合特征点,找到一个合适的拟合线,然后消除噪声点。
- 直线拟合:
给定若干二维空间中的点,求直线y=ax+b,使得该直线对空间点的拟合误差最小:
①随机选择两个点;
②根据该点构造直线;
③给定阈值【设置一个超参数】,计算inliers数量【即比较近的点】
- 圆拟合:
三点可以确定一个圆,随机选取三个点,确定经过这三个点的圆,然后计算这个圆上的点的数量,达到指定阈值就可以确定要拟合的圆。
- 复杂方程拟合:
通过求解多项式,解出未知参数,得到曲线上的点,确定拟合曲线。
1.3.2 参数求解:RAndom SAmple Consensus
对于这些坏的匹配点,我们应该怎么办呢?
- 不断选择一对匹配的特征点,然后计算由这对特征点确定的数学模型的inliers。
- 当inliers达到阈值条件,拟合出了数学模型后,便计算两幅对应所有特征点的偏移量,求出偏移量的平均值,进行图像拼接。
1.3.3 APAP算法
- 2013年,Julio Zaragoza等人发表了一种新的图像配准算法APAP(As-Projective-As-Possible Image Stitching with Moving DLT)解决鬼影现象可以采用APAP算法。
- APAP算法流程:
①SIFT得到两幅图像的匹配点对;
②通过RANSAC剔除外点,得到N对内点;
③利用DLT和SVD计算全局单应性;
④将源图划分网格,取网格中心点,计算每个中心点和源图上内点之间的欧式距离和权重;
⑤将权重放到DLT算法的A矩阵中,构建成新的W*A矩阵,重新SVD分解,自然就得到了当前网格的局部单应性矩阵;
⑥遍历每个网格,利用局部单应性矩阵映射到全景画布上,就得到了APAP变换后的源图;
⑦最后就是进行拼接线的加权融合。
1.3.4 寻找最佳拼接缝
- 很多情况下,使用一个全局单应变换并不能准确对齐图像,需要一些后处理来削弱拼接的痕迹,比如寻找最佳拼接缝【如下图所示】。
- 如何找?
使用最大流最小割算法寻找拼接缝:【找最小割与找最大流在本质上是等价的】
1.4 图像拼接
1.4.1 整体流程
- 根据给定图像/集,实现特征匹配;
- 通过匹配特征计算图像之间的变换结构;
- 利用图像变换结构,实现图像映射;
- 针对叠加后的图像,采用APAP之类的算法,对其特征点;
- 通过图割方法,自动选取拼接缝;
- 根据multu-blending策略实现融合。
1.4.2 multi-blending策略
- multi-band bleing策略采用Laplacian(拉普拉斯)金字塔,通过对相邻两层的高斯金字塔进行差分,将原图分解成不同尺度的子图,对每一个之图进行加权平均,得到每一层的融合结果,最后进行金字塔的反向重建,得到最终融合效果过程,融合之后可以得到较好的拼接效果。
- 如下图所示:
二、全景拼接
2.1 RANSAC
- RANSAC 是“RANdom SAmple Consensus”(随机一致性采样)的缩写。该方法是用来找到正确模型来拟合带有噪声数据的迭代方法。给定一个模型,例如点集之间的单应性矩阵,RANSAC 基本的思想是,数据中包含正确的点和噪声点,合理的模型应该能够在描述正确数据点的同时摒弃噪声点。
- RANSAC的基本假设:
①数据由“局内点”组成,例如:数据的分布可以用一些模型参数来解释;
②“局外点”是不能适应该模型的数据;
③除此之外的数据属于噪声。 - RANSAC算法基本思想:(如上面直线拟合)
①随机选取两个点;
②根据随机选取的两个点构造方程y=ax+b;
③将所有的数据点套到这个模型中计算误差;
④给定阈值,计算inliers数量;
⑤不断重复上述过程,直到达到一次迭代次数后,选择inliers数量最多的直线方程,作为问题的解。 - RANSAC求解单应性矩阵
①随机选择四对匹配特征(选择4对特征点因为单应性矩阵有8个自由度,至少需要8个线性方程求解,对应到点位置信息上,一组点对可以列出两个方程,则至少包含4组匹配点对)
②根据直接线性变换解法DLT计算单应性矩阵H(唯一解)
③对所匹配点,计算映射误差
④根据误差阈值,确定inliers
⑤针对最大的inliers集合,重新计算单应性矩阵H - RANSAC 的标准例子:用一条直线拟合带有噪声数据的点集。简单的最小二乘在该例子中可能会失效,但是 RANSAC 能够挑选出正确的点,然后获取能够正确拟合的直线。
使用RANSAC算法用一条直线来拟合包含噪声点数据点集如下(源自http://www.scopy.org/Cookbook/RANSAC)
【代码】
import numpy
import scipy # use numpy if scipy unavailable
import scipy.linalg # use numpy if scipy unavailable
## Copyright (c) 2004-2007, Andrew D. Straw. All rights reserved.
## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions are
## met:
## * Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimer.
## * Redistributions in binary form must reproduce the above
## copyright notice, this list of conditions and the following
## disclaimer in the documentation and/or other materials provided
## with the distribution.
## * Neither the name of the Andrew D. Straw nor the names of its
## contributors may be used to endorse or promote products derived
## from this software without specific prior written permission.
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
def ransac(data,model,n,k,t,d,debug=False,return_all=False):
"""fit model parameters to data using the RANSAC algorithm
This implementation written from pseudocode found at
http://en.wikipedia.org/w/index.php?title=RANSAC&oldid=116358182
{
{
{
Given:
data - a set of observed data points
model - a model that can be fitted to data points
n - the minimum number of data values required to fit the model
k - the maximum number of iterations allowed in the algorithm
t - a threshold value for determining when a data point fits a model
d - the number of close data values required to assert that a model fits well to data
Return:
bestfit - model parameters which best fit the data (or nil if no good model is found)
iterations = 0
bestfit = nil
besterr = something really large
while iterations < k {
maybeinliers = n randomly selected values from data
maybemodel = model parameters fitted to maybeinliers
alsoinliers = empty set
for every point in data not in maybeinliers {
if point fits maybemodel with an error smaller than t
add point to alsoinliers
}
if the number of elements in alsoinliers is > d {
% this implies that we may have found a good model
% now test how good it is
bettermodel = model parameters fitted to all points in maybeinliers and alsoinliers
thiserr = a measure of how well model fits these points
if thiserr < besterr {
bestfit = bettermodel
besterr = thiserr
}
}
increment iterations
}
return bestfit
}}}
"""
iterations = 0
bestfit = None
besterr = numpy.inf
best_inlier_idxs = None
while iterations < k:
maybe_idxs, test_idxs = random_partition(n,data.shape[0])
maybeinliers = data[maybe_idxs,:]
test_points = data[test_idxs]
maybemodel = model.fit(maybeinliers)
test_err = model.get_error( test_points, maybemodel)
also_idxs = test_idxs[test_err < t<