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中wx将图标显示在右下角的脚本代码
Mar 08 Python
Python中给List添加元素的4种方法分享
Nov 28 Python
在Python中使用__slots__方法的详细教程
Apr 28 Python
python语言基本语句用法总结
Jun 11 Python
python实现鸢尾花三种聚类算法(K-means,AGNES,DBScan)
Jun 27 Python
python执行scp命令拷贝文件及文件夹到远程主机的目录方法
Jul 08 Python
Django如何简单快速实现PUT、DELETE方法
Jul 24 Python
python 利用turtle库绘制笑脸和哭脸的例子
Nov 23 Python
python异常处理try except过程解析
Feb 03 Python
Python中用pyinstaller打包时的图标问题及解决方法
Feb 17 Python
解决pycharm下载库时出现Failed to install package的问题
Sep 04 Python
利用Python脚本写端口扫描器socket,python-nmap
Jul 23 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中的静态变量的基本用法
2014/03/20 PHP
php将数组存储为文本文件方法汇总
2015/10/28 PHP
php实现的统计字数函数定义与使用示例
2017/07/26 PHP
jqPlot jquery的页面图表绘制工具
2009/07/25 Javascript
Extjs中常用表单介绍与应用
2010/06/07 Javascript
IE6图片加载的一个BUG解决方法
2010/07/13 Javascript
jquery获取颜色在ie和ff下的区别示例介绍
2014/03/28 Javascript
js+html5通过canvas指定开始和结束点绘制线条的方法
2015/06/05 Javascript
JavaScript实现自动弹出窗口并自动关闭窗口的方法
2015/08/06 Javascript
深入浅析JavaScript中的Function类型
2016/07/09 Javascript
AngularJS入门教程之多视图切换用法示例
2016/11/02 Javascript
Ionic2调用本地SQlite实例
2017/04/22 Javascript
基于zepto.js实现登录界面
2017/10/09 Javascript
bootstrap轮播模板使用方法详解
2017/11/17 Javascript
使用webpack打包koa2 框架app
2018/02/02 Javascript
webpack 静态资源集中输出的方法示例
2018/11/09 Javascript
判断“命令按钮”是否被鼠标单击详解
2019/07/31 Javascript
Vue+Element实现网页版个人简历系统(推荐)
2019/12/31 Javascript
JS如何寻找数组中心索引过程解析
2020/06/01 Javascript
[33:39]DOTA2上海特级锦标赛C组小组赛#2 LGD VS Newbee第二局
2016/02/27 DOTA
[01:02:26]DOTA2-DPC中国联赛 正赛 SAG vs RNG BO3 第二场 1月18日
2021/03/11 DOTA
Python中的super用法详解
2015/05/28 Python
Python 爬虫多线程详解及实例代码
2016/10/08 Python
Python模拟随机游走图形效果示例
2018/02/06 Python
python监控进程脚本
2018/04/12 Python
浅析canvas元素的html尺寸和css尺寸对元素视觉的影响
2019/07/22 HTML / CSS
香港草莓网土耳其网站:Strawberrynet TR
2017/03/02 全球购物
员工薪酬福利制度
2014/01/17 职场文书
学校三节实施方案
2014/06/09 职场文书
材料物理专业求职信
2014/09/01 职场文书
2014年药房工作总结
2014/11/22 职场文书
卫生院艾滋病宣传活动总结
2015/05/09 职场文书
初中语文教学随笔
2015/08/15 职场文书
一年级下册数学教学反思
2016/02/16 职场文书
2019职场单身人才调研报告:互联网行业单身比例最高
2019/08/07 职场文书
解析高可用Redis服务架构分析与搭建方案
2021/06/20 Redis