学到的数学知识:正态分布,泰勒公式
正态分布——用来计算权重,首先转换成标准正太分布函数f(u),.每一个u就对应一个概率
泰勒公式——用来拟合函数,原因是离散极值点往往不是真实极值点,所以需要对点进行拟合,拟合过程中的偏导数利用“有限差分法求导”,公式如下:
第二天数学知识:正定、负定矩阵、海森矩阵
海森矩阵的正、负定矩阵——目的是用来求极大值或极小值,正定矩阵有极小值,负定矩阵有极大值,主子式行列式结果全部是正数是正定矩阵,主子式行列式结果全部是负数是负定矩阵,有正有负非定矩阵
海森矩阵——是函数二阶偏导数形成的矩阵,应用见下图:
尺度空间——目的是作为高斯模糊正态分布的参数sigam,尺度空间L(x,y,sigam)=l(x,y)G(x,y,sigam),尺度空间为原图与高斯卷积核卷积得到的。尺度空间参数:sigam(o,s) = sigam02**(O+s/S) 其中O是组数,S是该组总层数,s是该层的索引值, O = log2(min(M,N)) - t M,N分别为矩阵的行、列,t为金字塔中最小尺寸对应2的对数
高斯模糊卷积核——是一个符合正太分布函数的矩阵,参数有x,y,sigam。u = [(x-2/m)**2+(y-2/n)2]/sigam2,通过参数可求出各点对应的权重。所以sigam是形状参数,越小,图像越尖锐,越大,图像越柔和。
高斯金字塔——是图像通过高斯模糊卷积核进行步长不为1的卷积操作分组,步长为1的卷积操作分层或直接通过步长不为1的卷积操作即分组又分层。 组——不同组的图像大小不同,差别为步长的n次方。 层——同组各层的图像大小相同,卷积核不同。
高斯差分金字塔(DOG算子)——是同组中,每两层进行一次高斯差分求出高斯差分图谱。L(x,y,sigam) = L(x,y,sigam(s+1)) - L(x,y,sigam(s))
DOG极值点——是某个点与本层周围8个点,及上下两层各9个点,共计26个点做比较,提取极值点。因为极值点与上下两层相关,所以最上层,与最下层不能提取极值点,也就是说如果想要获取S个尺度极值点,就需要S+2层高斯差分金字塔,需要S+3层高斯金字塔
去除边缘响应——利用Hessian矩阵,矩阵迹的平方/矩阵行列式<一个阈值(一般为10) 满足既为真正的极值点,这里只知道Hessian矩阵的特征值和曲率成正比,至于为什么这样可以消除边缘响应还不明白,看效果图只是比消除前特征点少了。矩阵的迹是两个特征值的和,两个特征值的积就是行列式。高斯函数的二阶偏导数如下:
上面已经求得了关键点
接下来根据关键点所在的尺度空间,求出关键点的角度及幅度,绘制直方图,提取特征向量,公式如下:
直方图邻域范围是边长21.5*sigam的正方形,直方图为角度——幅度,将0~360度划分成8分,幅度在响应角度范围内提取权重,这里和HOG算法类似,最后将幅度最高的作为主方向,幅度为主方向幅度80%以上为辅方向,因为是离散的,所以需要对它进行二次插值,求得最大值,二次插值算法如下:
#coding:utf-8
def f(x):
pass
def get_min(f,x1,x2,x3):
if f(x1)<f(x2) or f(x2)>f(x3):
print('值错误')
return
a = int(get_two(x1,x2,x3))
if f(a)>f(x2):
get_min(f,x1,x2,a)
elif f(a)<f(x2):
get_min(s,x1,a,x2)
elif:
return a
def get_two(x1,x2,x3):
pass
有了关键点的直方图,提取了8个方向的特征向量, 将关键点附近的区域划分为d*d(Lowe建议d=4)个子区域,每个子区域作为一个种子点,每个种子点有8个方向。所需图像窗口边长为3x3xσ_oct x(d+1) 。在考虑到旋转因素(方便下一步将坐标轴旋转到关键点的方向),这里直接利用旋转矩阵,角度设置为主方向。考虑到实际计算时,需要采用三线性插值(三线性插值与双线性插值类似,只是维度是三维空间),权重公式如下
x,y,z分别为△x,△y,△z,x1/scale -int(x1/scale)
W0 = (1 - x)(1 - y)(1 - z)
W1 = x(1 - y)(1 - z)
W2 = (1 - x)y(1 - z)
W3 = xy(1 - z)
W4 = (1 - x)(1 - y)z
W5 = x(1 - y)z
W6 = (1 - x)yz
W7 = xyz
有了448 维度的特征向量后,因为要考虑光照影响,所以需要多其进行归一化,单个幅度/np.sum(幅度)!结束了!!
总结一下:一张灰度图,创建尺度空间,计算关键点,求出角度和幅度,创建角度幅度直方图,提取特征向量,提取4*4邻域范围内特征向量,最后归一化!!!
虽然现在有可调用api,但通过学习,掌握了不少数学知识,包括上面没提到的牛顿法求根——是函数的一阶泰勒展开式,f(x)=0=f(x0)/f’(x0)+x-x0
附上调用api的代码和ORB检测差不多:
无语,竟然出现版本问题,降版本降到.3.4.2.16才解决,而且安装的是opencv-contrib-python
import cv2
import numpy as np
path = 'test.jpg'
image = cv2.imread(path,0)
detector = cv2.xfeatures2d.SIFT_create()
kp_point,des = detector.detectAndCompute(image,None)
image = cv2.drawKeypoints(image,kp_point,image,color=(0,255,0))
cv2.imshow('test',image)
cv2.waitKey(0)
cv2.destroyWindows()