冒泡...恍恍惚惚了几天...还是要振作冲鸭!
SIFT
介绍
SIFT(Scale-invariant feature transform)即尺度不变特征转换。
SIFT特征是基于物体上的一些局部外观的兴趣点,与影像的大小和旋转无关。SIFT算法是用来提取图像的局部特征的算法,它的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。(注:查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。)
特点
1.SIFT特征是图像的局部特征,其对旋转、尺度缩放、亮度变化保持不变性,对视角变化、仿射变换、噪声也保持一定程度的稳定性;
2.独特性(Distinctiveness)好,信息量丰富,适用于在海量特征数据库中进行快速、准确的匹配;
3.多量性,即使少数的几个物体也可以产生大量的特征向量。
4.高速性,经优化的匹配算法甚至可以达到实时的要求。
5.可扩展性,可以很方便的与其他形式的特征向量进行联合。
算法
1、初始化操作,构建图像的金字塔
2、关键点搜索、定位、筛选
3、关键点方向赋值
4、关键点描述子的生成
分步骤详解:
(1)初始化操作,构建图像的金字塔
名词解释:
图像尺度空间:图像的尺度空间它可以模拟人在距离目标由近到远的过程中,目标在视网膜当中形成的图像的过程。尺度越大图像越模糊,相当于我们观察远处物体,这时候关注该物体的轮廓。比如可以这样理解,在过马路的时候我们只可以看清马路对面的行人的轮廓,但是他衣服的花纹就会显得比较模糊。
特点:
高斯模糊: 这里尺度空间的生成需要使用高斯模糊来实现,Lindeberg等人已经证明高斯卷积核是实现尺度变换的唯一线性核。高斯模糊是一种图像滤波器,它使用正态分布(高斯函数)计算模糊模板,并使用该模板与原图像做卷积运算,达到模糊图像的目的。
实现:
八度(octave): 八度就是在特定尺寸(长宽)下,经不同高斯核模糊的图像的集合。八度的集合是高斯金字塔。
第一步中的初始化操作就是通过高斯卷积核来实现尺度变换,从而模拟图像的多尺度特征,之后就是建立高斯金字塔和差分高斯金字塔。
建立高斯金字塔:高斯金字塔构建过程中,一般首先将图像扩大一倍,在扩大的图像的基础之上构建高斯金字塔,然后对该尺寸下图像进行高斯模糊,几幅模糊之后的图像集合构成了一个八度,然后对该八度下的最模糊的一幅图像进行下采样的过程,长和宽分别缩短一倍,图像面积变为原来四分之一。这幅图像就是下一个八度的初始图像,在初始图像图像的基础上完成属于这个八度的高斯模糊处理,以此类推完成整个算法所需要的所有八度构建,这样这个高斯金字塔就构建出来了。
建立差分高斯金字塔:差分,顾名思义,也就是要做差。对同一个八度的上下两幅相邻的图像做差得到插值图像,所有八度的这些插值图像的集合,就构成了差分高斯金字塔。差分高斯金字塔的好处是为后续的特征点的提取提供了方便。
关于高斯金字塔的生成细节可以参考:(https://blog.csdn.net/hit2015spring/article/details/52895367)
(2)关键点搜索、定位、筛选
寻找:实质是为了寻找尺度空间的极值点,因此每一个采样点要和它所有的相邻点比较,看其是否比它的图像域和尺度域的相邻点大或者小。
举个例子:如图所示,中间的检测点和它同尺度的8个相邻点和上下相邻尺度对应的9×2个点共8+18=26个点比较,以确保在尺度空间和二维图像空间都检测到极值点。 一个点如果在DOG尺度空间本层以及上下两层的26个领域中是最大或最小值时,就认为该点是图像在该尺度下的一个特征点。下图中将叉号点要比较的26个点都标为了绿色。
定位:
在离散空间下寻找的点不一定是符合的,所以需要定位。
筛选:在DOG函数中,它存在比较强的边缘效应,而当特征点在边缘的时候,这些点就会很不稳定,所以,我们应该把这些边缘效应很强的点找出来,进行筛选。
详细过程可参见(https://blog.csdn.net/hit2015spring/article/details/52972890)
至此,我们得到了关键点的位置信息和尺度信息(x,y,σ)。
(3)关键点方向赋值
为了实现图像的旋转不变性,需要根据检测到的关键点的局部图像结构为特征点方向赋值。
梯度直方图:方向直方图的核心是统计以关键点为原点,一定区域内的图像像素点对关键点方向生成所作的贡献。
由此可以得到每一个点的幅值和幅角,但是由于与特征点的距离不同,各个点对特征点的支持也是不一样的,所以离得远的就支持弱一点,离得近的就支持大一点,这里面的权重就要通过一个规则来管理,而这个规则就是高斯滤波,即以特征点为圆心,做一个高斯滤波,给它周围的点加上一个高斯权重。高斯函数的方差当然还是与这个特征点所在的图像层的尺度有关。
直方图峰值代表该关键点邻域内图像梯度的主方向,当存在另一个相当于主峰值。
(4)关键点描述子的生成
注意:这个描述子不但包括关键点,也包括关键点周围对其有贡献的像素点。
a.描述子采样区域
b.区域坐标旋转:为了使sift特征点具有旋转不变性,要以特征点为中心,在附近邻域内旋转θ角,即旋转为特征点的方向。
c.计算采样区域梯度直方图
将旋转后区域划分为d×d个子区域(每个区域间隔为mσ像元),在子区域内计算8个方向的梯度直方图,绘制每个方向梯度方向的累加值,形成一个种子点。与求主方向不同的是,此时,每个子区域梯度方向直方图将0°~360°划分为8个方向区间,每个区间为45°。即每个种子点有8个方向区间的梯度强度信息。然后对子区域的像素的梯度大小采用mσd/2的高斯加权函数加权。由于存在d×d,即4×4个子区域,所以最终共有4×4×8=128个数据,形成128维SIFT特征矢量。特征向量形成后,为了去除光照变化的影响,需要对它们进行归一化处理。
SIFT的缺点
- 实时性不高。
- 有时特征点较少。
- 对边缘光滑的目标无法准确提取特征点。
4.模糊的图像和边缘平滑的图像,检测出的特征点过少,对圆更是无能为力.
代码
import cv2
import numpy as np
img = cv2.imread('F:/3.jpg') # 读取要处理的图片
alg = input('Select an Alg --> ')
def fd(algorithm):
if algorithm == 'SIFT':
return cv2.xfeatures2d.SIFT_create()
if algorithm == 'SURF':
threshold = input('Enter a threshold --> ') # 提示输入SURF算法所采用的阈值
return cv2.xfeatures2d.SURF_create(float(threshold))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图像
fd_alg = fd(alg)
keypoints, descriptor = fd_alg.detectAndCompute(gray, None)
img = cv2.drawKeypoints(image=img, outImage=img, keypoints=keypoints,
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,
color=(51, 163, 236))
cv2.imshow('keypoints', img)
while (True):
if cv2.waitKey(30) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
结果
参考(https://blog.csdn.net/happyer88/article/details/45817305 )
(https://blog.csdn.net/zddblog/article/details/7521424)
Finally~so tired!