目录
1.RANSAC简介
RANSAC(Random Sample Consensus)随机采样一致算法是根据一组包含异常数据的样本数据集,计算出数据的数学模型参数,得到有效样本数据的算法。
1.1 算法基本思想和流程
RANSAC是通过反复选择数据集去估计出模型,一直迭代到估计出认为比较好的模型。具体的实现步骤可以分为以下几步:
- 选择出可以估计出模型的最小数据集;(对于直线拟合来说就是两个点,对于计算Homography矩阵就是4个点)
- 使用这个数据集来计算出数据模型;
- 将所有数据带入这个模型,计算出“内点”的数目;(累加在一定误差范围内的适合当前迭代推出模型的数据)
- 比较当前模型和之前推出的最好的模型的“内点“的数量,记录最大“内点”数的模型参数和“内点”数;
- 重复1-4步,直到迭代结束或者当前模型已经足够好了(“内点数目大于一定数量”)。
1.2 RANSAC 求解单应矩阵
RANSAC 循环:
- 随机选择四对匹配特征
- 根据DLT计算单应矩阵 H (唯一解)
- 对所有匹配点,计算映射误差ε= ||p i ’, H p i ||
- 根据误差阈值,确定inliers(例如3-5像素)
- 针对最大inliers集合,重新计算单应矩阵 H
2.图像映射与全景拼接
首先是在连续图像对间使用SIFT特征寻找匹配对应点对,SIFT是具有较强稳健性的描述子,能够比其他描述子产生更少的错误点,但是该方法仍不是很完美;使用RANSAC算法估计出图像间的单应性矩阵,判定哪些点对是正确的,哪些点对是错误的,即使用一个阈值来决定哪些单应性矩阵是合理的;然后将所有的图像扭曲到一个公共的图像平面上。
基于SIFT特征匹配的RNASAC在上一篇博客也有相应实验的叙述,可参见博客SIFT理解与应用。
通常,这里的公共平面为中心图像平面。一种方法是创建一个很大的图像,比如将图像中全部填充0,使其和中心图像平行,然后将所有的图像扭曲到上面。由于我们所有的图像是由照相机水平旋转拍摄的,因此我们可以使用一个较简单的步骤:将中心图像左边或者右边的区域填充为0,以便为扭曲的图像腾出空间。
图像拼接的几何原理:全景融合的 3D 几何解释,图像被投影到共同的拼接平面上(同一座标系), 在拼接平面上实现全景融合。在拼接的应用中,其实可以简化理解为 2D图像的变换,叠加过程。
基础流程
① 针对某个场景拍摄多张/序列图像
② 计算第二张图像与第一张图像之间的变换关系
③ 将第二张图像叠加到第一张图像的座标系中
④ 变换后的融合/合成
⑤ 在多图场景中,重复上述过程
2.1 计算第二张图像与第一张图像之间的变换关系
(1)变换类型选择
将两幅图像叠加在一起,选择需要采用模型,如位移、旋转、尺度大小、仿射和透视等。
(2)2D 图像变换原理:
图像滤波: 改变图像的像素点取值范围
图像变换: 改变图像的座标取值范围
(3)2D 图像变换类型
#DoF | Preserves | Icon | |
平移 | 2 | orientation | |
旋转+平移 (刚体) |
3 | lengths | |
相似 |
4 | angles | |
仿射
|
6 | parallelism | |
单应性变换
|
8 | straight lines |
(4)参数求解:平移问题、仿射变换和单应性变换等
2.2 将第二张图像叠加到第一张图像的座标系中
2D 图像变换
给定变换模型 x'= h(x) ,以及输入图像f(x), 根据f(x)计算变换后的图像 g(x')= f(h(x))。前向映射:对于 f(x) 中的每个像素 x,根据变换模型计算相应的映射座标x' = h(x),并将x的像素值赋给 g(x')。逆向映射:对于 g(x')中的每个像素 x',根据变换模型计算相应的映射座标 x = h -1 (x'),并将x的像素值赋给g(x')。
2.3. 图像映射小结
流程:
① 针对两张/多张图像提取特征
② 特征匹配
③ 根据图像变换特点,选取合适的变换结构
④ 根据DLT等方法计算变换结构
⑤ 采用正向/逆向映射,利用插值方式实现图像映射变换
2.4 图像拼接整体流程
- 根据给定图像/集, 实现特征匹配
- 通过匹配特征计算图像之间的变换结构
- 利用图像变换结构, 实现图像映射
- 针对叠加后的图像, 采用APAP算法对齐特征点
- 通过图割方法, 自动选取拼接缝
- 根据multi-band bleing策略实现融合
(1)针对叠加后的图像, 采用APAP算法对齐特征点
对两张图片进行SIFT特征匹配, 然后对SIFT特征匹配得到的特征点使用 RANSAC算法进行去除错误的特征点对。筛选后的特征点基本能够一一对应。使用DLT算法,将剩下的特征点对进行透视变换矩阵的估计。因为得到的透视变换矩阵是基于全局特征点对进行的,即一个刚性的单应性矩阵完成配准。为提高配准的精度,Apap将图像切割成无数多个小方块,对每个小方块的变换矩阵逐一估计。非常依赖于特征点对。若图像高频信息较少,特征点对过少,配准将完全失效,并且对大尺度的图像进行配准,其效果也不是很好,一切都决定于特征点对的数量。
(2)通过图割方法, 自动选取拼接缝
寻找代价最小的分割,典型算法是最小割最大流算法,将图内带权值的看作带有流量值的管道,将最大量水从源点送到汇点。
(3)根据multi-band bleing策略实现融合
融合目的在于拼缝消除, Multi-Band能够达到比较好的融合效果,但是效率低,采用Laplacian(拉普拉斯)金字塔,通过对相邻两层的高斯金字塔进行差分,将原图分解成不同尺度的子图,对每一个之图进行加权平均,得到每一层的融合结果,最后进行金字塔的反向重建,得到最终融合效果过程。
3.实验分析
3.1 代码实现
# -*- coding: utf-8 -*-
from pylab import *
from numpy import *
from PIL import Image
from PCV.geometry import homography, warp
from PCV.localdescriptors import sift
featname = ['data/pic1/c' + str(i + 1) + '.sift' for i in range(3)]
imname = ['data/pic1/c' + 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])
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)
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)
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] # im 1 to 2
fp, tp = convert_points(0)
H_01 = homography.H_from_ransac(fp, tp, model)[0] # im 0 to 1
delta = 1000 # 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')
show()
3.2 实验分析
3.2.1 实验场景一
针对固定点位拍摄多张图片,以中间图片为中心
小结:
从该全景拼接图可以看出左边的拼接效果较好,虽然因图片曝光度的不同存在一定的边缘效应,但特征点能相对应,两图的拼接没有扭曲或者其他的问题;而全景拼接图的右边,虽然实现了拼接在一起,但是右边的图片被变大扭曲了,边缘楼房明显倾斜变形,且越右边变形的越厉害,右边的图片整个都被拉伸扭曲变形。从SIFT特征匹配的结果来看,两两匹配得到的特征点很多,匹配效果也很好,但是最后的全景拼接图只有左边能够实现较好的点对点拼接。
3.2.2 实验场景二
针对同一场景(选取视差变化大的场景,也就是有近景目标),更换拍摄位置
小结:
该全景拼接图相对于实验(1)得到的全景拼接图效果要好,左边拼接依然存在曝光度不同导致的边缘效应,但是图片没有被大幅度扭曲,只是在花盆左后面旁边的瓷砖拼接有点扭曲,两张图片过渡不连续存在的拼接缝隙;此时的全景拼接图没有再出现右边扭曲变形的情况,反而因为曝光度的相似性,特征点能一一对应得到了较好的拼接效果。
3.3 实验总结
- 图片全景拼接把几张图片拼接在一起,先选取一个中间图像作为中心图像,也就是希望将其他图像变成的图像,由于匹配是从最右边的图像开始计算,所以需要注意将图片的顺序进行颠倒(即由1,2,3,4,5的存放顺序变为5,4,3,2,1),使得从左边图像开始扭曲,将所有图像扭曲到一个公共的图像平面上。
- 图像右边的黑色区域可以通过减小代码中的delta相应减小,但不能设置的过小,delta值太小会使得图片不能完整呈现,即可能存在部分图片被截取了。
- 两个实验场景我选取的都是建筑物较多的室外场景,背景比较复杂,但也因为繁复的建筑物背景可以检测出较多的特征点,总结两个实验都是左边的匹配效果较佳,即特征点能够较好的实现一一对应。
- 曝光度的不同容易导致拼接全景图存在边缘效应。
4.错误
错误提示为ImportError: No module named delaunay。
解决:
1.先进入到进入到python目录下的Lib\site-packages\PCV\geometry\warp.py,把黑色方框中的
import matplotlib.delaunay as md
改为红色方框的
from scipy.spatial import Delaunay
2.把红色方框的...triangulate_points(x,y)里面的代码替换成
tri = Delaunay(np.c_[x,y]).simplices