python opencv进行图像拼接

本文实例为大家分享了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

原图2.jpg

特征点匹配

直接拼接和平滑对比

效果

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

以上是 python opencv进行图像拼接 的全部内容, 来源链接: utcz.com/z/358512.html

回到顶部