从2015年João F. Henriques等人提出KCF以来,网上已经有了很多相关的科普,也有博主给出了非常详细的推导,但如果想要真正理解我觉得还是得自己推导一遍,所以我在这里准备写一下自己学习过程中的一些想法。
本文是CSK与KCF算法推导的第一篇,主要介绍DFT、相关运算和循环卷积相关的内容。
SpringerLink上的ECCV2012里的CSK的论文里公式(4)落了一个共轭,下面链接里的CSK论文没有问题。知乎上有人说作者的论文中推导有问题,我推导了之后也发现确实是有那个问题,但无伤大雅。
- 2012 - CSK: Exploiting the Circulant Structure of Tracking-by-detection with Kernels
- 2015 - KCF: High-Speed Tracking withKernelized Correlation Filters
- 2015 - 作者博士论文: Circulant Structures in Computer Vsion
- 作者Github源码
上面的这些链接是我的主要参考资料。
- (本文)CSK与KCF算法推导(一)——DFT、相关运算和循环卷积
- CSK与KCF算法推导(二)——带核函数的岭回归问题求解
- CSK与KCF算法推导(三)——算法主体部分推导
- CSK与KCF算法推导(四)——从一维推广到二维
- CSK与KCF算法推导(五)——具体实现细节
- CSK与KCF算法推导(六)——HOG特征提取与多通道计算
向量内积
在二维平面中,两个向量如果长度相同,它们之间的相似程度可以用它们之间的夹角来衡量。
c
o
s
(
θ
)
cos(\theta)
cos(θ)越接近1,说明两个向量越相似。如果两个向量
a
⃗
\vec a
a,
b
⃗
\vec b
b在直角坐标系下用坐标表示为
(
x
1
,
y
1
)
(x_1, y_1)
(x1,y1)和
(
x
2
,
y
2
)
(x_2, y_2)
(x2,y2),那么它们之间的夹角余弦可以这样计算:
c
o
s
(
θ
)
=
a
⃗
⋅
b
⃗
∣
a
⃗
∣
∣
b
⃗
∣
=
x
1
x
2
+
y
1
y
2
x
1
2
+
y
1
2
x
2
2
+
y
2
2
cos(\theta)=\frac{\vec a\cdot \vec b}{|\vec a||\vec b|}=\frac{x_1x_2+y_1y_2}{\sqrt{x_1^2+y_1^2}\sqrt{x_2^2+y_2^2}}
cos(θ)=∣a∣∣b∣a⋅b=x12+y12x22+y22x1x2+y1y2
前一个等号是通过余弦定理得到的。
∣
a
⃗
−
b
⃗
∣
2
=
∣
a
⃗
∣
2
+
∣
b
⃗
∣
2
−
2
∣
a
⃗
∣
∣
b
⃗
∣
c
o
s
(
θ
)
|\vec a - \vec b|^2 = |\vec a|^2+|\vec b|^2-2|\vec a||\vec b|cos(\theta)
∣a−b∣2=∣a∣2+∣b∣2−2∣a∣∣b∣cos(θ)
化简上面这个式子就可以得到结论。那么为什么两个向量相乘是对应的坐标相乘呢?因为两个向量的坐标是在一组正交基为基底表示的。
a
⃗
=
x
1
e
1
+
y
1
e
2
\vec a = x_1e_1+y_1e_2
a=x1e1+y1e2,其中,{
e
1
,
e
2
e_1,e_2
e1,e2}是一组单位正交基。
a
⃗
⋅
b
⃗
=
(
x
1
e
1
+
y
1
e
2
)
(
x
2
e
1
+
y
2
e
2
)
=
x
1
x
2
+
y
1
y
2
\vec a \cdot \vec b=(x_1e_1+y_1e_2)(x_2e_1+y_2e_2)=x_1x_2+y_1y_2
a⋅b=(x1e1+y1e2)(x2e1+y2e2)=x1x2+y1y2
从上面的例子中可以看到,向量内积在两个向量的长度相同的前提下能够反映两个向量的夹角大小。
向量范数
向量范数被用来衡量向量的长度。严格的数学定义我就不写了,我感觉只要能够知道L-p范数的形式就行,L-p范数用
∣
∣
⋅
∣
∣
p
||\cdot||_p
∣∣⋅∣∣p表示,根据p的不同,它表示的含义也不同。
∣
∣
⋅
∣
∣
p
:
=
(
∑
i
=
1
i
=
n
x
i
p
)
1
p
||\cdot||_p:=\left(\sum\limits_{i = 1}^{i = n} x_i^p\right)^{\frac{1}{p}}
∣∣⋅∣∣p:=(i=1∑i=nxip)p1
L
2
L^2
L2范数就相当于求向量的模长,是向量自己与自己的内积再开根号。
L
2
L^2
L2范数
∣
∣
⋅
∣
∣
2
||\cdot||_2
∣∣⋅∣∣2也通常省略右下角的“2”,所以论文中经常看到的
∣
∣
⋅
∣
∣
2
||\cdot||^2
∣∣⋅∣∣2表示的实际上是向量自己和自己的内积。
Gram矩阵与协方差矩阵
Gram矩阵和协方差矩阵都可以用
X
H
X
X^HX
XHX或者
X
X
H
XX^H
XXH表示,这两种表示方法取决于样本向量的摆放方式。如果样本是竖着排列的,那么
X
H
X
X^HX
XHX才是Gram矩阵或协方差矩阵;如果样本是横着排列的,那么
X
X
H
XX^H
XXH才是。
计算得到的方阵中,对角线上元素是每个样本向量自己和自己内积的结果;非对角线元素是不同样本向量之间的内积。
协方差矩阵是Gram矩阵的特殊形式。协方差矩阵要求样本向量的期望是零向量。这样一来对角线的值就是样本各个维度的方差;非对角线的值能够衡量样本各个维度之间的相关性。
DFT与DFT的矩阵表示
DFT的本质还是DFS,我觉得DFT只是DFS的一种表示方式。我们处理的序列是有限长的,可以把时域上的序列周期延拓,那样就可以用DFS处理。DFS的主值区间的系数就是DFT的结果。所以在做DFT分析的时候一定要注意序列隐含的周期性。
与DFT类似的还有DTFT,它是离散非周期时域信号到周期连续频谱的变换,这个在采样率变换的时候经常会用到。
DFT分析式:
x
^
[
k
]
=
∑
n
=
0
N
−
1
x
[
n
]
W
N
k
n
\hat x[k]=\sum \limits_{n=0}^{N-1}x[n]W_N^{kn}
x^[k]=n=0∑N−1x[n]WNkn
DFT合成式(IDFT):
x
[
n
]
=
1
N
∑
k
=
0
N
−
1
x
^
[
k
]
W
N
−
k
n
x[n]=\frac{1}{N}\sum \limits_{k=0}^{N-1}\hat x[k]W_N^{-kn}
x[n]=N1k=0∑N−1x^[k]WN−kn
上面的式子中
x
^
[
k
]
\hat x[k]
x^[k]表示DFT之后频域的序列,
x
[
n
]
x[n]
x[n]表示时域的序列,
W
N
k
n
W_N^{kn}
WNkn是“旋转因子”,
W
N
=
e
−
j
2
π
/
N
W_N=e^{-j2\pi/N}
WN=e−j2π/N,因为
W
N
W_N
WN的模长始终是1,它的幂次始终落在复平面的单位圆上。把DFT和IDFT写成矩阵的形式可以便于后面分析。
x
^
[
k
]
=
[
1
1
1
1
⋯
1
1
W
N
1
W
N
2
W
N
3
⋯
W
N
N
−
1
1
W
N
2
W
N
4
W
N
6
⋯
W
N
2
(
N
−
1
)
1
W
N
3
W
N
6
W
N
9
⋯
W
N
3
(
N
−
1
)
⋮
⋮
⋮
⋮
⋱
⋮
1
W
N
N
−
1
W
N
2
(
N
−
1
)
W
N
3
(
N
−
1
)
⋯
W
N
(
N
−
1
)
(
N
−
1
)
]
[
x
[
0
]
x
[
1
]
x
[
2
]
x
[
3
]
⋮
x
[
N
−
1
]
]
=
F
x
[
n
]
\hat x[k]= {\begin{bmatrix} 1&1&1&1& \cdots &1\\ 1&W_N^1&W_N^2&W_N^3& \cdots &W_N^{N-1}\\ 1&W_N^2&W_N^4&W_N^6& \cdots &W_N^{2(N-1)}\\ 1&W_N^3&W_N^6&W_N^9& \cdots &W_N^{3(N-1)}\\ \vdots & \vdots & \vdots & \vdots& \ddots & \vdots \\ 1&W_N^{N-1}&W_N^{2(N-1)}&W_N^{3(N-1)}& \cdots &W_N^{(N-1)(N-1)} \end{bmatrix}} {\begin{bmatrix} x[0]\\ x[1]\\ x[2]\\ x[3]\\ \vdots\\ x[N-1] \end{bmatrix}} = Fx[n]
x^[k]=
1111⋮11WN1WN2WN3⋮WNN−11WN2WN4WN6⋮WN2(N−1)1WN3WN6WN9⋮WN3(N−1)⋯⋯⋯⋯⋱⋯1WNN−1WN2(N−1)WN3(N−1)⋮WN(N−1)(N−1)
x[0]x[1]x[2]x[3]⋮x[N−1]
=Fx[n]
F
F
F矩阵可以看作是由傅立叶变换的一组正交基组成的,
F
F
F中的每一行是一个基向量。简单计算就可以得到,基向量只有自己和自己的内积才不为0,不同基向量之间的内积为0,因为在复平面单位圆上均匀间隔分布的向量求和之后就相互抵消了。
DFT计算,每行基向量都分别和
x
[
n
]
x[n]
x[n]内积,得到
x
^
[
k
]
\hat x[k]
x^[k]。内积可以理解为一个向量往另一个向量做投影,这里也就直观地展示了
x
^
[
k
]
\hat x[k]
x^[k]是
x
[
n
]
x[n]
x[n]往一组正交基上做投影得到的结果。
DFT矩阵的性质
DFT矩阵
F
F
F有非常好的性质,首先从结构上就可以看出来,它是一个对称矩阵,
F
T
=
F
F^T=F
FT=F,
F
H
=
F
∗
F^H=F^*
FH=F∗。然后,它的Gram矩阵几乎是一个单位阵。
F
F
H
=
[
s
0
0
⋯
0
0
s
0
⋯
0
0
0
s
⋯
0
⋮
⋮
⋮
⋱
⋮
0
0
0
⋯
s
]
=
s
I
s
FF^H={\begin{bmatrix} s&0&0& \cdots &0\\ 0& s& 0 & \cdots &0\\ 0 & 0& s& \cdots & 0\\ \vdots & \vdots& \vdots& \ddots& \vdots\\ 0& 0& 0& \cdots& s\\ \end{bmatrix}}=s\boldsymbol I_s
FFH=
s00⋮00s0⋮000s⋮0⋯⋯⋯⋱⋯000⋮s
=sIs
前面分析的时候,
x
[
n
]
x[n]
x[n]和
x
^
[
k
]
\hat x[k]
x^[k]的维度均为N,但考虑到大写的N容易和矩阵混淆,所以这里沿用了作者博士论文中的表示方式,改用
s
s
s来表示。上式左乘
F
−
1
F^{-1}
F−1之后可以求出:
F
−
1
=
1
s
F
H
F^{-1}=\frac{1}{s}F^H
F−1=s1FH
F
−
1
F^{-1}
F−1自然就表示离散傅立叶逆变换,因为
x
[
n
]
=
F
−
1
F
x
[
n
]
x[n]=F^{-1}Fx[n]
x[n]=F−1Fx[n],直接通过合成式来写也能得到一样的结果。
酉矩阵(Unitary Matrix)
F
F
F矩阵有个重要性质就是能跟酉矩阵建立起联系。酉矩阵满足
U
U
H
=
U
H
U
=
I
UU^H=U^HU=I
UUH=UHU=I,对上面的性质做简单的变换可以得到:
(
1
s
F
)
(
1
s
F
H
)
=
I
s
{\left (\frac{1}{\sqrt s}F\right )}\left( \frac{1}{\sqrt s}F^H\right )=I_s
(s1F)(s1FH)=Is
所以
1
s
F
\frac{1}{\sqrt s}F
s1F是一个酉矩阵,酉矩阵不改变
L
2
L^2
L2范数,也就是不改变向量自己和自己的内积。令
U
=
1
s
F
U=\frac{1}{\sqrt s}F
U=s1F,由于
F
F
F是对称的,这个
U
U
U还满足
U
H
=
U
∗
U^H=U^*
UH=U∗,后文提到的
U
U
U都特指这个
1
s
F
\frac{1}{\sqrt s}F
s1F。
{
∣
∣
x
∣
∣
2
=
x
H
x
∣
∣
U
x
∣
∣
2
=
x
H
U
H
U
x
=
x
H
x
\left \{ \begin {matrix} ||x||^2=x^Hx\\ ||Ux||^2=x^HU^HUx=x^Hx \end {matrix} \right .
{∣∣x∣∣2=xHx∣∣Ux∣∣2=xHUHUx=xHx
这是酉矩阵都具有的性质,除此之外还可以根据这一关系推导出帕斯瓦尔定理,信号在时频域的能量相等。
∣
∣
x
∣
∣
2
=
∣
∣
U
x
∣
∣
2
=
∣
∣
1
s
F
x
∣
∣
2
=
1
s
∣
∣
x
^
∣
∣
2
||x||^2=||Ux||^2=||\frac{1}{\sqrt s}Fx||^2=\frac{1}{s}||\hat x||^2
∣∣x∣∣2=∣∣Ux∣∣2=∣∣s1Fx∣∣2=s1∣∣x^∣∣2
循环卷积
频域乘积等于时域卷积。DFT也有这一性质,考虑到DFT隐含的周期性,循环卷积需要从DFS的周期卷积开始讲起。
周期卷积是将两个周期均为
s
s
s的周期序列进行卷积,求和只在一个周期的序列长度上进行。设
x
~
1
[
n
]
\tilde x_1[n]
x~1[n]和
x
~
2
[
n
]
\tilde x_2[n]
x~2[n]是两个周期为
s
s
s的序列,它们的DFS系数分别为
X
~
1
[
k
]
\tilde X_1[k]
X~1[k]和
X
~
2
[
k
]
\tilde X_2[k]
X~2[k]。
x
~
1
[
n
]
\tilde x_1[n]
x~1[n]和
x
~
2
[
n
]
\tilde x_2[n]
x~2[n]的周期卷积为:
x
~
3
[
n
]
=
∑
m
=
0
s
−
1
x
~
1
[
m
]
x
~
2
[
n
−
m
]
\tilde x_3[n]=\sum\limits_{m = 0}^{s - 1} {{{\tilde x}_1}[m]{{\tilde x}_2}[n - m]}
x~3[n]=m=0∑s−1x~1[m]x~2[n−m]
X
~
3
[
k
]
{\tilde X_3}[k]
X~3[k]是
x
~
3
\tilde x_3
x~3的离散傅立叶级数表示。
X
~
3
[
k
]
=
∑
n
=
0
s
−
1
(
∑
m
=
0
s
−
1
x
~
1
[
m
]
x
~
2
[
n
−
m
]
)
W
N
k
n
=
∑
m
=
0
s
−
1
x
~
1
[
m
]
∑
n
=
0
s
−
1
x
~
2
[
n
−
m
]
W
N
k
(
n
−
m
)
W
N
k
m
{\tilde X_3}[k] = \sum \limits_{n = 0}^{s - 1} \left( {\sum\limits_{m = 0}^{s - 1} {{{\tilde x}_1}[m]{{\tilde x}_2}[n - m]} } \right)W_N^{kn} = \sum\limits_{m = 0}^{s - 1} {{{\tilde x}_1}[m]\sum\limits_{n = 0}^{s - 1} {{{\tilde x}_2}[n - m]W_N^{k(n - m)}W_N^{km}} }
X~3[k]=n=0∑s−1(m=0∑s−1x~1[m]x~2[n−m])WNkn=m=0∑s−1x~1[m]n=0∑s−1x~2[n−m]WNk(n−m)WNkm
=
∑
m
=
0
s
−
1
x
~
1
[
m
]
W
N
k
m
X
~
2
[
k
]
=
X
~
1
[
k
]
X
~
2
[
k
]
= \sum\limits_{m = 0}^{s - 1} {{{\tilde x}_1}[m]W_N^{km}} {{\tilde X}_2}[k] = {{\tilde X}_1}[k]{{\tilde X}_2}[k]
=m=0∑s−1x~1[m]WNkmX~2[k]=X~1[k]X~2[k]
先周期卷积再计算DFS可以通过交换求和顺序,来推导出时域卷积等于频域乘积的结论。回到DFT上,循环卷积实际上和周期卷积是同样的数值计算,只是换一种说法而已。
只有循环卷积才能用DFT来加速运算,如果是做线性卷积,那么需要对循环卷积的长度做调整,然后才能用DFT,因为循环卷积相当于是一种有混叠的线性卷积。不过好在论文里要用的都是循环卷积,所以可以直接用DFT加速。
相关运算
自相关和互相关都是相关运算。自相关(auto-correlation)和互相关(cross-correlation)顾名思义就是序列自身和自身做相关运算,或者是两个序列之间做相关运算。
相关运算和卷积非常像,上课老师肯定有讲过,卷积是把一个序列翻转,然后在另一个序列上滑动;相关运算就是省去了序列翻转的过程。
x
~
3
[
n
]
=
∑
m
=
0
s
−
1
x
~
1
[
m
]
x
~
2
[
n
+
m
]
\tilde x_3[n]=\sum \limits_{m=0}^{s-1}\tilde x_1[m]\tilde x_2[n+m]
x~3[n]=m=0∑s−1x~1[m]x~2[n+m]
上面的式子就表示
x
~
1
\tilde x_1
x~1保持不动,
x
~
2
\tilde x_2
x~2滑动并与
x
~
1
\tilde x_1
x~1做乘加运算。
相关运算和循环卷积那么像,自然也可以用DFT来加速运算。类似上面卷积的推导,
X
~
3
[
k
]
=
∑
n
=
0
s
−
1
(
∑
m
=
0
s
−
1
x
~
1
[
m
]
x
~
2
[
n
+
m
]
)
W
N
k
n
=
∑
m
=
0
s
−
1
x
~
1
[
m
]
∑
n
=
0
s
−
1
x
~
2
[
n
+
m
]
W
N
k
(
n
+
m
)
W
N
−
k
m
{\tilde X_3}[k] = \sum \limits_{n = 0}^{s - 1} \left( {\sum\limits_{m = 0}^{s - 1} {{{\tilde x}_1}[m]{{\tilde x}_2}[n+m]} } \right)W_N^{kn} = \sum\limits_{m = 0}^{s - 1} {{{\tilde x}_1}[m]\sum\limits_{n = 0}^{s - 1} {{{\tilde x}_2}[n+ m]W_N^{k(n + m)}W_N^{-km}} }
X~3[k]=n=0∑s−1(m=0∑s−1x~1[m]x~2[n+m])WNkn=m=0∑s−1x~1[m]n=0∑s−1x~2[n+m]WNk(n+m)WN−km
=
∑
m
=
0
s
−
1
x
~
1
[
m
]
W
N
−
k
m
X
~
2
[
k
]
=
X
~
1
∗
[
k
]
X
~
2
[
k
]
= \sum\limits_{m = 0}^{s - 1} {{{\tilde x}_1}[m]W_N^{-km}} {{\tilde X}_2}[k] = {\tilde X_1^*}[k]{{\tilde X}_2}[k]
=m=0∑s−1x~1[m]WN−kmX~2[k]=X~1∗[k]X~2[k]
相关运算结果的傅里叶级数是也是两个序列的傅里叶级数相乘,只不过其中一个傅里叶级数需要求复共轭。
换另一个角度思考,既然相关运算相比于卷积只是少了序列翻转,那我先把序列翻转一下不就好了吗?所以
X
~
3
[
k
]
{\tilde X_3}[k]
X~3[k]还可以这样求:
X
~
3
[
k
]
=
D
F
S
(
x
~
1
[
n
]
)
D
F
S
(
x
~
2
[
−
n
]
)
=
X
~
1
[
k
]
X
~
2
∗
[
k
]
\tilde X_3[k]=DFS(\tilde x_1[n])DFS(\tilde x_2[-n])=\tilde X_1[k]\tilde X_2^*[k]
X~3[k]=DFS(x~1[n])DFS(x~2[−n])=X~1[k]X~2∗[k]
这时候就有问题了?到底是哪个序列需要求复共轭?经过观察可以发现,一个序列在另一个序列上滑动是有两种情况的,不同的情况对应着不同的求复共轭的情况。
当
x
~
2
\tilde x_2
x~2相对于
x
~
1
\tilde x_1
x~1往前滑动时,
X
~
1
\tilde X_1
X~1需要求复共轭;当
x
~
1
\tilde x_1
x~1相对于
x
~
2
\tilde x_2
x~2往前滑动时,
X
~
2
\tilde X_2
X~2需要求复共轭