1.SIFT

在原图上提取描述子并可视化得到如下结果:

得到描述子后进行匹配:

构造单应性矩阵:

from PCV.geometry import homography, warpmodel = homography.RansacModel() 

将匹配转换成齐次坐标点:

# 将匹配转换成齐次坐标点的函数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 elsewherefp = vstack([fp[1],fp[0],fp[2]])tp = vstack([tp[1],tp[0],tp[2]])return fp,tpfp,tp = convert_points(0)

获取单应性矩阵和对应该单应性矩阵的正确点对:

H_01 = homography.H_from_ransac(fp,tp,model)[0]
class RansacModel(object):""" 用于测试单应性矩阵的类,其中单应性矩阵是由网站http://www.scipy.org/Cookbook/RANSAC上的ransac.py计算出来的"""def __init__(self,debug=False):self.debug = debugdef fit(self, data):"""计算选取的4个对应的单应性矩阵 """#将其转置,来调用H_from_points()计算单应性矩阵data = data.T# 映射的起始点fp = data[:3,:4]#映射的目标点tp = data[3:,:4]#计算单应性矩阵然后返回return H_from_points(fp,tp)def get_error( self, data, H):"""对所有的对应计算单应性矩阵,然后对每个变换后的点,返回响应的误差"""data = data.T#映射的起始点fp = data[:3]#映射的目标点tp = data[3:]# 变换fpfp_transformed = dot(H,fp)# 归一化齐次坐标fp_transformed = normalize(fp_transformed)# 返回每个点的误差return sqrt( sum((tp-fp_transformed)**2,axis=0) )def H_from_ransac(fp,tp,model,maxiter=1000,match_theshold=10):""" 使用RANSAC稳健性聚集点对应间的单应性矩阵H(ransac.py为从http://www.scipy.org/Cookbook/RANSAC下载的版本).输入: 齐次坐标表示的点fp,tp (3*n数组) """from PCV.tools import ransac# 对应点组data = vstack((fp,tp))# 计算H,并返回H,ransac_data = ransac.ransac(data.T,model,4,maxiter,match_theshold,10,return_all=True)return H,ransac_data['inliers']

切割以及拼接图像:

delta = 2000 # for padding and translationim1 = array(Image.open(imname[0]), "uint8")im2 = array(Image.open(imname[1]), "uint8")###
im_12 = warp.panorama(H_01,im1,im2,delta,delta)##

其中warp.panorama()用于图像扭曲

def panorama(H,fromim,toim,padding=2400,delta=2400):""" 使用单应性矩阵H(使用RANSAC稳健性估计得出),协调两幅图像,创建水平全景图。结果为一幅和toim具有相同高度的图像。padding指定填充像素的数目,delta指定额外的平移量""" #检查图像是灰度图像,还是彩色图像is_color = len(fromim.shape) == 3# 用于geometric_transform()的单应性变换def transf(p):p2 = dot(H,[p[0],p[1],1])return (p2[0]/p2[2],p2[1]/p2[2])if H[1,2]<0: # fromim在右边print 'warp - right'# 变换fromimif is_color:# 在目标图像的右边填充0toim_t = hstack((toim,zeros((toim.shape[0],padding,3))))fromim_t = zeros((toim.shape[0],toim.shape[1]+padding,toim.shape[2]))for col in range(3):fromim_t[:,:,col] = ndimage.geometric_transform(fromim[:,:,col],transf,(toim.shape[0],toim.shape[1]+padding))else:# 在目标图像的右边填充0toim_t = hstack((toim,zeros((toim.shape[0],padding))))fromim_t = ndimage.geometric_transform(fromim,transf,(toim.shape[0],toim.shape[1]+padding)) else:print 'warp - left'#为了补偿填充效果,在左边加入平移量H_delta = array([[1,0,0],[0,1,-delta],[0,0,1]])H = dot(H,H_delta)#fromim变换if is_color:# 在目标图像的左边填充0toim_t = hstack((zeros((toim.shape[0],padding,3)),toim))fromim_t = zeros((toim.shape[0],toim.shape[1]+padding,toim.shape[2]))for col in range(3):fromim_t[:,:,col] = ndimage.geometric_transform(fromim[:,:,col],transf,(toim.shape[0],toim.shape[1]+padding))else:# 在目标图像的左边填充0toim_t = hstack((zeros((toim.shape[0],padding)),toim))fromim_t = ndimage.geometric_transform(fromim,transf,(toim.shape[0],toim.shape[1]+padding))# 协调后返回(将fromim放在toim上)if is_color:# 所有非黑像素alpha = ((fromim_t[:,:,0] * fromim_t[:,:,1] * fromim_t[:,:,2] ) > 0)for col in range(3):toim_t[:,:,col] = fromim_t[:,:,col]*alpha + toim_t[:,:,col]*(1-alpha)else:alpha = (fromim_t > 0)toim_t = fromim_t*alpha + toim_t*(1-alpha)return toim_t

完整代码如下:

# -*- coding: utf-8 -*-
"""
Created on Sat Apr 23 15:36:26 2022
@author: 95490
"""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.
"""def read_features_from_file(filename):"""读取特征属性值,然后将其以矩阵的形式返回"""f = loadtxt(filename)return f[:,:4], f[:,4:] #特征位置,描述子def write_featrues_to_file(filename, locs, desc):"""将特征位置和描述子保存到文件中"""savetxt(filename, hstack((locs,desc)))def plot_features(im, locs, circle=False):"""显示带有特征的图像输入:im(数组图像),locs(每个特征的行、列、尺度和朝向)"""def draw_circle(c,r):t = arange(0,1.01,.01)*2*pix = r*cos(t) + c[0]y = r*sin(t) + c[1]plot(x, y, 'b', linewidth=2)imshow(im)if circle:for p in locs:draw_circle(p[:2], p[2])else:plot(locs[:,0], locs[:,1], 'ob')axis('off')def match(desc1, desc2):"""对于第一幅图像中的每个描述子,选取其在第二幅图像中的匹配输入:desc1(第一幅图像中的描述子),desc2(第二幅图像中的描述子)"""desc1 = array([d/linalg.norm(d) for d in desc1])desc2 = array([d/linalg.norm(d) for d in desc2])dist_ratio = 0.6desc1_size = desc1.shapematchscores = zeros((desc1_size[0],1),'int')desc2t = desc2.T #预先计算矩阵转置for i in range(desc1_size[0]):dotprods = dot(desc1[i,:],desc2t) #向量点乘dotprods = 0.9999*dotprods# 反余弦和反排序,返回第二幅图像中特征的索引indx = argsort(arccos(dotprods))#检查最近邻的角度是否小于dist_ratio乘以第二近邻的角度if arccos(dotprods)[indx[0]] < dist_ratio * arccos(dotprods)[indx[1]]:matchscores[i] = int(indx[0])return matchscoresdef match_twosided(desc1, desc2):"""双向对称版本的match()"""matches_12 = match(desc1, desc2)matches_21 = match(desc2, desc1)ndx_12 = matches_12.nonzero()[0]# 去除不对称的匹配for n in ndx_12:if matches_21[int(matches_12[n])] != n:matches_12[n] = 0return matches_12def appendimages(im1, im2):"""返回将两幅图像并排拼接成的一幅新图像"""#选取具有最少行数的图像,然后填充足够的空行rows1 = im1.shape[0]rows2 = im2.shape[0]if rows1 < rows2:im1 = concatenate((im1, zeros((rows2-rows1,im1.shape[1]))),axis=0)elif rows1 >rows2:im2 = concatenate((im2, zeros((rows1-rows2,im2.shape[1]))),axis=0)return concatenate((im1,im2), axis=1)def plot_matches(im1,im2,locs1,locs2,matchscores,show_below=True):""" 显示一幅带有连接匹配之间连线的图片输入:im1, im2(数组图像), locs1,locs2(特征位置),matchscores(match()的输出),show_below(如果图像应该显示在匹配的下方)"""im3=appendimages(im1,im2)if show_below:im3=vstack((im3,im3))plt.figure(figsize=(20, 10))imshow(im3)cols1 = im1.shape[1]for i in range(len(matchscores)):if matchscores[i]>0:plot([locs1[i,0],locs2[matchscores[i,0],0]+cols1], [locs1[i,1],locs2[matchscores[i,0],1]],'c')axis('off')# set paths to data folder
featname = ['out_sift_'+str(i+1)+'.txt' for i in range(2)]
imname = [str(i+1)+'.jpg' for i in range(2)]# extract features and match
l = {}
d = {}l[0],d[0] = read_features_from_file(featname[0])
l[1],d[1] = read_features_from_file(featname[1])
matches = {}matches[0]  = match_twosided(d[1], d[0])### visualize the matches (Figure 3-11 in the book)im1 = array(Image.open(imname[0]))
im2 = array(Image.open(imname[1]))
#figure()
#plot_matches(im2,im1,l[1],l[0],matches[0],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 elsewherefp = 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(0)
H_01 = homography.H_from_ransac(fp,tp,model)[0] #im 0 to 1 # warp the images
delta = 2000 # for padding and translationim1 = array(Image.open(imname[0]), "uint8")im2 = array(Image.open(imname[1]), "uint8")###
im_12 = warp.panorama(H_01,im1,im2,delta,delta)##figure()
imshow(array(im_12, "uint8"))
axis('off')
show()

运行结果:

2.PTGUI 

PTGUI是一款功能强大的全景图片拼接软件,其五个字母来自于Panorama Tools Graphical User Interface。从1996年至今(2022)已经升级到第12版了。

使用PTGui可以快捷方便地制作出360X180度的“完整球型全景图片”(Full spherical panorama),其工作流程非常简便:1、导入一组原始底片;2、运行自动对齐控制点;3、生成并保存全景图片文件。

软件能自动读取底片的镜头参数,识别图片重叠区域的像素特征,然后以“控制点”(control point)的形式进行自动缝合,并进行优化融合。在软件的全景图片编辑器有更丰富的功能,支持多种视图的映射方式,用户也可以手工添加或删除控制点,从而提高拼接的精度。软件支持多种格式的图像文件输入,输出可以选择为高动态范围的图像,拼接后的图像明暗度均一,基本上没有明显的拼接痕迹。软件提供Windows和MAC版本。

2.1导入原始底片

点击加载影像

选择相机参数

2.2对齐影像 

点击对齐影像自动对齐控制点,可以预览对齐后效果,效果不好时可以手动添加控制点进行优化。

 2.3创建全景

        创建全景后即可导出全景图

 

运行结果:

图像拼接(SIFT与PTGUI)相关推荐

  1. 图像拼接 SIFT资料合集

    最近也注意一些图像拼接方面的文章,很多很多,尤其是全景图拼接的,实际上类似佳能相机附加的软件,好多具备全景图拼接,多幅图像自动软件实现拼接,构成(合成)一幅全景图像(风景). Sift算法,我略知一二 ...

  2. ADAS辅助驾驶_自动驾驶_技术点列表

    0 ADAS 汽车电子及ADAS安全部分相关测试标准 汽车总线特性简述 短距离车间通信V2X简述 先进驾驶辅助系统ADAS接口协议ADASIS v2简介 ADAS在车载导航设备上的应用 先进驾驶辅助系 ...

  3. (三)计算机视觉 --SIFT特征匹配、地理标记图像匹配及RANSAC图像拼接

    目录 一.sift特征检测概述 1.1特征点 1.2sift特征检测 二.sift特征提取与匹配 2.1特征提取并展示 2.2对两张图片进行特征匹配计算 2.3给定一张图片,输出与其匹配最多的三张图片 ...

  4. 图像拼接领域的经典文章以及常用的算法函数(一)(SIFT,APAP,AANAP,Seam-sutting,HomographyNet等等)

    1.特征点的匹配 首先进行SIFT的特征点的匹配: SIFT特征点的提取与匹配是图像拼接的第一步,如何提取到有效的,鲁棒性强的特征点是接下来的工作的重要前提,搞清楚什么是尺度空间极值检测.关键点定位. ...

  5. 基于SIFT特征的图像拼接融合(matlab+vlfeat实现)

    基于SIFT特征的图像拼接融合(matlab+vlfeat实现) piccolo,之前做的东西,简单整理下,不是做图像方向的,写的不好轻喷 主要原理参看SIFT算法详解和SIFT特征匹配算法介绍--寻 ...

  6. 计算机视觉3 SIFT特征提取与全景图像拼接

    1.原理 检测并提取图像的特征和关键点 匹配两个图像之间的描述符 使用RANSAC算法使用我们匹配的特征向量估计单应矩阵 拼接图像 步骤一和步骤二过程是运用SIFT局部描述算子检测图像中的关键点和特征 ...

  7. 基于sift特征点的图像拼接

    最近学习了图像拼接的一些知识,在这里记录一下,方便以后的学习, 博客中的代码均基于python,目前只能用于左右拼接 基于sift特征点的图像拼接包括以下几个步骤: 1.sift特征点的提取 2.利用 ...

  8. 图像拼接(一)——SIFT算法新手入门级介绍!!!

    前言 因为博主毕设和图像拼接有关,所以博主简单地学习了SIFT算法,不知道以后研究生会不会接触图像这块,顺便也为了检验一下自己学的是否透彻,所以在CSDN上写一篇Blog,纪录一下,仅供各位小伙伴参考 ...

  9. 基于SIFT特征的全景图像拼接

    主要分为以下几个步骤: (1) 读入两张图片并分别提取SIFT特征 (2) 利用k-d tree和BBF算法进行特征匹配查找 (3) 利用RANSAC算法筛选匹配点并计算变换矩阵 (3) 图像融合 S ...

最新文章

  1. 【连载】优秀程序员的 45 个习惯之习惯27
  2. English Speech-Graduation from University
  3. java简述会话对象的生命周期_简述Java Web三大作用域对象
  4. 实践 | kafka 基本使用
  5. 2020年中职学计算机有前途吗,2020年南昌中专计算机专业都学什么
  6. PyQt4设置窗口左上角的小图标
  7. mac 关闭 mysqld 进程(亲测可用)
  8. 时间数值缺失产生的字符串NaT处理
  9. 构建AD域 、 管理AD域
  10. Oracle 根据dbf文件的数据恢复
  11. 并发测试工具(ubuntu 16.04)
  12. leapFTP 使用笔记
  13. annot keep settings in the secure 或WRITE_SETTINGS not granted
  14. 如何给华硕笔记本在光驱位加装另一块linux系统固态硬盘?
  15. 支付宝php40247,支付宝APP支付 显示 系统繁忙 请稍后再试 ALI40247
  16. TokenInsight 对话首席——隐私安全计算,价值几何?
  17. 三元组顺序表表示的稀疏矩阵转置(10分)
  18. RabbitMQ如何保证消息的可靠性
  19. IE 兼容性问题记录
  20. FortiGate抓包 Sniffer

热门文章

  1. 数据结构——带头结点双向循环链表
  2. arXiv journal 2022.0311
  3. 【理论学习】什么是技术栈?
  4. 牛客小白月赛61 F.选座椅(双指针)
  5. matlab 电路频率响应_你不知道的这12个细节,正毁掉你的电路...
  6. 一窥社交媒体中的档案学
  7. 社区升级改造,智慧社区解决方案解读
  8. 不能连接MySQL服务主机3306_解决centos的mysql服务3306端口无法远程连接10038问题
  9. [从头学绘画] 第16节 六十四式八卦掌 (33-40)
  10. 2018年8月草原计划