一、RANSAC算法
1.1 RANSAC算法简介
RANSAC (随机一致性采样)是一种迭代算法,该算法从一组包含“外点(outlier)”的观测数据中估计数学模型的参数。“外点”指观测数据中的无效数据,通常为噪声或错误数据,比如图像匹配中的误匹配点和曲线拟合中的离群点。与“外点”相对应的是“内点(inlier)”,即用来估计模型参数的有效数据。因此,RANSAC也是一种“外点”检测算法。此外,RANSAC算法是一种非确定算法,它只能在一定概率下产生可信的结果,当迭代次数增加时,准确的概率也会增加。RANSAC算法是用来找到正确模型来拟合带有噪声数据的迭代方法。
1.2 算法基本思想和流程
RANSAC是通过反复选择数据集去估计出模型,一直迭代到估计出认为比较好的模型。具体的实现步骤可以分为以下几步:
(1)随机采样K个点,K是求解模型参数的最少点个数(对于直线拟合来说就是两个点(两点确定一条直线),对于拟合圆就是3个点)
(2)使用采样出的k个点估计模型参数,得到数据模型;
(3)将所有数据带入这个模型,计算出“内点”的数目;(累加在一定误差范围内的适合当前迭代得出的模型的数据);
(4)比较当前模型和之前推出的最好的模型的“内点“的数量,记录最大“内点”数的模型参数和“内点”数;
(5)重复1-4步,直到迭代结束或者当前模型已经足够好了(“内点数目大于一定数量”)。
二:图像映射与全景拼接
基本流程
① 针针对某个场景拍摄多张/序列图像;
② 计算第二张图像与第一张图像之间的变换关系;
③ 将第二张图像叠加到第一张图像的坐标系中;
④ 变换后的融合/合成;
⑤ 在多图场景中,重复上述过程;
变换类型选择
参数求解:
针对不同问题,需要不同的多少对匹配特征才能计算出模型参数。
图像拼接流程:
(1)根据给定图像/集, 实现特征匹配
(2)通过匹配特征计算图像之间的变换结构
(3)利用图像变换结构, 实现图像映射
(4)针对叠加后的图像, 采用APAP算法对齐特征点
(5)通过图割方法, 自动选取拼接缝
(6)根据multi-band bleing策略实现融合
代码实现:
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
from numpy import *
from PIL import Image
from newPCV.geometry import homography, warp
from newPCV.Localdescriptors import sift
from newPCV.tools import reviseSize
# 批量修改图像尺寸
path = "D:\\python\\RRJ\\pycharmproject\\全景拼接\\vistaImg\\Imgdemo3\\"
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()
结果展示:
SIFT特征匹配:
中间有一条明显的拼接缝,实际效果还是不错 基本还原