首先对图片进行灰度化,然后调用cv库函数即可,这个网上帖子很多,不多说了。
##特征提取函数
def extract(method,filename):
if(method == 'sift'):
extractor = cv2.xfeatures2d_SIFT.create()
if(method == 'surf'):
extractor = cv2.xfeatures2d_SURF.create()
if(method == 'orb'):
extractor = cv2.ORB_create()
img= cv2.imread(filename)
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
keypoint, descriptor = extractor.detectAndCompute(img,None)
img = cv2.drawKeypoints(img,keypoint,None,(100,0,0))
# cv2.imshow("descriptor extraction",img)
# cv2.waitKey(0)
return img,keypoint,descriptor
这个是手写的,因为老师要求),BruteForce匹配和FLANN匹配是opencv二维特征点匹配常见的两种办法,我选择复现了BF算法,因为自己要做的工作量不大,BF是暴力算法,耗时长,但效果也是最好,BF算法的思想就是尝试所有可能的匹配,从而使得它总能够找到最佳匹配。
知道了原理,我们还要知道sift这些函数提取出来的到底是个什么结构才行,具体参考这位博主的文章:opencv中 cv2.KeyPoint和cv2.DMatch的理解,至于提取出的descriptor,则是一个list,每一个成员是一个特征向量,我们要计算的就是图片1和图片2的这个descriptor中哪两个向量的‘距离’最近,这两个向量所对应的keypoint就是一个匹配,对于BF算法,遍历图片1中所有向量v1,对于每个向量,找到图片2中距离最小的向量v2,这时候要注意,对于v2,还应该回过头再遍历一遍图片1,找到距离最小的向量,这样才能保证找到最优匹配,即‘双向最优’。
距离的计算,sift和surf比较适合用NORM_L2,orb适合NORM_HAMMING,距离函数如下:
##计算两个向量的汉明距离函数
def NORM_HAMMING(vec1,vec2):
sum = 0
for i in range(len(vec1)):
sum = sum + bin(vec1[i]^vec2[i]).count('1')
return sum
##计算两个向量的L2距离
def NORM_L2(vec1, vec2):
return np.sqrt(np.sum(np.square(vec1 - vec2)))
匹配函数的编写,基本就按上文中的思路来,在求得一个匹配后,将它封装到cv库的DFMatch类中,以便绘制匹配图,代码如下:
##最优特征点匹配函数(手写)
def match(method,des1,des2):
matches = []
mem1 = []#记录已经被匹配的特征点
mem2 = []#记录已经被匹配的特征点
if(method == 'orb'):
##进行mxn次循环,寻找最优匹配
for de1 in range(len(des1)):
mindistance = sys.maxsize
for de2 in range(len(des2)):
#print(des1[de1])
if(mindistance > NORM_HAMMING(des1[de1],des2[de2]) and de1 not in mem1 and de2 not in mem2):
mindistance = NORM_HAMMING(des1[de1],des2[de2])
match1 = de1
match2 = de2
for detemp in range(len(des1)):
if(mindistance > NORM_HAMMING(des1[detemp],des2[match2]) and detemp not in mem1):
match1 = detemp
mindistance = NORM_HAMMING(des1[detemp],des2[match2])
#print(maxdistance)
#print(match1,match2)
mem1.append(match1)##将已经匹配的点记录,之后不会再用这些点进行匹配
mem2.append(match2)
match = cv2.DMatch(match1,match2,0,mindistance)##将匹配结果初始化为DMatch类型
matches.append(match)
else:
for de1 in range(len(des1)):
mindistance = sys.maxsize
for de2 in range(len(des2)):
# print(des1[de1])
if (mindistance > NORM_L2(des1[de1], des2[de2]) and de1 not in mem1 and de2 not in mem2):
mindistance = NORM_L2(des1[de1], des2[de2])
match1 = de1
match2 = de2
for detemp in range(len(des1)):
if (mindistance > NORM_L2(des1[detemp], des2[match2]) and detemp not in mem1):
match1 = detemp
mindistance = NORM_L2(des1[detemp], des2[match2])
# print(maxdistance)
match = cv2.DMatch(match1, match2, 0, mindistance)
matches.append(match)
#print(type(matches))
#print(len(matches))
matches = sorted(matches, key = lambda x: x.distance)#对匹配结果进行排序
return matches
主函数:
def main():
method = 'sift'#orb/surf/sift
img1, keypoint1, descriptor1 = extract(method,'gi1.jpg')
img2, keypoint2, descriptor2 = extract(method,'gi2.jpg')
#print(len(keypoint1))
#print(len(descriptor1))
#print(len(keypoint2))
#print(len(descriptor2))
matches = match2(method,descriptor1,descriptor2)
#for i in matches:
#print(i.imgIdx)
img = cv2.drawMatches(img1, keypoint1, img2, keypoint2, matches[:20], img2, flags=2)#绘制匹配结果
cv2.imshow("descriptor match", img)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()