SIFT/SUR/ORB特征提取及手写最优特征点匹配

SIFT/SUR/ORB特征提取及手写最优特征点匹配

特征提取

首先对图片进行灰度化,然后调用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()

运行结果

以提取orb特征为例:
运行结果示例
运行结果示例

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值