图像的拼接----RANSAC算法
一、全景拼接的原理
1.RANSAC算法介绍
RANSAC算法的基本假设是样本中包含正确数据(inliers,可以被模型描述的数据),也包含异常数据(outliers,偏离正常范围很远、无法适应数学模型的数据),即数据集中含有噪声。这些异常数据可能是由于错误的测量、错误的假设、错误的计算等产生的。同时RANSAC也假设,给定一组正确的数据,存在可以计算出符合这些数据的模型参数的方法。
2.使用RANSAC算法来求解单应性矩阵
在进行图像拼接时,我们首先要解决的是找到图像之间的匹配的对应点。通常我们采用SIFT算法来实现特征点的自动匹配,SIFT算法的具体内容参照我的上一篇博客 。SIFT是具有很强稳健性的描述子,比起图像块相关的Harris角点,它能产生更少的错误的匹配,但仍然还是存在错误的对应点。所以需要用RANSAC算法,对SIFT算法产生的128维特征描述符进行剔除误匹配点。
由直线的知识点可知,两点可以确定一条直线,所以可以随机的在数据点集中选择两点,从而确定一条直线。然后通过设置给定的阈值,计算在直线两旁的符合阈值范围的点,统计点的个数inliers。inliers最多的点集所在的直线,就是我们要选取的最佳直线。
RANSAC算法就是在一原理的基础上,进行的改进,从而根据阈值,剔除错误的匹配点。首先,从已求得的匹配点对中抽取几对匹配点,计算变换矩阵。然后对所有匹配点,计算映射误差。接着根据误差阈值,确定inliers。最后针对最大inliers集合,重新计算单应矩阵 H。
3.基本思想描述:
①考虑一个最小抽样集的势为n的模型(n为初始化模型参数所需的最小样本数)和一个样本集P,集合P的样本数#(P)>n,从P中随机抽取包含n个样本的P的子集S初始化模型M;
②余集SC=P\S中与模型M的误差小于某一设定阈值t的样本集以及S构成S*。S*认为是内点集,它们构成S的一致集(Consensus Set);
③若#(S*)≥N,认为得到正确的模型参数,并利用集S*(内点inliers)采用最小二乘等方法重新计算新的模型M*;重新随机抽取新的S,重复以上过程。
④在完成一定的抽样次数后,若未找到一致集则算法失败,否则选取抽样后得到的最大一致集判断内外点,算法结束。
4.图像拼接
使用RANSAC算法估计出图像间的单应性矩阵,将所有的图像扭曲到一个公共的图像平面上。通常,这里的公共平面为中心图像平面。一种方法是创建一个很大的图像,比如将图像中全部填充0,使其和中心图像平行,然后将所有的图像扭曲到上面。由于我们所有的图像是由照相机水平旋转拍摄的,因此我们可以使用一个较简单的步骤:将中心图像左边或者右边的区域填充为0,以便为扭曲的图像腾出空间。
二、实验
1.源代码
# -*- coding: utf-8 -*-
from pylab import *
from PIL import Image
from PCV.geometry import homography, warp
from PCV.localdescriptors import sift
# set paths to data folder
featname = ['C:/Users/LE/PycharmProjects/untitled/hh/' + str(i + 1) + '.sift' for i in range(4)]
imname = ['C:/Users/LE/PycharmProjects/untitled/hh/' + str(i + 1) + '.jpg' for i in range(4)]
# extract features and match
l = {}
d = {}
for i in range(4):
sift.process_image(imname[i], featname[i])
l[i], d[i] = sift.read_features_from_file(featname[i])
matches = {}
for i in range(3):#2
matches[i] = sift.match(d[i + 1], d[i])
# visualize the matches (Figure 3-11 in the book)
for i in range(3):#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)
# 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
# warp the images
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()
原文地址:https://www.cnblogs.com/lhx0814/p/12559835.html
- Python之dict(或对象)与json之间的互相转化
- datetime.date(2014, 4, 25) is not JSON serializable
- Linux下PAM模块学习总结
- 统计文件中出现的单词次数
- EF批量操作数据与缓存扩展框架
- 前端面试题:JS中的let和var的区别
- 虚拟机字节码执行引擎
- 快速傅里叶变换(FFT)详解
- SQLServer 数据库镜像+复制切换方案
- Handler源码分析
- STM32-对芯片启动读保护,实现加密(详解)
- Django+xadmin打造在线教育平台(一)
- “无法删除数据库,因为该数据库当前正在使用”问题解决
- HDU 4372 Count the Buildings
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SpringMVC源码学习(三) - 请求处理的流程
- Hadoop框架:集群模式下分布式环境搭建
- 微服务 Hystrix 实现服务熔断
- 微服务 Gateway 的基本配置
- 有赞营销逆向域的探索与实践
- RabbitMQ 启动报错:Error: unable to perform an operation on node ‘rabbit@***‘. Please see diagnostics...
- MySQL|查询字段数量多少对查询效率的影响
- 如果MySQL事务中发生了网络异常?
- MySQL|update字段为相同的值是否会记录binlog
- 微服务配置 Config 与消息总线
- 贷款违约预测-Task5 模型融合
- Python字符串
- MYSQL logstash 同步数据到es的几种方案对比以及每种方案数据丢失原因分析。
- 手写“SpringBoot”:几十行代码基于Netty搭建一个 HTTP Server
- SpringCloud Sleuth 分布式请求链路追踪