1.SIFT算法
1.1SIFT原理
SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点,边缘点,暗区的亮点以及亮区的暗点等。
Lowe将SIFT算法分解为如下四步:
1.尺度空间极值检测:搜索所有尺度上的图像位置,通过高斯差分函数来识别潜在的对于尺度和旋转不变的关键点
2.关键点定位:在每个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于他们的稳定程度
3.关键点方向确定:基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像数据的操作都相对于关键点的方向、尺度和位置进行变换,从而保证了对于这些变换的不变性
4.关键点描述:在每个关键点周围的领域内,在选定的尺度上测量图像局部的梯度。这些梯度作为关键点的描述符,它允许比较大的局部形状的变形或光照变化
由于DoG对噪声和边缘比较敏感,因此在上面高斯差分金字塔中检测到的局部极值点需经过进一步的检验才能精确定位为特征点
DoG算法对边界非常敏感,所以我们必须要把边界去除。Harris算法除了可以用于角点检测之外还可以用于检测边界。从Harris角点检测的算法中,当一个特征值远远大于另一个特征值时检测到的是边界。那在DoG算法中欠佳的关键点在平行边缘的方向有较大的主曲率,而在垂直于边缘的方向有较小的曲率,两者的比值如果高于某个阈值(在opencv中叫做边界阈值),就认为该关键点为边界,将被忽略,一般将该阈值设置为10。
1.2尺度空间极值检测
1.构建高斯金字塔
2.构建高斯差分金字塔
3.极值点检测
1.3构建高斯金字塔
1.原图像上采集,得到最低的一组结果
2.使用降采用获取每一组的结果,对于每一组的图像进行高斯模糊,得到每一组中不同尺度的结果
3.每一组中创建s+2个图像
1.4极值点检测
对于图像中的一个像素点而言,它需要与自己周围的8领域,以及尺度空间中上下两层的相邻的18(2x9)个点相比。如果是局部最大值,它就可能是一个关键点。基本上来说关键点是图像在相应尺度空间中的最好代表。
1.5关键点定位
1.低对比度的去除
2.检测到边界的去除
1.6关键点方向确定
完成关键点梯度计算后,使用直方图统计关键点领域内像素的梯度幅值和方向。具体做法是,将360°分为36柱,每10°为一柱。然后在r为半径的区域内,将梯度方向在某一个柱内的像素找出来,然后将他们的幅值相加在一起作为柱的高度。
每个特征点必须分配一个主方向,还需要一个或多个辅方向,增加辅方向的目的 是为了增强图像匹配的鲁棒性。辅方向的定义是,当一个柱体的高度大于主方向柱体高度的80%时,则该柱体所代表的方向就是给特征点的辅方向。
直方图的峰值,即最高的柱代表的方向是特征点领域范围内图像梯度的主方向,但该柱体代表的角度是一个范围,所以我们还要对离散的直方图进行插值拟合,以得到更精确的方向角度值。利用抛物线对离散的直方图进行拟合,如图所示:
1.7关键点描述
1.以特征点为中心,将其附近领域划分为d*dd*d个子区域(一般取d=4),每个子区域都是一个正方形,边长为3a
2.以特征点为中心,将坐标轴旋转为关键点的主方向
3.计算子区域内的像素的梯度,并按照a=0.5d进行高斯加权,然后插值计算得到每个种子点的八个方向的梯度
4.构建d*d*8个值来描述当前关键点
总结
SIFT在图像的不变特征提取方面拥有无与伦比的优势,但并不完美,仍然存在实时性不高,有时特征点较少,对边缘光滑的目标无法准确提取特征点等缺陷,自SIFT算法问世以来,人们就一直对其进行优化和改进,其中最著名的就是SURF算法。
2.SURF算法
2.1SURF原理
是SIFT算法的增强版,它的计算量小,运行速度快,提取的特征与SIFT几乎相同
3.实现
在opencv中利用SIFT检测关键点的流程如下:
1.实例化 sift
sift=cv.xfeatures2d.SIFT_create()
2.利用sift.detectAndCompute()检测关键点并计算
kp,des=sift.detectAndCompute(gray,None)
参数:
-gray:进行关键点检测的图像,注意是灰度图像
返回:
-kp:关键点信息,包括位置,尺度,方向
-des:关键点描述,每个关键点对应128个梯度信息的特征向量
3.将关键点检测结果绘制在图像上
cv.drawKeypoints(image,keypoints,outputimage,color,flags)
参数:
-image:原始图像
-keypoints:关键点信息,将其绘制在图像上
-outputimage:输出图像,可以是原始图像
-color:颜色设置,通过修改(b,g,r)的值,更改画笔的颜色,b=蓝色,g=绿色,r=红色
-flags:绘制功能的标识设置
1.cv2.DRAW_MSTCHES_FLAGS_DEFAULT:创建输出图像矩阵,使用现存的输出图像绘制匹配对和特征点,对每一个关键点只绘制中间点
2.cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG:不创建输出图像矩阵,而是在输出图像上绘制匹配对
3.cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS:对每一个特征点绘制带大小和方向的关键点图形
4.cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
#1.读取图像
img=cv.imread('shi-tomas.jpg')
gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#2.sift关键点检测
#2.1实例化sift对象
sift=cv.xfeatures2d.SIFT_create()
#2.2关键点检测,kp关键点信息包括方向,尺度,位置信息,des是关键点的描述符
kp,des=sift.detectAndCompute(gray,None)
#2.3在图像上绘制关键点的检测结果
cv.drawKeypoints(img,kp,img,flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
#图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(img[:,:,::-1]),plt.title('sift检测')
plt.xticks([]),plt.yticks([])
plt.show()
总结:
SIFT原理:
-尺度空间极值检测:构建高斯金字塔,高斯差分金字塔,检测极值点
-关键点定位:去除对比度较小和边缘对极值点的影响
-关键点方向确定:利用梯度直方图确定关键点的方向
-关键点描述:对关键点周围图像区域分块,计算块内的梯度直方图,生成具有特征向量,对关键点信息进行描述。
API:cv.xfeatures2d.SIFT_create()
SURF算法:
对SIFT算法的改进,在尺度空间极值检测,关键点方向确定,关键点描述方面都有改进,提高效率
3.Fast算法
3.1原理
FAST(全称Feature from accelerated segment test)是一种用于角点检测的算法,该算法的原理是取图像中检测点,以该点为圆心领域内像素点判断检测点是否为角点,通俗的将就是若一个像素周围有一定数量的像素与该点像素值不同,则认为其为角点。
虽然这个检测器的效率很高,但它有以下几条缺点:
-获得的候选点比较多
-特征点的选取不是最优的,因为它的效果取决与要解决的问题和角点的分布情况
-进行非特征点判别时大量的点被丢弃
-检测到的很多特征点都是相邻的
前三个问题可以通过机器学习的方法解决,最后一个问题可以使用非最大值抑制的方法解决
3.2机器学习的角点检测器
1.选择一组训练图片(最好是最后应用相关的图片)
2.使用FAST算法找出每幅图像的特征点,对图像中的每个特征点,将其周围的16个像素存储构成一个向量p
3.每一个特征点的16像素点都属于一下三类中的一种
4.根据这些像素点的分类,特征向量p也 被分为3个子集:pd,ps,pb
5.定义一个新的布尔变量Kp,如果p是角点就设置为True,如果不是就设置为False
6.利用特征向量p,目标值是$K_p$,训练ID3树(决策树分类器)
7.将构建好的决策树运用于其他图像的快速得到检测
3.3非极大值抑制
在筛选出来的候选角点中有很多是紧凑在一起的,需要通过非极大值抑制来消除这种影响
为所有的候选角点都确定一个打分函数V,V的值可以这样计算:先分别计算Ip与圆上16个点的像素值差值,取绝对值,再将这16个绝对值相加
3.4FAST算法的基本流程
1.在图像中选取一个像素点p,来判断它是不是关键点
2.以r为半径画圆,覆盖p点周围的M个像素
3.设置一个阈值t,如果在这16个像素点中存在n个连续像素点的灰度值都高于Ip+t,或者低于Ip-t,那么像素点p就被认为是一个角点
4.非特征点判别:首先对候选点的周围每个90度的点:1,9,5,13进行测试
4.实现
opencv中的FAST检测算法是用传统方法实现的
1.实例化fast
fast=cv.FastFeatureDetector_create(threshold,nonmaxSuppression)
参数:
-threshold:阈值t,有默认值10
-nonmaxSuppression:是否进行非极大值抑制,默认值True
返回:
-Fast:创建的FastFeatureDetector对象
2.利用fast.detect检测关键点,没有对应的关键点描述
kp=fast.detect(grayImg,None)
参数:
-grayImg:进行关键点检测的图像,注意是灰度图像
返回:
-kp:关键点信息,包括位置,尺度,方向信息
3.将关键点检测结果绘制在图像上,与在sift中是一样的
cv.drawKeypoints(image,keypoints,outputimage,color,flags)
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
#1.读取图像
img=cv.imread('shi-tomas.jpg')
#2.Fast角点检测
#2.1创建一个Fast对象,传入阈值,注意:可以处理彩色空间图像
fast=cv.FastFeatureDetector_create(threshold=30)
#2.2检测图像上的关键点
kp=fast.detect(img,None)
#2.3在图像上绘制关键点
img2=cv.drawKeypoints(img,kp,None,color=(0,0,255))
#2.4输出默认参数
print('Threshold:{}'.format(fast.getThreshold()))
print('nonmaxSuppression:{}'.format(fast.getNonmaxSuppression()))
print('neighborhood:{}'.format(fast.getType()))
print('Total keypoints with nonmaxSuppression:{}'.format(len(kp)))
#2.5关闭非极大值抑制
fast.setNonmaxSuppression(0)
kp=fast.detect(img,None)
print('Total keypoints with nonmaxSuppression:{}'.format(len(kp)))
#2.6绘制为进行非极大值抑制的结果
img3=cv.drawKeypoints(img,kp,None,color=(0,0,255))
#绘制图像
fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,8),dpi=100)
axes[0].imshow(img2[:,:,::-1])
axes[0].set_title('加入非极大值抑制')
axes[1].imshow(img3[:,:,::-1])
axes[1].set_title('未加入非极大值抑制')
plt.show()