应用OpenCV和Python进行SIFT算法的实现详解

应用OpenCV和Python进行SIFT算法的实现

如下图为进行测试的gakki101和gakki102,分别验证基于BFmatcher、FlannBasedMatcher等的SIFT算法,对比其优劣。为体现出匹配效果对于旋转特性的优势,将图gakki101做成具有旋转特性的效果。

基于BFmatcher的SIFT实现

BFmatcher(Brute-Force Matching)暴力匹配,应用BFMatcher.knnMatch( )函数来进行核心的匹配,knnMatch(k-nearest neighbor classification)k近邻分类算法。

kNN算法则是从训练集中找到和新数据最接近的k条记录,然后根据他们的主要分类来决定新数据的类别。该算法涉及3个主要因素:训练集、距离或相似的衡量、k的大小。kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。

kNN方法在类别决策时,只与极少量的相邻样本有关。由于kNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,kNN方法较其他方法更为适合。
经检验 BFmatcher在做匹配时会耗费大量的时间。

代码段如下:

import numpy as np
import cv2
from matplotlib import pyplot as plt

imgname1 = 'E:/other/gakki101.jpg'
imgname2 = 'E:/other/gakki102.jpg'

sift = cv2.xfeatures2d.SIFT_create()

img1 = cv2.imread(imgname1)
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) #灰度处理图像
kp1, des1 = sift.detectAndCompute(img1,None)  #des是描述子

img2 = cv2.imread(imgname2)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)#灰度处理图像
kp2, des2 = sift.detectAndCompute(img2,None) #des是描述子

hmerge = np.hstack((gray1, gray2)) #水平拼接
cv2.imshow("gray", hmerge) #拼接显示为gray
cv2.waitKey(0)

img3 = cv2.drawKeypoints(img1,kp1,img1,color=(255,0,255)) #画出特征点,并显示为红色圆圈
img4 = cv2.drawKeypoints(img2,kp2,img2,color=(255,0,255)) #画出特征点,并显示为红色圆圈
hmerge = np.hstack((img3, img4)) #水平拼接
cv2.imshow("point", hmerge) #拼接显示为gray
cv2.waitKey(0)
# BFMatcher解决匹配
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)
# 调整ratio
good = []
for m,n in matches:
  if m.distance < 0.75*n.distance:
    good.append([m])

img5 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,flags=2)
cv2.imshow("BFmatch", img5)
cv2.waitKey(0)
cv2.destroyAllWindows()

首先是针对图像的灰度化显示:

之后完成特征点的标注,用红色圆圈表示:

在cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,flags=2)下的匹配效果,比较杂乱,且会出错。

如果更换为cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2),明显优于上面的匹配,并且为预想的匹配区域,其效果为:

基于FlannBasedMatcher的SIFT实现

FLANN(Fast_Library_for_Approximate_Nearest_Neighbors)快速最近邻搜索包,它是一个对大数据集和高维特征进行最近邻搜索的算法的集合,而且这些算法都已经被优化过了。在面对大数据集时它的效果要好于 BFMatcher。
经验证,FLANN比其他的最近邻搜索软件快10倍。使用 FLANN 匹配,我们需要传入两个字典作为参数。这两个用来确定要使用的算法和其他相关参数等。

第一个是 IndexParams
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
这里使用的是KTreeIndex配置索引,指定待处理核密度树的数量(理想的数量在1-16)。

第二个字典是SearchParams
search_params = dict(checks=100)用它来指定递归遍历的次数。值越高结果越准确,但是消耗的时间也越多。实际上,匹配效果很大程度上取决于输入。

5kd-trees50checks总能取得合理精度,而且短时间完成。在之下的代码中,丢弃任何距离大于0.7的值,则可以避免几乎90%的错误匹配,但是好的匹配结果也会很少。

import numpy as np
import cv2
from matplotlib import pyplot as plt

imgname1 = 'E:/other/gakki101.jpg'
imgname2 = 'E:/other/gakki102.jpg'

sift = cv2.xfeatures2d.SIFT_create()

# FLANN 参数设计
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params,search_params)

img1 = cv2.imread(imgname1)
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) #灰度处理图像
kp1, des1 = sift.detectAndCompute(img1,None)#des是描述子

img2 = cv2.imread(imgname2)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
kp2, des2 = sift.detectAndCompute(img2,None)

hmerge = np.hstack((gray1, gray2)) #水平拼接
cv2.imshow("gray", hmerge) #拼接显示为gray
cv2.waitKey(0)

img3 = cv2.drawKeypoints(img1,kp1,img1,color=(255,0,255))
img4 = cv2.drawKeypoints(img2,kp2,img2,color=(255,0,255))

hmerge = np.hstack((img3, img4)) #水平拼接
cv2.imshow("point", hmerge) #拼接显示为gray
cv2.waitKey(0)
matches = flann.knnMatch(des1,des2,k=2)
matchesMask = [[0,0] for i in range(len(matches))]

good = []
for m,n in matches:
  if m.distance < 0.7*n.distance:
    good.append([m])

img5 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,flags=2)
cv2.imshow("FLANN", img5)
cv2.waitKey(0)
cv2.destroyAllWindows()

首先是针对图像的灰度化显示:

之后完成特征点的标注,用红色圆圈表示:

在cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,flags=2)下的匹配效果,比较杂乱,且会出错。

如果更换为cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2),明显优于上面的匹配,并且为预想的匹配区域,其效果为:

修改if m.distance < 0.7*n.distance:为 if m.distance < 1*n.distance:,显示效果为:

可见,虽然值越大,匹配的线条越密集,但错误匹配点也会增多,在lowe论文中,Lowe推荐ratio的阈值为0.8,但作者对大量任意存在尺度、旋转和亮度变化的两幅图片进行匹配,结果表明ratio取值在0. 4~0. 6 之间最佳,小于0. 4的很少有匹配点,大于0. 6的则存在大量错误匹配点,所以建议ratio的取值原则如下:

ratio=0. 4:对于准确度要求高的匹配;
ratio=0. 6:对于匹配点数目要求比较多的匹配;
ratio=0. 5:一般情况下。

基于FlannBasedMatcher的SURF实现

SURF全称为“加速稳健特征”(Speeded Up Robust Feature),不仅是尺度不变特征,而且是具有较高计算效率的特征。可被认为SURF是尺度不变特征变换算法(SIFT算法)的加速版。SURF最大的特征在于采用了haar特征以及积分图像的概念,SIFT采用的是DoG图像,而SURF采用的是Hessian矩阵(SURF算法核心)行列式近似值图像。SURF借鉴了SIFT算法中简化近似的思想,实验证明,SURF算法较SIFT算法在运算速度上要快3倍,综合性优于SIFT算法。

import numpy as np
import cv2
from matplotlib import pyplot as plt

imgname1 = 'E:/other/gakki101.jpg'
imgname2 = 'E:/other/gakki102.jpg'

surf = cv2.xfeatures2d.SURF_create()

FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params,search_params)

img1 = cv2.imread(imgname1)
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) #灰度处理图像
kp1, des1 = surf.detectAndCompute(img1,None)#des是描述子

img2 = cv2.imread(imgname2)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
kp2, des2 = surf.detectAndCompute(img2,None)

hmerge = np.hstack((gray1, gray2)) #水平拼接
cv2.imshow("gray", hmerge) #拼接显示为gray
cv2.waitKey(0)

img3 = cv2.drawKeypoints(img1,kp1,img1,color=(255,0,255))
img4 = cv2.drawKeypoints(img2,kp2,img2,color=(255,0,255))

hmerge = np.hstack((img3, img4)) #水平拼接
cv2.imshow("point", hmerge) #拼接显示为gray
cv2.waitKey(0)

matches = flann.knnMatch(des1,des2,k=2)

good = []
for m,n in matches:
  if m.distance < 0.7*n.distance:
    good.append([m])
img5 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
cv2.imshow("SURF", img5)
cv2.waitKey(0)
cv2.destroyAllWindows()

在cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,flags=2)下的匹配效果,比较杂乱,且会出错。

如果更换为cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2),明显优于上面的匹配,并且为预想的匹配区域,其效果为:

但就其错误点数量和匹配效果而言,并没有SIFT来的理想。

基于BFMatcher的ORB实现

ORB(Oriented Fast and Rotated BRIEF),结合Fast与Brief算法,并给Fast特征点增加了方向性,使得特征点具有旋转不变性,并提出了构造金字塔方法,解决尺度不变性,但文章中没有具体详述。特征提取是由FAST(Features from Accelerated Segment Test)算法发展来的,特征点描述是根据BRIEF(Binary Robust Independent Elementary Features)特征描述算法改进的。ORB特征是将FAST特征点的检测方法与BRIEF特征描述子结合起来,并在它们原来的基础上做了改进与优化。ORB主要解决BRIEF描述子不具备旋转不变性的问题。实验证明,ORB远优于之前的SIFT与SURF算法,ORB算法的速度是sift的100倍,是surf的10倍。

import numpy as np
import cv2
from matplotlib import pyplot as plt

imgname1 = 'E:/other/gakki101.jpg'
imgname2 = 'E:/other/gakki102.jpg'

orb = cv2.ORB_create()

img1 = cv2.imread(imgname1)
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) #灰度处理图像
kp1, des1 = orb.detectAndCompute(img1,None)#des是描述子

img2 = cv2.imread(imgname2)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
kp2, des2 = orb.detectAndCompute(img2,None)

hmerge = np.hstack((gray1, gray2)) #水平拼接
cv2.imshow("gray", hmerge) #拼接显示为gray
cv2.waitKey(0)

img3 = cv2.drawKeypoints(img1,kp1,img1,color=(255,0,255))
img4 = cv2.drawKeypoints(img2,kp2,img2,color=(255,0,255))

hmerge = np.hstack((img3, img4)) #水平拼接
cv2.imshow("point", hmerge) #拼接显示为gray
cv2.waitKey(0)

# BFMatcher解决匹配
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)
# 调整ratio
good = []
for m,n in matches:
  if m.distance < 0.75*n.distance:
    good.append([m])

img5 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
cv2.imshow("ORB", img5)
cv2.waitKey(0)
cv2.destroyAllWindows()

经显示观察到,ORB算法在特征点标记时数量较少,如图:

在cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,flags=2)下的匹配效果,比较杂乱,且会出错。

如果更换为cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2),明显优于上面的匹配,并且为预想的匹配区域,其效果为:

但同样会出现在同样的匹配方式上,效果不如SIFT的现象。
如下为使用FAST作为特征描述的关键代码和提取图像显示:

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('E:/other/gakki102.',0)

fast=cv2.FastFeatureDetector_create()#获取FAST角点探测器
kp=fast.detect(img,None)#描述符
img = cv2.drawKeypoints(img,kp,img,color=(255,255,0))#画到img上面
print ("Threshold: ", fast.getThreshold())#输出阈值
print ("nonmaxSuppression: ", fast.getNonmaxSuppression())#是否使用非极大值抑制
print ("Total Keypoints with nonmaxSuppression: ", len(kp))#特征点个数
cv2.imshow('fast',img)
cv2.waitKey(0)

如图为FAST特征提取的图像显示:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • python opencv之SIFT算法示例

    本文介绍了python opencv之SIFT算法示例,分享给大家,具体如下: 目标: 学习SIFT算法的概念 学习在图像中查找SIFT关键的和描述符 原理: (原理部分自己找了不少文章,内容中有不少自己理解和整理的东西,为了方便快速理解内容和能够快速理解原理,本文尽量不使用数学公式,仅仅使用文字来描述.本文中有很多引用别人文章的内容,仅供个人记录使用,若有错误,请指正出来,万分感谢) 之前的harris算法和Shi-Tomasi 算法,由于算法原理所致,具有旋转不变性,在目标图片发生旋转时依然

  • 应用OpenCV和Python进行SIFT算法的实现详解

    应用OpenCV和Python进行SIFT算法的实现 如下图为进行测试的gakki101和gakki102,分别验证基于BFmatcher.FlannBasedMatcher等的SIFT算法,对比其优劣.为体现出匹配效果对于旋转特性的优势,将图gakki101做成具有旋转特性的效果. 基于BFmatcher的SIFT实现 BFmatcher(Brute-Force Matching)暴力匹配,应用BFMatcher.knnMatch( )函数来进行核心的匹配,knnMatch(k-nearest

  • C++ 操作系统内存分配算法的实现详解

    目录 一.实验目的 二.实验内容 三.实验要求 四.代码实现 五.测试样例 一.实验目的 通过本实验帮助学生理解在动态分区管理方式下应怎样实现主存空间的分配和回收. 二.实验内容 在动态分区管理方式下采用不同的分配算法实现主存分配和实现主存回收. 三.实验要求 (1)可变分区方式是按作业需要的主存空间大小来分割分区的.当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业:若无,则作业不能装入.随着作业的装入.撤离.主存空间被分成许多个分区,有

  • Linux内核中红黑树算法的实现详解

    一.简介 平衡二叉树(BalancedBinary Tree或Height-Balanced Tree) 又称AVL树.它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1.若将二叉树上结点的平衡因子BF(BalanceFactor)定义为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有结点的平衡因子只可能是-1.0和1.(此段定义来自严蔚敏的<数据结构(C语言版)>) 红黑树 R-B Tree,全称是Red-B

  • python常用排序算法的实现代码

    这篇文章主要介绍了python常用排序算法的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 排序是计算机语言需要实现的基本算法之一,有序的数据结构会带来效率上的极大提升. 1.插入排序 插入排序默认当前被插入的序列是有序的,新元素插入到应该插入的位置,使得新序列仍然有序. def insertion_sort(old_list): n=len(old_list) k=0 for i in range(1,n): temp=old_lis

  • python Canny边缘检测算法的实现

    图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波.我们知道微分运算是求信号的变化率,具有加强高频分量的作用.在空域运算中来说,对图像的锐化就是计算微分.对于数字图像的离散信号,微分运算就变成计算差分或梯度.图像处理中有多种边缘检测(梯度)算子,常用的包括普通一阶差分,Robert算子(交叉差分),Sobel算子等等,是基于寻找梯度强度.拉普拉斯算子(二阶差分)是基于过零点检测.通过计算梯度,设置阀值,得到边缘图像. Canny边缘检测算子是一种多级检测算法.1986年由J

  • 对Python+opencv将图片生成视频的实例详解

    如下所示: import cv2 fps = 16 size = (width,height) videowriter = cv2.VideoWriter("a.avi",cv2.VideoWriter_fourcc('M','J','P','G'),fps,size) for i in range(1,200): img = cv2.imread('%d'.jpg % i) videowriter.write(img) 以上这篇对Python+opencv将图片生成视频的实例详解就是

  • Python OpenCV Canny边缘检测算法的原理实现详解

    目录 Gaussian smoothing Computing the gradient magnitude and orientation Non-maxima suppression Hysteresis thresholding OpenCV实现 Gaussian smoothing 总的来说,Canny边缘检测可以分为四个步骤: 由于边缘检测对噪声敏感,因此对图像应用高斯平滑以帮助减少噪声.具体做法是,采用一个5*5的高斯平滑滤波器对图像进行滤波处理. Computing the gra

  • Python+Opencv实现物体尺寸测量的方法详解

    目录 1.效果展示 2.项目介绍 3.项目搭建 4.utils.py文件代码展示与讲解 5.项目代码展示与讲解 6.项目资源 7.项目总结 1.效果展示 我们将以两种方式来展示我们这个项目的效果. 下面这是视频的实时检测,我分别用了盒子和盖子来检测,按理来说效果不应该怎么差的,但我实在没有找到合适的背景与物体.且我的摄像头使用的是外设,我不得不手持,所以存在一点点的抖动,但我可以保证,它是缺少了适合检测物体与背景. 我使用手机拍了一张照片并经过了ps修改了背景,效果不错. 2.项目介绍 本项目中

  • Python+OpenCV实现信用卡数字识别的方法详解

    目录 一.模板图像处理 二.信用卡图片预处理 一.模板图像处理 (1)灰度图.二值图转化 template = cv2.imread('C:/Users/bwy/Desktop/number.png') template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) cv_show('template_gray', template_gray) # 形成二值图像,因为要做轮廓检测 ret, template_thresh = cv2.thre

  • Python实现聚类K-means算法详解

    目录 手动实现 sklearn库中的KMeans K-means(K均值)算法是最简单的一种聚类算法,它期望最小化平方误差 注:为避免运行时间过长,通常设置一个最大运行轮数或最小调整幅度阈值,若到达最大轮数或调整幅度小于阈值,则停止运行. 下面我们用python来实现一下K-means算法:我们先尝试手动实现这个算法,再用sklearn库中的KMeans类来实现.数据我们采用<机器学习>的西瓜数据(P202表9.1): # 下面的内容保存在 melons.txt 中 # 第一列为西瓜的密度:第

随机推荐