python opencv进行图像拼接


Posted in Python onMarch 27, 2020

本文实例为大家分享了python opencv进行图像拼接的具体代码,供大家参考,具体内容如下

思路和方法

思路

1、提取要拼接的两张图片的特征点、特征描述符;
2、将两张图片中对应的位置点找到,匹配起来;
3、如果找到了足够多的匹配点,就能将两幅图拼接起来,拼接前,可能需要将第二幅图透视旋转一下,利用找到的关键点,将第二幅图透视旋转到一个与第一幅图相同的可以拼接的角度;
4、进行拼接;
5、进行拼接后的一些处理,让效果看上去更好。

实现方法

1、提取图片的特征点、描述符,可以使用opencv创建一个SIFT对象,SIFT对象使用DoG方法检测关键点,并对每个关键点周围的区域计算特征向量。在实现时,可以使用比SIFT快的SURF方法,使用Hessian算法检测关键点。因为只是进行全景图拼接,在使用SURF时,还可以调节它的参数,减少一些关键点,只获取64维而不是128维的向量等,加快速度。
2、在分别提取好了两张图片的关键点和特征向量以后,可以利用它们进行两张图片的匹配。在拼接图片中,可以使用Knn进行匹配,但是使用FLANN快速匹配库更快,图片拼接,需要用到FLANN的单应性匹配。
3、单应性匹配完之后可以获得透视变换H矩阵,用这个的逆矩阵来对第二幅图片进行透视变换,将其转到和第一张图一样的视角,为下一步拼接做准备。
4、透视变换完的图片,其大小就是最后全景图的大小,它的右边是透视变换以后的图片,左边是黑色没有信息。拼接时可以比较简单地处理,通过numpy数组选择直接把第一张图加到它的左边,覆盖掉重叠部分,得到拼接图片,这样做非常快,但是最后效果不是很好,中间有一条分割痕迹非常明显。使用opencv指南中图像金字塔的代码对拼接好的图片进行处理,整个图片平滑了,中间的缝还是特别突兀。
5、直接拼效果不是很好,可以把第一张图叠在左边,但是对第一张图和它的重叠区做一些加权处理,重叠部分,离左边图近的,左边图的权重就高一些,离右边近的,右边旋转图的权重就高一些,然后两者相加,使得过渡是平滑地,这样看上去效果好一些,速度就比较慢。如果是用SURF来做,时间主要画在平滑处理上而不是特征点提取和匹配。

python_opencv中主要使用的函数

0、基于python 3.7和对应的python-opencv

1、cv2.xfeatures2d.SURF_create ([hessianThreshold[, nOctaves[, nOctaveLayers[, extended[, upright]]]]])
该函数用于生成一个SURF对象,在使用时,为提高速度,可以适当提高hessianThreshold,以减少检测的关键点的数量,可以extended=False,只生成64维的描述符而不是128维,令upright=True,不检测关键点的方向。

2、cv2.SURF.detectAndCompute(image, mask[, descriptors[, useProvidedKeypoints]])

该函数用于计算图片的关键点和描述符,需要对两幅图都进行计算。

3、flann=cv2.FlannBasedMatcher(indexParams,searchParams)
match=flann.knnMatch(descrip1,descrip2,k=2)
flann快速匹配器有两个参数,一个是indexParams,一个是searchParams,都用手册上建议的值就可以。在创建了匹配器得到匹配数组match以后,就可以参考Lowe给出的参数,对匹配进行过滤,过滤掉不好的匹配。其中返回值match包括了两张图的描述符距离distance 、训练图(第二张)的描述符索引trainIdx 、查询的图(第一张)的描述符索引queryIdx 这几个属性。

4、M,mask=cv2.findHomography(srcPoints, dstPoints[, method[, ransacReprojThreshold[, mask]]])
这个函数实现单应性匹配,返回的M是一个矩阵,即对关键点srcPoints做M变换能变到dstPoints的位置。

5、warpImg=cv2.warpPerspective(src,np.linalg.inv(M),dsize[,dst[,flags[,borderMode[,borderValue]]]])
用这个函数进行透视变换,变换视角。src是要变换的图片,np.linalg.inv(M)是④中M的逆矩阵,得到方向一致的图片。

6、a=b.copy() 实现深度复制,Python中默认是按引用复制,a=b是a指向b的内存。

7、draw_params = dict(matchColor = (0,255,0),singlePointColor = (255,0,0),matchesMask = matchMask,flags = 2),img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
使用drawMatches可以画出匹配的好的关键点,matchMask是比较好的匹配点,之间用绿色线连接起来。

核心代码

import cv2
import numpy as np
from matplotlib import pyplot as plt
import time
MIN = 10
starttime=time.time()
img1 = cv2.imread('1.jpg') #query
img2 = cv2.imread('2.jpg') #train

#img1gray=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
#img2gray=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
surf=cv2.xfeatures2d.SURF_create(10000,nOctaves=4,extended=False,upright=True)
#surf=cv2.xfeatures2d.SIFT_create()#可以改为SIFT
kp1,descrip1=surf.detectAndCompute(img1,None)
kp2,descrip2=surf.detectAndCompute(img2,None)

FLANN_INDEX_KDTREE = 0
indexParams = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
searchParams = dict(checks=50)

flann=cv2.FlannBasedMatcher(indexParams,searchParams)
match=flann.knnMatch(descrip1,descrip2,k=2)


good=[]
for i,(m,n) in enumerate(match):
 if(m.distance<0.75*n.distance):
 good.append(m)

if len(good)>MIN:
 src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1,1,2)
 ano_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1,1,2)
 M,mask=cv2.findHomography(src_pts,ano_pts,cv2.RANSAC,5.0)
 warpImg = cv2.warpPerspective(img2, np.linalg.inv(M), (img1.shape[1]+img2.shape[1], img2.shape[0]))
 direct=warpImg.copy()
 direct[0:img1.shape[0], 0:img1.shape[1]] =img1
 simple=time.time()

#cv2.namedWindow("Result", cv2.WINDOW_NORMAL)
#cv2.imshow("Result",warpImg)
 rows,cols=img1.shape[:2]
 
 for col in range(0,cols):
 if img1[:, col].any() and warpImg[:, col].any():#开始重叠的最左端
 left = col
 break
 for col in range(cols-1, 0, -1):
 if img1[:, col].any() and warpImg[:, col].any():#重叠的最右一列
 right = col
 break

 res = np.zeros([rows, cols, 3], np.uint8)
 for row in range(0, rows):
 for col in range(0, cols):
 if not img1[row, col].any():#如果没有原图,用旋转的填充
 res[row, col] = warpImg[row, col]
 elif not warpImg[row, col].any():
 res[row, col] = img1[row, col]
 else:
 srcImgLen = float(abs(col - left))
 testImgLen = float(abs(col - right))
 alpha = srcImgLen / (srcImgLen + testImgLen)
 res[row, col] = np.clip(img1[row, col] * (1-alpha) + warpImg[row, col] * alpha, 0, 255)

 warpImg[0:img1.shape[0], 0:img1.shape[1]]=res
 final=time.time()
 img3=cv2.cvtColor(direct,cv2.COLOR_BGR2RGB)
 plt.imshow(img3,),plt.show()
 img4=cv2.cvtColor(warpImg,cv2.COLOR_BGR2RGB)
 plt.imshow(img4,),plt.show()
 print("simple stich cost %f"%(simple-starttime))
 print("\ntotal cost %f"%(final-starttime))
 cv2.imwrite("simplepanorma.png",direct)
 cv2.imwrite("bestpanorma.png",warpImg)
 
else:
 print("not enough matches!")

运行结果

原图1.jpg

python opencv进行图像拼接

原图2.jpg

python opencv进行图像拼接

特征点匹配

python opencv进行图像拼接

直接拼接和平滑对比

python opencv进行图像拼接

效果

python opencv进行图像拼接

本文已被收录到专题《python图片处理操作》 ,欢迎大家点击学习更多精彩内容。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python转换字符串为摩尔斯电码的方法
Jul 06 Python
Linux下通过python访问MySQL、Oracle、SQL Server数据库的方法
Apr 23 Python
Python的Tornado框架的异步任务与AsyncHTTPClient
Jun 27 Python
Python面向对象编程中关于类和方法的学习笔记
Jun 30 Python
Django学习教程之静态文件的调用详解
May 08 Python
Python matplotlib 画图窗口显示到gui或者控制台的实例
May 24 Python
python实现爬取图书封面
Jul 05 Python
对tf.reduce_sum tensorflow维度上的操作详解
Jul 26 Python
python实现字符串完美拆分split()的方法
Jul 16 Python
python 实现GUI(图形用户界面)编程详解
Jul 17 Python
Python配置文件处理的方法教程
Aug 29 Python
keras 权重保存和权重载入方式
May 21 Python
Python爬虫爬取电影票房数据及图表展示操作示例
Mar 27 #Python
Pyspark读取parquet数据过程解析
Mar 27 #Python
Python基于pyecharts实现关联图绘制
Mar 27 #Python
Python爬虫爬取杭州24时温度并展示操作示例
Mar 27 #Python
Django添加bootstrap框架时无法加载静态文件的解决方式
Mar 27 #Python
Python itertools.product方法代码实例
Mar 27 #Python
python实现图像全景拼接
Mar 27 #Python
You might like
php下连接ftp实现文件的上传、下载、删除文件实例代码
2010/06/03 PHP
Eclipse的PHP插件PHPEclipse安装和使用
2014/07/20 PHP
codeigniter中view通过循环显示数组数据的方法
2015/03/20 PHP
Thinkphp模板标签if和eq的区别和比较实例分析
2015/07/01 PHP
解读PHP中的垃圾回收机制
2015/08/10 PHP
Yii2.0 Basic代码中路由链接被转义的处理方法
2016/09/21 PHP
注释PHP和html混合代码的小技巧(分享)
2016/11/03 PHP
TP5框架实现的数据库备份功能示例
2020/04/05 PHP
在模板页面的js使用办法
2010/04/01 Javascript
nodejs实用示例 缩址还原
2010/12/28 NodeJs
调用innerHTML之后onclick失效问题的解决方法
2014/01/28 Javascript
qq悬浮代码(兼容各个浏览器)
2014/01/29 Javascript
iframe子页面与父页面在同域或不同域下的js通信
2014/05/07 Javascript
删除javascript中注释语句的正则表达式
2014/06/11 Javascript
Egret引擎开发指南之创建项目
2014/09/03 Javascript
javascript实现框架高度随内容改变的方法
2015/07/23 Javascript
DIV随滚动条滚动而滚动的实现代码【推荐】
2016/04/12 Javascript
js修改onclick动作的四种方法(推荐)
2016/08/18 Javascript
基于bootstrap-datetimepicker.js不支持IE8的快速解决方法
2016/11/07 Javascript
Vue实现购物车功能
2017/04/27 Javascript
简单的Vue SSR的示例代码
2018/01/12 Javascript
Layui带搜索的下拉框的使用以及动态数据绑定方法
2019/09/28 Javascript
微信小程序实现侧边栏分类
2019/10/21 Javascript
解决ant Design中Select设置initialValue时的大坑
2020/10/29 Javascript
vue集成一个支持图片缩放拖拽的富文本编辑器
2021/01/29 Vue.js
[02:28]DOTA2亚洲邀请赛附加赛 RECAP赛事回顾
2015/01/29 DOTA
Python2.x版本中maketrans()方法的使用介绍
2015/05/19 Python
Python基础篇之初识Python必看攻略
2016/06/23 Python
shell命令行,一键创建 python 模板文件脚本方法
2018/03/20 Python
Python中实现输入超时及如何通过变量获取变量名
2020/01/18 Python
详解tensorflow之过拟合问题实战
2020/11/01 Python
Mountain Warehouse波兰官方网站:英国户外品牌
2019/08/29 全球购物
业务部经理岗位职责
2014/01/04 职场文书
前台接待岗位职责范本
2015/04/03 职场文书
2016幼儿园教师年度考核评语
2015/12/01 职场文书
CSS使用Flex和Grid布局实现3D骰子
2022/08/05 HTML / CSS