import cv2 as cv
import numpy as np
def cv_show(name,img):
cv.imshow(name,img)
cv.waitKey(0)
cv.destroyAllWindows()
def detectAndDescribe(image):
gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
sift = cv.xfeatures2d.SIFT_create()
(kps,features)=sift.detectAndCompute(image,None)#这里的kps是一个特征点对象,,属性有.pt关键点坐标
#.angle关键点方向 .response响应强度 .size该点的直径大小
kps = np.float32([kp.pt for kp in kps])#此刻得到kps特征点对象中每一个特征点的坐标。
return (kps,features)
def matchKeypoints(kpsA,kpsB,features1,features2,ratio):
bf = cv.BFMatcher()
rawMatches = bf.knnMatch(features1,features2,2)#rawMatcher是一个Dmatch型对象,属性有.distance描述符间距离
#.trainIdx样本图像特征点标识符,.queryIdx测试图像的特征点标识符,.imgIdx训练图像的索引
matches = []
for m,n in rawMatches:
if m.distance 4:
pts1 = np.float32([kpsA[i] for (_,i) in matches])#将测试图像的坐标储存到Pts1里
pts2 = np.float32([kpsB[i] for (i,_) in matches])#将样本图像的坐标储存到pts2里
# 计算视角变换矩阵H
#参数一,测试图像的特征点坐标,参数二,样本图像的特征点坐标,参数三,RANSAC算法:
#RANSCA原理, 因为拟合一条直线只需要两个点,因此我们每次随机选取两个点,做出直线,划定一个距离,判断落在直线周围距离范围点的个数,
# 不断的迭代,直到找出拟合的直线,使得点落在上面最多的拟合曲线
#参数四:参数范围1~10,原图像的点经过变换后点与目标图像上对应点的误差,超过了就是outlier
(H, status) = cv.findHomography(pts1, pts2, cv.RANSAC, 5)
return (matches, H, status)
return None
imageA = cv.imread("E:/opencv/picture/right1.jpg")
imageB = cv.imread("E:/opencv/picture/left1.png")
(kpsA,features1)=detectAndDescribe(imageA)
(kpsB,features2)=detectAndDescribe(imageB)
M = matchKeypoints(kpsA, kpsB, features1, features2, 0.75)
(matches, H, status) = M
# 将图片A进行视角变换,result是变换后图片
result = cv.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageB.shape[0]))
cv_show('result1',result)
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
cv_show('result2', result)
经常遇到的一个错误:
new style getargs format but argument is not a tuple
针对这句代码:result = cv.warpPerspective(imageA,M,[imageA.shape[1]+imageB.shape[1],max(imageA.shape[0],imageB.shape[0])])
原因是size那个参数应该是tuple(),而不是list[]。即应该是()而不是[]。
下面讲一下这个案例的大体过程:
1.首先我们是通过SIFT算法找到两张图(right,left)的特征点及特征向量,并把特征点的坐标储存起来。
2.通过蛮力匹配算法的得到kWmatches对象,将kWmatches对象的queryIdx和trainIdx给存起来,其中features1对应的图像为样本图像
3.求出样本图像的特征点坐标和测试图像的特征点坐标,找出这两坐标矩阵的H变换公式(利用RANSAC算法),将H变换公式对right图像做透视变换,得到拼接后的右边图像
4.将left原图赋给result对应的ROI区域,大功告成。