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


Posted in Python onAugust 21, 2019

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

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

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

基于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()

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

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

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

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

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

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

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

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

基于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()

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

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

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

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

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

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

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

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

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

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

可见,虽然值越大,匹配的线条越密集,但错误匹配点也会增多,在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)下的匹配效果,比较杂乱,且会出错。

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

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

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

但就其错误点数量和匹配效果而言,并没有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算法在特征点标记时数量较少,如图:

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

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

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

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

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

但同样会出现在同样的匹配方式上,效果不如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特征提取的图像显示:

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

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

Python 相关文章推荐
Python 字符串定义
Sep 25 Python
Python的一些用法分享
Oct 07 Python
将Python代码嵌入C++程序进行编写的实例
Jul 31 Python
在Python的Flask框架中构建Web表单的教程
Jun 04 Python
python3 selenium 切换窗口的几种方法小结
May 21 Python
详解Python logging调用Logger.info方法的处理过程
Feb 12 Python
详解Python中pyautogui库的最全使用方法
Apr 01 Python
Win10用vscode打开anaconda环境中的python出错问题的解决
May 25 Python
Python类绑定方法及非绑定方法实例解析
Oct 09 Python
Python爬虫之Selenium库的使用方法
Jan 03 Python
PyQt5通过信号实现MVC的示例
Feb 06 Python
Python时间操作之pytz模块使用详解
Jun 14 Python
Python Django 添加首页尾页上一页下一页代码实例
Aug 21 #Python
Python Django 简单分页的实现代码解析
Aug 21 #Python
Django项目之Elasticsearch搜索引擎的实例
Aug 21 #Python
python爬虫豆瓣网的模拟登录实现
Aug 21 #Python
Python Django 页面上展示固定的页码数实现代码
Aug 21 #Python
详解Python利用random生成一个列表内的随机数
Aug 21 #Python
Python Django 封装分页成通用的模块详解
Aug 21 #Python
You might like
php中文字母数字验证码实现代码
2008/04/25 PHP
php获取字段名示例分享
2014/03/03 PHP
Laravel 4.2 中队列服务(queue)使用感受
2014/10/30 PHP
PHP执行SQL文件并将SQL文件导入到数据库
2015/09/17 PHP
优化WordPress的Google字体以加速国内服务器上的运行
2015/11/24 PHP
PHP文件上传类实例详解
2016/04/08 PHP
php使用flock阻塞写入文件和非阻塞写入文件的实例讲解
2017/07/10 PHP
PHP实现的简单组词算法示例
2018/04/10 PHP
关闭ie窗口清除Session的解决方法
2014/01/10 Javascript
js window.open弹出新的网页窗口
2014/01/16 Javascript
为开发者准备的10款最好的jQuery日历插件
2014/02/04 Javascript
原生javascript实现的分页插件pagenav
2014/08/28 Javascript
js实现选中复选框文字变色的方法
2015/08/14 Javascript
JavaScript中字符串与Unicode编码互相转换的实现方法
2015/12/18 Javascript
onclick和onblur冲突问题的快速解决方法
2016/04/28 Javascript
基于node.js的fs核心模块读写文件操作(实例讲解)
2017/09/10 Javascript
JS实现的tab页切换效果完整示例
2018/12/18 Javascript
浅谈Vue CLI 3结合Lerna进行UI框架设计
2019/04/14 Javascript
微信小程序实现消息框弹出动画
2020/04/18 Javascript
JS随机密码生成算法
2019/09/23 Javascript
NodeJs crypto加密制作token的实现代码
2019/11/15 NodeJs
微信小程序实现下滑到底部自动翻页功能
2020/03/07 Javascript
详解Vue.js3.0 组件是如何渲染为DOM的
2020/11/10 Javascript
[03:01]2014DOTA2国际邀请赛 DC:我是核弹粉,为Burning和国土祝福
2014/07/13 DOTA
Python 网页解析HTMLParse的实例详解
2017/08/10 Python
pytorch 共享参数的示例
2019/08/17 Python
独特的礼品和创新的科技产品:The Grommet
2018/02/24 全球购物
HQhair美国/加拿大:英国化妆品、美容及美发产品商城
2019/04/15 全球购物
单位创先争优活动方案
2014/01/26 职场文书
《狮子和兔子》教学反思
2014/03/02 职场文书
关于诚信的活动方案
2014/08/18 职场文书
教师查摆问题及整改措施
2014/10/11 职场文书
人身损害赔偿协议书格式
2014/11/01 职场文书
导游词之苏州寒山寺
2019/12/05 职场文书
php 解析非标准json、非规范json
2021/04/01 PHP
CentOS8.4安装Redis6.2.6的详细过程
2021/11/20 Redis