apap图像全景拼接

apap图像全景拼接文章目录基本原理图像配准关于最小割关于最大流apap的实现流程代码实现实验场景场景一场景二遇到的问题基本原理图像配准图像配准(apap)是将两张场景相关的图像进行映射,寻找其中的关系,多用在医学图像配准、图像拼接、不同摄像机的几何标定等方面,其研究也较为成熟。OpenCv中的stitching类就是使用了2007年的一篇论文(Automaticpanoramicimagestitchi…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

1、基本原理

1.1图像配准

图像配准(apap)是将两张场景相关的图像进行映射,寻找其中的关系,多用在医学图像配准、图像拼接、不同摄像机的几何标定等方面,其研究也较为成熟。OpenCv中的stitching类就是使用了2007年的一篇论文(Automatic panoramic image stitching using invariant features)实现的。虽然图像配准已较为成熟,但其实其精度、鲁棒性等在某些场合仍不足够,如光线差异很大的两张图片、拍摄角度差异很大的图片等。2013年,Julio Zaragoza等人发表了一种新的图像配准算法Apap(As-Projective-As-Possible Image Stitching with Moving DLT),该算法的效果还是不错的,比opencv自带的auto-stitch效果要好。而2015年也有一篇cvpr是介绍图像配准(Non-rigid Registration of Images with Geometric and Photometric Deformation by Using Local Affine Fourier-Moment Matching),其效果貌似很牛,但没有源码,难以检验。

1.2关于最小割

如图1所示,是一个有向带权图,共有4个顶点和5条边。每条边上的箭头代表了边的方向,每条边上的数字代表了边的权重。
G = < V, E >是图论中对图的表示方式,其中V表示顶点(vertex)所构成的集合,E表示边(edge)所构成的集合。顶点V的集合和边的集合E构成了图G(graph)。

在这里插入图片描述
那什么是最小割呢?
以图1为例,图1中顶点s表示源点(source),顶点t表示终点(terminal),从源点s到终点t共有3条路径:

s -> a -> t
s -> b -> t
s -> a -> b-> t

现在要求剪短图中的某几条边,使得不存在从s到t的路径,并且保证所减的边的权重和最小。相信大家能很快想到解答:剪掉边”s -> a”和边”b -> t”。
剪完以后的图如图2所示。此时,图中已不存在从s到t的路径,且所修剪的边的权重和为:2 + 3 = 5,为所有修剪方式中权重和最小的。
我们把这样的修剪称为最小割。
在这里插入图片描述

1.3关于最大流

什么是最大流呢?
继续以图1为例,假如顶点s源源不断有水流出,边的权重代表该边允许通过的最大水流量,请问顶点t流入的水流量最大是多少?
从顶点s到顶点t的3条路径着手分析,从源点s到终点t共有3条路径:

s -> a -> t:流量被边”s -> a”限制,最大流量为2
s -> b -> t:流量被边”b -> t”限制,最大流量为3
s -> a -> b-> t:边”s -> a”的流量已经被其他路径占满,没有流量

所以,顶点t能够流入的最大水流量为:2 + 3 = 5。
这就是最大流问题。所以,图1的最大流为:2 + 3 = 5。
细心的你可能已经发现:图1的最小割和最大流都为5。是的,经过数学证明可以知道,图的最小割问题可以转换为最大流问题。所以,算法上在处理最小割问题时,往往先转换为最大流问题。
那如何凭直觉解释最小割和最大流存在的这种关系呢?借用Jecvy博客的一句话:1.最大流不可能大于最小割,因为最大流所有的水流都一定经过最小割那些割边,流过的水流怎么可能比水管容量还大呢? 2.最大流不可能小于最小割,如果小,那么说明水管容量没有物尽其用,可以继续加大水流。

1.4apap的实现流程

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将图像切割成无数多个小方块,对每个小方块的变换矩阵逐一估计。

2、代码实现

# -*- 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 = ['C:\Python\Pictrue/apap/pic' + str(i + 1) + '.sift' for i in range(5)]  # 图片路径记得修改
imname = ['C:\Python\Pictrue/apap/pic' + 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()

3、实验场景

3.1场景一

固定拍摄位置,移动镜头拍摄多张图片,以中间图片为中心,实现图像的拼接融合(1)测试图片如下:
在这里插入图片描述
(2) sift特征匹配:
在这里插入图片描述
(3)全景图像拼接:在这里插入图片描述
实验小结:该组实验测试图片拍摄位置选定,在原地转换角度从左到右依次拍摄,因此图片基本处于同一水平。运行结果总体拼接效果不错,拼接痕迹不明显,边缘部分存在部分扭曲。在这个结果上,我认为除了跟拍摄角度有关联之外,还可以在图片纠正上做一些改进处理,可以使得到的结果效果更好。

3.2场景二

针对同一场景(视差变化大的场景),更换拍摄位置,实现图像的拼接融合
(1)测试图片如下:
在这里插入图片描述
(2)sift特征匹配:
在这里插入图片描述
(3)全景图片拼接:
在这里插入图片描述
实验小结:
在这组实验中,虽然大体拼接上了,但是在边缘拼接的地方出现了少量黑边。我认为,除了与算法本身有关的情况下,与拍摄角度也是有关系的。同时,拼接效果图上也出现了较为明显的拼接缝,由于两张图片角度相差过大,因此会更明显。

4、遇到的问题

(1)在实验过程中因为图片尺寸过大导致运行超时
解决方法:统一修改图片尺寸,并且一组图片尺寸应相同
(2)拼接图片有大部分黑色
解决方法:修改代码中delta的值,改小以后黑边明显减少,delta值合适时黑边可以消除在这里插入图片描述
(3)运行结果扭曲拼接效果不佳
解决方法:测试图片要按照拍摄顺序从右到左进行命名排列

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/190572.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • JS保留3位小数_保留一位小数表示精确到几位

    JS保留3位小数_保留一位小数表示精确到几位今天朋友面试,遇到一道面试题,写一个方法实现传入的参数数字保留三位小数//保留3位小数functionname(params){letnewpar=parseFloat(params);letreg=/^[0-9]+.?[0-9]*$/;if(reg.test(newpar)){letnewNum=newpar.toFixed(3);return…

    2022年10月31日
  • Python抛出异常_python抛出异常的作用

    Python抛出异常_python抛出异常的作用在工作中都会遇到异常报错问题,那么在这抽空码一些内容以作记录。在python中不同的异常可以用不同的类型(python中统一了类与类型,类型即类)去标识,不同的类对象标识不同的异常,一个异常标识一种错误AttributeError#试图访问一个对象没有的树形,比如foo.x,但是foo没有属性xIOError#输入/输出异常;基本上是无法打开文件ImportError#无法引入模块或包;基本上是路径问题或名称错误Indentati.

    2022年10月17日
  • java map 缓存_缓存用于

    java map 缓存_缓存用于缓存什么是缓存?平常的开发项目中,多多少少都会使用到缓存,因为一些数据我们没有必要每次查询的时候都去查询到数据库。缓存的使用场景:在Java应用中,对于访问频率高,更新少的数据,通常的方案是将这类数据加入缓存中,相对从数据库中读取,读缓存效率会有很大提升。在集群环境下,常用的分布式缓存有Redis等。但在某些业务场景上,可能不需要去搭建一套复杂的分布式缓存系统,在单机环境下,通常是会希望使用内部的缓存(LocalCache)。使用map缓存方案:基于ConcurrentHashMap实现数

  • pycharm全局查找一个关键词

    pycharm全局查找一个关键词PyCharm的FindinPath功能提供了全局查找功能,快捷键为Ctrl+Shift+F。Find则是在当前文件查找,快捷键为Ctrl+F。这两个个功能非常实用。FindinPath的使用:按快捷键Ctrl+Shift+F或从从菜单Edit-》Find-》FindinPath进入全局查找界面。如下图所示,在Texttofind输入要查找的内容,可以说某…

  • Django接口_django中几个html互相跳转

    Django接口_django中几个html互相跳转前言在RESTful规范中,有关版本的问题,用restful规范做开放接口的时候,用户请求API,系统返回数据。但是难免在系统发展的过程中,不可避免的需要添加新的资源,或者修改现有资源。因此,改动升

  • 生物AI插图免费领取[通俗易懂]

    生物AI插图免费领取[通俗易懂]人靠衣装,佛靠金装,科研成果靠图装。如今做科研不仅只需要会做实验,如何将成果美美地展示出来也是一门需要培养的技能。科研海报、项目PPT、论文插图、通路图……这些直接刺激人感官的展示都可以帮助升华我们的科研内容。之前我们介绍过如何用AdobeIllustrator对图形进行编辑、拼合、排版、简单模式图绘制,并录制了视频,放在了腾讯课堂,http://bioinfo.ke.qq.com,可免费观…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号