sift、surf、orb 特征提取及最优特征点匹配
目录
siftsift特征简介SIFT(Scale-Invariant Feature Transform)特征,即尺度不变特征变换,是一种计算机视觉的特征提取算法,用来侦测与描述图像中的局部性特征。 实质上,它是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出、不会因光照、仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。 sift特征提取步骤1. 尺度空间的极值检测: 尺度空间指一个变化尺度 具体可以参考这篇博客:https://www.cnblogs.com/liuchaogege/p/5155739.html surfsurf特征简介SURF(Speeded Up Robust Features,加速稳健特征) 是一种稳健的图像识别和描述算法。它是SIFT的高效变种,也是提取尺度不变特征,算法步骤与SIFT算法大致相同,但采用的方法不一样,要比SIFT算法更高效(正如其名)。SURF使用海森(Hesseian)矩阵的行列式值作特征点检测并用积分图加速运算;SURF 的描述子基于 2D 离散小波变换响应并且有效地利用了积分图。 surf特征提取步骤1. 特征点检测: SURF使用Hessian矩阵来检测特征点,该矩阵是x,y方向的二阶导数矩阵,可测量一个函数的局部曲率,其行列式值代表像素点周围的变化量,特征点需取行列式值的极值点。用方型滤波器取代SIFT中的高斯滤波器,利用积分图(计算位于滤波器方型的四个角落值)大幅提高运算速度。 具体可以参考这篇博客: orborb特征简介ORB(Oriented FAST and Rotated BRIEF)该特征检测算法是在著名的FAST特征检测和BRIEF特征描述子的基础上提出来的,其运行时间远远优于SIFT和SURF,可应用于实时性特征检测。ORB特征检测具有尺度和旋转不变性,对于噪声及其透视变换也具有不变性,良好的性能是的利用ORB在进行特征描述时的应用场景十分广泛。ORB特征检测主要分为以下两个步骤:(1)方向FAST特征点检测(2)BRIEF特征描述。 orb特征提取算法
代码实现接下来的代码采用的库如下图所示 红色框的那两个库非常重要!版本请使用3.4.2.16的,而不是最新的,否则在特征提取的时候会报错。 错误提示:sift = cv2.xfeatures2d.SIFT_create() cv2.error: OpenCV(3.4.3) C:projectsopencv-pythonopencv_contribmodulesxfeatures2dsrcsift.cpp:1207: error: (-213:The function/feature is not implemented) This algorithm is patented and is excluded in this configuration; Set OPENCV_ENABLE_NONFREE CMake option and rebuild the library in function ‘cv::xfeatures2d::SIFT::create’ 如果你在使用cv2.xfeatures2d.SIFT_create()这个函数的时候出现了上面的错误,就是因为你的库版本太新。把版本退回去就可以了。 特征提取def sift(filename): img = cv2.imread(filename) # 读取文件 img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 转化为灰度图 sift = cv2.xfeatures2d_SIFT.create() keyPoint,descriptor = sift.detectAndCompute(img,None) # 特征提取得到关键点以及对应的描述符(特征向量) return img,keyPoint,descriptor def surf(filename): img = cv2.imread(filename) # 读取文件 img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 转化为灰度图 sift = cv2.xfeatures2d_SURF.create() keyPoint,descriptor def orb(filename): img = cv2.imread(filename) # 读取文件 img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 转化为灰度图 sift = cv2.ORB_create() keyPoint,descriptor 这里解释一下为什么要进行转化为灰度图?
比较一下提取的结果看看 def compare(filename): imgs = [] keyPoint = [] descriptor = [] img,keyPoint_temp,descriptor_temp = sift(filename) keyPoint.append(keyPoint_temp) descriptor.append(descriptor_temp) imgs.append(img) img,descriptor_temp = surf(filename) keyPoint.append(keyPoint_temp) descriptor.append(descriptor_temp) imgs.append(img) img,descriptor_temp = orb(filename) keyPoint.append(keyPoint_temp) descriptor.append(descriptor_temp) imgs.append(img) return imgs,descriptor def main(): method = ['sift','surf','orb'] imgs,kp,des = compare('./pic/doraemon1.jpg') for i in range(3): img = cv2.drawKeypoints(imgs[i],kp[i],None) cv2.imshow(method[i],img) cv2.waitKey() cv2.destroyAllWindows() print("sift len of des: %d,size of des: %d" % (len(des[0]),len(des[0][0]))) print("surf len of des: %d,size of des: %d" % (len(des[1]),len(des[1][0]))) print("orb len of des: %d,size of des: %d" % (len(des[2]),len(des[2][0]))) 下图是提取的结果,从左到右分别是原图、sift、surf、orb sift len of des: 458,size of des: 128 surf len of des: 1785,size of des: 64 orb len of des: 500,size of des: 32 可以看出:
特征匹配BruteForce匹配和FLANN匹配是opencv二维特征点匹配常见的两种办法,分别对应BFMatcher(BruteForceMatcher)和FlannBasedMatcher。 二者的区别在于BFMatcher总是尝试所有可能的匹配,从而使得它总能够找到最佳匹配,这也是Brute Force(暴力法)的原始含义。而FlannBasedMatcher中FLANN的含义是Fast Library forApproximate Nearest Neighbors,从字面意思可知它是一种近似法,算法更快但是找到的是最近邻近似匹配,所以当我们需要找到一个相对好的匹配但是不需要最佳匹配的时候往往使用FlannBasedMatcher。当然也可以通过调整FlannBasedMatcher的参数来提高匹配的精度或者提高算法速度,但是相应地算法速度或者算法精度会受到影响。 本文是进行最优特征点匹配,因此选用BruteForce Matcher。 def match(filename1,filename2,method): if(method == 'sift'): img1,kp1,des1 = sift(filename1) img2,kp2,des2 = sift(filename2) bf = cv2.BFMatcher(cv2.NORM_L2,crossCheck=True) # sift的normType应该使用NORM_L2或者NORM_L1 matches = bf.match(des1,des2) matches = sorted(matches,key=lambda x: x.distance) knnMatches = bf.knnMatch(des1,des2,k=1) # drawMatchesKnn if (method == 'surf'): img1,des1 = surf(filename1) img2,des2 = surf(filename2) bf = cv2.BFMatcher(cv2.NORM_L2,crossCheck=True) # surf的normType应该使用NORM_L2或者NORM_L1 matches = bf.match(des1,k=1) # drawMatchesKnn if(method == 'orb'): img1,des1 = orb(filename1) img2,des2 = orb(filename2) bf = cv2.BFMatcher(cv2.NORM_HAMMING,crossCheck = True) # orb的normType应该使用NORM_HAMMING matches = bf.match(des1,k = 1) # drawMatchesKnn # 过滤 for m in matches: for n in matches: if(m != n and m.distance >= n.distance*0.75): matches.remove(m) break img = cv2.drawMatches(img1,img2,matches[:50],flags=2) cv2.imshow("matches",img) cv2.waitKey() cv2.destroyAllWindows() def main(): method = ['sift','orb'] for i in range(3): match('./pic/wechat1.jpg','./pic/wechat2.png',method[i]) if __name__ == '__main__': main() 介绍一下几个关键函数。
然后是
这里还对匹配得到的结果做了过滤,排除一些不好的匹配结果。 - img1 – 源图像1 - keypoints1 –源图像1的特征点. - img2 – 源图像2. - keypoints2 – 源图像2的特征点 - matches1to2 – 源图像1的特征点匹配源图像2的特征点 - outImg – 输出图像具体由flags决定. - matchColor – 匹配的颜色(特征点和连线),若matchColor==Scalar::all(-1),颜色随机. - singlePointColor – 单个点的颜色,即未配对的特征点,若matchColor==Scalar::all(-1),颜色随机. - matchesMask – Mask决定哪些点将被画出,若为空,则画出所有匹配点. - flags – Fdefined by DrawMatchesFlags. 接下来看一下上面的代码运行的结果。从上到底依次是原图、sift、surf、orb  sift size of kp: 59,after filtering: 20 从输出的结果来看,orb的效果最好。感兴趣的话还可以用其他图片看看效果,pic文件夹还提供其他两组比较的图片。 # 总结 基于特征的匹配分为特征点提取和匹配两个步骤,本篇主要针对特征点提取三种方法进行比较,分别是SIFT,SURF以及ORB三种方法,这三种方法在OpenCV里面都已实现。SURF基本就是SIFT的全面升级版,有 SURF基本就不用考虑SIFT,而ORB的强点在于计算时间,以下具体比较: 计算速度: ORB>>SURF>>SIFT(各差一个量级) 旋转鲁棒性:SURF>ORB~SIFT(表示差不多) 模糊鲁棒性:SURF>ORB~SIFT 尺度变换鲁棒性: SURF>SIFT>ORB(ORB并不具备尺度变换性) 附录GitHub:https://github.com/Professorchen/Computer-Vision/tree/master/feature-extraction (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |