大纲
SIFT算法是为了解决图片的匹配问题,想要从图像中提取一种对图像的大小和旋转变化保持鲁棒的特征,从而实现匹配。这一算法的灵感也十分的直观:人眼观测两张图片是否匹配时会注意到其中的典型区域(特征点部分),如果我们能够实现这一特征点区域提取过程,再对所提取到的区域进行描述就可以实现特征匹配了。于是问题就演变成了以下几个子问题:
以上几个问题在SIFT算法里都用了很有意思的trick,后续会一一介绍。
引入高斯金字塔的目的在引言中已经介绍过了–解决图片缩放及尺度变化下特征提取的问题,高斯金字塔的Intuition有两个:1. 人看物体时近大远小,可以对图片下采样实现(金字塔->组);2. 人看物体时近处清晰,远处模糊,可以对图像高斯平滑实现(高斯->层);具体的推导可以参见我的另一篇博客:
Opencv学习笔记(六)图像金字塔
在SIFT里,高斯金字塔的层数和组数有着如下设定:
组数:
O
=
[
l
o
g
2
m
i
n
(
M
,
N
)
]
−
3
O=[log_2min(M,N)]-3
O=[log2min(M,N)]−3
层数:
S
=
n
+
3
S=n+3
S=n+3
组数的设定是来自于提出SIFT算法的原始论文给出的经验值,理论上来说知要
O
≤
[
l
o
g
2
m
i
n
(
M
,
N
)
]
O\leq[log_2min(M,N)]
O≤[log2min(M,N)]即可,层数的设定则是有着理论依据的,这里的
n
n
n是我们想要提取特征点的图片层数,由于提取出高斯金字塔后需要计算层间差分以获得高斯差分金字塔(DOG, Difference of Gausssian),高斯金字塔层数需要比DOG层数多1,而计算特征值时要求在尺度层面,即上下相邻层间计算,则DOG层数要比特征层数多2,则要求
S
=
n
+
3
S=n+3
S=n+3。
附:在SIFT中对于高斯金字塔有几个需要补充的知识点。
通过高斯金字塔,我们获取了不同尺度的图片,接下来的问题是如何获取高频区域呢,一个很简单的思路就是按照边缘检测的算法使用差分滤波器如拉普拉斯滤波器、sobel滤波器在图片上滑动找到灰度值变化剧烈的区域。而经前人研究,归一化的高斯拉普拉斯算子的极大值极小值相较于其他特征提取函数可以获得最稳定的图像特征,因此我们打算使用归一化的高斯拉普拉斯算子在多尺度图片上提取特征,但是使用这种方式提取复杂度会很高,又尺度归一化高斯拉普拉斯算子和DOG函数有着如下关系:
G
(
x
,
y
,
k
σ
)
−
G
(
x
,
y
,
σ
)
≈
(
k
−
1
)
σ
2
∇
2
G
G(x,y,k\sigma)-G(x,y,\sigma)\approx(k-1)\sigma^2 \nabla^2 G
G(x,y,kσ)−G(x,y,σ)≈(k−1)σ2∇2G
证明如下:
忽略高斯函数系数:
G
(
x
,
y
,
σ
)
=
1
σ
2
e
x
p
(
−
x
2
+
y
2
2
σ
2
)
∂
G
∂
x
=
−
x
σ
4
e
x
p
(
−
x
2
+
y
2
2
σ
2
)
∂
2
G
∂
x
2
=
−
σ
2
+
x
2
σ
6
e
x
p
(
−
x
2
+
y
2
2
σ
2
)
∇
2
G
(
x
,
y
)
=
∂
2
G
∂
x
2
+
∂
2
G
∂
y
2
=
−
2
σ
2
+
x
2
+
y
2
σ
6
e
x
p
(
−
x
2
+
y
2
2
σ
2
)
∂
G
∂
σ
=
−
2
σ
2
+
x
2
+
y
2
σ
5
e
x
p
(
−
x
2
+
y
2
2
σ
2
)
⇒
σ
∇
2
G
=
∂
G
∂
σ
\begin{aligned} &G(x,y,\sigma)=\frac{1}{\sigma^2}exp(-\frac{x^2+y^2}{2\sigma^2})\\ &\frac{\partial{G}}{\partial x}=-\frac{x}{\sigma^4}exp(-\frac{x^2+y^2}{2\sigma^2})\\ &\frac{\partial^2{G}}{\partial x^2}=\frac{-\sigma^2+x^2}{\sigma^6}exp(-\frac{x^2+y^2}{2\sigma^2})\\ &\nabla^2 G(x,y)=\frac{\partial^2{G}}{\partial x^2}+\frac{\partial^2{G}}{\partial y^2}\\ &\qquad \qquad \ =\frac{-2\sigma^2+x^2+y^2}{\sigma^6}exp(-\frac{x^2+y^2}{2\sigma^2})\\ &\frac{\partial{G}}{\partial \sigma}=\frac{-2\sigma^2+x^2+y^2}{\sigma^5}exp(-\frac{x^2+y^2}{2\sigma^2})\\ &\Rightarrow\\ &\sigma\nabla^2G=\frac{\partial G}{\partial \sigma} \end{aligned}
G(x,y,σ)=σ21exp(−2σ2x2+y2)∂x∂G=−σ4xexp(−2σ2x2+y2)∂x2∂2G=σ6−σ2+x2exp(−2σ2x2+y2)∇2G(x,y)=∂x2∂2G+∂y2∂2G =σ6−2σ2+x2+y2exp(−2σ2x2+y2)∂σ∂G=σ5−2σ2+x2+y2exp(−2σ2x2+y2)⇒σ∇2G=∂σ∂G
又对于差分高斯金字塔有:
D
O
G
=
G
(
x
,
y
,
k
σ
)
−
G
(
x
,
y
,
σ
)
(
k
−
1
)
σ
≈
∂
G
∂
σ
D
O
G
≈
(
k
−
1
)
σ
2
∇
2
G
\begin{aligned} &DOG=\frac{G(x,y,k\sigma)-G(x,y,\sigma)}{(k-1)\sigma}\approx \frac{\partial G}{\partial \sigma}\\ & DOG \approx(k-1)\sigma^2\nabla^2G \end {aligned}
DOG=(k−1)σG(x,y,kσ)−G(x,y,σ)≈∂σ∂GDOG≈(k−1)σ2∇2G
由此我们不再需要在高斯金子塔上进行卷积操作,只需要计算在尺度层面
σ
\sigma
σ进行层间差分得到高斯差分金字塔(DOG),即完成了特征提取的操作。

得到DOG后,我们理论上来说就已经获得了特征值,但我们需要对特征值进行一些处理,就像我们在cannny边缘检测中使用的非极大值抑制等思路,去掉没那么特征的特征值。
简单的阈值化去除掉变换没有那么剧烈的点,这些点就有可能是噪声引起的,算是在高斯拉普拉斯之外又加了一层去噪措施。
v
a
l
=
{
v
a
l
a
b
s
(
v
a
l
)
>
0.5
T
n
0
o
t
h
e
r
w
i
s
e
val=\begin{cases} val & abs(val)>0.5\frac{T}{n}\\ 0 & otherwise \end{cases}
val={val0abs(val)>0.5nTotherwise
这里的
T
T
T为经验值0.04,
n
n
n为之前提过的提取特征点数目。
非极大值一致的思路就和在其他算法中的一样,我们要求选取出的特征值应该是其领域范围内的极值,不同之处在于其他算法要求的只是图像这一二维平面内的极值,而这里要求还要在尺度
σ
\sigma
σ这一层面上也是极值,这也承接了前文DOG层数要比提取特征所用层数多2的设定。

由于我们的图片在
x
,
y
,
σ
x,y,\sigma
x,y,σ方向上都只能取到离散值,即使通过前两个步骤取到了一些特征点,但这些特征点都不够精确,我们需要引入二阶泰勒函数对齐进行修正,使得特征点可以出现在亚像素(亚尺度)位置。

f
(
X
)
=
f
(
X
0
)
+
∂
f
T
∂
X
X
^
+
1
2
X
T
^
∂
2
f
∂
X
2
X
^
f(X)=f(X_0)+\frac{\partial f^T}{\partial X}\hat{X}+\frac{1}{2}\hat{X^T}\frac{\partial^2 f}{\partial X^2}\hat{X}
f(X)=f(X0)+∂X∂fTX^+21XT^∂X2∂2fX^
上式给出了特征点
X
0
X_0
X0附近函数的近似值
f
(
x
)
f(x)
f(x),其中
X
^
=
X
−
X
0
\hat{X}=X-X_0
X^=X−X0,对该式求取一阶导数零点,即可得函数实际极值点位置与
X
0
X_0
X0的距离,从而对离散特征点修正到亚尺度处。
f
′
(
X
)
=
∂
f
T
∂
X
+
∂
f
2
∂
X
2
X
^
f'(X)=\frac{\partial f^T}{\partial X}+\frac{\partial f^2}{\partial X^2}\hat{X}
f′(X)=∂X∂fT+∂X2∂f2X^
X
^
e
x
=
−
∂
2
f
−
1
∂
X
2
∂
f
∂
X
\hat{X}_{ex}=-\frac{\partial^2 f^{-1}}{\partial X^2}\frac{\partial f}{\partial X}
X^ex=−∂X2∂2f−1∂X∂f
带入前式可求取新的特征点的灰度值:
f
(
X
′
)
=
f
(
X
0
)
+
1
2
∂
f
T
∂
X
′
X
^
e
x
f(X')=f(X_0)+\frac{1}{2}\frac{\partial f^T}{\partial X'}\hat{X}_{ex}
f(X′)=f(X0)+21∂X′∂fTX^ex
需要注意的是,上式是一个不断迭代的过程,也即根据当前特征点二阶泰勒求取新的特征点这一过程会不断重复直到满足终止条件,如
X
^
\hat{X}
X^过小。另需注意当所得解超出离散极值点一定范围时需要舍去,因为二阶泰勒拟合只在其附近有效。
附:一个挺有意思的点在于这里的迭代目的和梯度下降法里的迭代并不是同一个目的,梯度下降里我们求取的是函数在某点的梯度,因为我们很难对复杂非线性的神经网络求除其一阶导数零点,即使求取到了也可能落入局部极值;而这里我们是直接求到了函数的一阶零点,迭代的目的是因为函数本身是一种近似,泰勒展开只取到了第二项,需要不断对原函数进行近似。这两种迭代的目的并不相同。
目的和之间的阈值化类似,同样是去除掉没那么剧烈变化的特征点。要求:
∣
f
(
x
)
∣
≥
T
n
|f(x)|\geq\frac{T}{n}
∣f(x)∣≥nT
引言中提过我们想要提取的特征点为角点而非边缘,而前述一系列措施只能保证取到灰度值变换剧烈的点,而边缘点同样符合这一特征,因此我们将通过以下方式去除边缘点。
接下来解释以下这几个步骤的意义,角点和边缘点的区别在于边缘在图像中表现为一条线,垂直于线的方向频率高,沿着线的方向频率比较低;而角点则在多(大于2)个方向方向出现强高频分量。黑森矩阵实际上是函数的二阶偏导构成的矩阵,可以反应函数的曲率变化状况。又对于二次型矩阵有如下性质:
由性质1,2我们可以推导处当
D
e
t
(
H
)
<
0
Det(H)<0
Det(H)<0时,特征点为非极值点,舍去;
由性质1,3我们可以推导出当
T
r
(
H
)
D
e
t
(
H
)
=
(
α
+
β
)
2
α
2
β
2
\frac{Tr(H)}{Det(H)}=\frac{(\alpha+\beta)^2}{\alpha^2\beta^2}
Det(H)Tr(H)=α2β2(α+β)2过小时,由两特征特征向量的比值
γ
\gamma
γ构成的式子
(
γ
+
1
)
2
γ
\frac{(\gamma+1)^2}{\gamma}
γ(γ+1)2同样较小,且对勾函数在
γ
>
1
\gamma>1
γ>1时单增,我们可以根据
T
r
(
H
)
D
e
t
(
H
)
\frac{Tr(H)}{Det(H)}
Det(H)Tr(H)大小判断特征向量的相对大小,该值过小,说明函数在该点不同方向上的变化非常不均匀,类似于边缘,舍去。
通过前述步骤,我们已经获得了不同尺寸层面上的稳定特征点,接下来需要对其进行描述。
引言中提到为了使特征点拥有旋转不变性,我们会将特征点区域统一旋转到特定方向,这一方向即为特征点区域的主方向,因此我们需要先确定主方向。
计算方式为:统计在离该特征点尺度
σ
∗
\sigma^*
σ∗最近的尺度层
σ
o
c
t
上
,
\sigma_{oct}上,
σoct上,以特征点为中心
3
σ
′
=
3
∗
1.5
σ
o
c
t
3\sigma'=3*1.5\sigma_{oct}
3σ′=3∗1.5σoct范围内的像素的梯度幅值及方向,对于范围内的梯度幅值用
1.5
σ
∗
1.5\sigma^*
1.5σ∗高斯核滤波以实现距离加权。得到一系列梯度幅值和方向对
p
a
i
r
s
=
{
a
m
p
,
a
n
g
}
pairs=\{amp,ang\}
pairs={amp,ang}后,将
360
°
360°
360°方向划分为多个bins,将包含相应
a
n
g
ang
ang的
p
a
i
r
s
pairs
pairs中的
a
m
p
amp
amp值累加到对应的bins上,如果
a
n
g
ang
ang在两个bins划分间则根据距离分配
a
m
p
amp
amp。(此处和HOG算法类似,可自行查阅)。最终可以获得特征点区域内幅值-方向直方图,选取其中幅值最大的方向作为主方向。

附:这里的几个参数像是统计区域的半径,高斯加权的方差,有着不同的设置方式,但内在思路是一致的。此外如果在主方向之外出现了幅值达到了主方向幅值80%的其他方向,我们会将其作为辅方向,后续匹配时会出现两个位置、尺度相同但方向不同的两个特征点区域。
获得了特征点区域的主方向之后,我们就可以利用该值计算出有旋转不变性的描述子了。首先还是和前一步类似,统计该特征点所在尺度层面一定区域内的梯度幅值和方向,实施起来略有不同。

至此SIFT算法就讲解完毕了,匹配的部分根据提的特征采用其他的聚类算法即可,总的来说这个算法还是有一定难度,本文也只是针对其他博客没有提到的细节引入了数学推导,使得整个思考过程更加连贯,更加详细的数学证明如有限差分法还请移步参考。
SIFT原理部分:
SIFT算法详解
SIFT算法原理详解
SIFT算法
SIFT(尺度不变特征变换)
LOG和DOG关系部分:
LOG算子
黑森矩阵意义部分:
Hessian矩阵以及在图像中的应用
Hessian 矩阵的特征值有什么含义?
Hessian矩阵与多元函数极值
Hessian矩阵(黑塞矩阵)
为何矩阵特征值乘积等于矩阵行列式值?
高斯相乘部分:
两个高斯函数的卷积仍为一高斯函数
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva
一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su
TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是
我一直在尝试用Ruby实现Luhn算法。我一直在执行以下步骤:该公式根据其包含的校验位验证数字,该校验位通常附加到部分帐号以生成完整帐号。此帐号必须通过以下测试:从最右边的校验位开始向左移动,每第二个数字的值加倍。将乘积的数字(例如,10=1+0=1、14=1+4=5)与原始数字的未加倍数字相加。如果总模10等于0(如果总和以零结尾),则根据Luhn公式该数字有效;否则无效。http://en.wikipedia.org/wiki/Luhn_algorithm这是我想出的:defvalidCreditCard(cardNumber)sum=0nums=cardNumber.to_s.s
下面是我写的一个计算斐波那契数列中的值的方法:deffib(n)ifn==0return0endifn==1return1endifn>=2returnfib(n-1)+(fib(n-2))endend它工作到n=14,但在那之后我收到一条消息说程序响应时间太长(我正在使用repl.it)。有人知道为什么会这样吗? 最佳答案 Naivefibonacci进行了大量的重复计算-在fib(14)fib(4)中计算了很多次。您可以将内存添加到您的算法中以使其更快:deffib(n,memo={})ifn==0||n==1returnnen
为了防止在迁移到生产站点期间出现数据库事务错误,我们遵循了https://github.com/LendingHome/zero_downtime_migrations中列出的建议。(具体由https://robots.thoughtbot.com/how-to-create-postgres-indexes-concurrently-in概述),但在特别大的表上创建索引期间,即使是索引创建的“并发”方法也会锁定表并导致该表上的任何ActiveRecord创建或更新导致各自的事务失败有PG::InFailedSqlTransaction异常。下面是我们运行Rails4.2(使用Acti
我正在开发一个类似微论坛的项目,其中一个特殊用户发布一条快速(接近推文大小)的主题消息,订阅者可以用他们自己的类似大小的消息来响应。直截了当,没有任何形式的“挖掘”或投票,只是每个主题消息的响应按时间顺序排列。但预计会有很高的流量。我们想根据它们引起的响应嗡嗡声来标记主题消息,使用0到10的等级。在谷歌上搜索了一段时间的趋势算法和开源社区应用示例,到目前为止已经收集到两个有趣的引用资料,但我还没有完全理解它们:Understandingalgorithmsformeasuringtrends,关于使用基线趋势算法比较维基百科页面浏览量的讨论,在SO上。TheBritneySpearsP
我收到错误:unsupportedcipheralgorithm(AES-256-GCM)(RuntimeError)但我似乎具备所有要求:ruby版本:$ruby--versionruby2.1.2p95OpenSSL会列出gcm:$opensslenc-help2>&1|grepgcm-aes-128-ecb-aes-128-gcm-aes-128-ofb-aes-192-ecb-aes-192-gcm-aes-192-ofb-aes-256-ecb-aes-256-gcm-aes-256-ofbRuby解释器:$irb2.1.2:001>require'openssl';puts
文章目录一.Dijkstra算法想解决的问题二.Dijkstra算法理论三.java代码实现一.Dijkstra算法想解决的问题解决的问题:求解单源最短路径,即各个节点到达源点的最短路径或权值考察其他所有节点到源点的最短路径和长度局限性:无法解决权值为负数的情况二.Dijkstra算法理论参数:S记录当前已经处理过的源点到最短节点U记录还未处理的节点dist[]记录各个节点到起始节点的最短权值path[]记录各个节点的上一级节点(用来联系该节点到起始节点的路径)Dijkstra算法步骤:(1)初始化:顶点集S:节点A到自已的最短路径长度为0。只包含源点,即S={A}顶点集U:包含除A外的其他顶