由于计算机视觉课程的作业,不得不去实现这个经典的算法,感谢这次难得的机会。
本文将从算法核心说起,讲解实现过程,最后验证实验结果。
算法核心
Eigenface 算法的思想是希望能够将高维的图像数据降维,以此实现对不同人脸的特征刻画。Eigenface 降维图像数据的方法是寻找一组特征脸,将特征脸作为一组基,人脸信息便可以描述为特征脸的线性组合再加上一张平均脸,如下式。
F
a
c
e
p
i
x
e
l
=
A
v
e
r
a
g
e
f
a
c
e
p
i
x
e
l
+
α
1
E
i
g
e
n
f
a
c
e
1
+
α
2
E
i
g
e
n
f
a
c
e
2
+
.
.
.
+
α
k
E
i
g
e
n
f
a
c
e
k
Face_{pixel}=Averageface_{pixel}+\alpha_1Eigenface_1+\alpha_2Eigenface_2+...+\alpha_kEigenface_k
Facepixel=Averagefacepixel+α1Eigenface1+α2Eigenface2+...+αkEigenfacek
写成矩阵乘法的形式,即为
F
a
c
e
p
i
x
e
l
=
A
v
e
r
a
g
e
f
a
c
e
p
i
x
e
l
+
α
∗
E
i
g
e
n
f
a
c
e
s
Face_{pixel}=Averageface_{pixel}+\alpha *Eigenfaces
Facepixel=Averagefacepixel+α∗Eigenfaces
上式中,
F
a
c
e
p
i
x
e
l
Face_{pixel}
Facepixel、
A
v
e
r
a
g
e
F
a
c
e
p
i
x
e
l
AverageFace_{pixel}
AverageFacepixel均为行数为
M
N
MN
MN的列向量,
E
i
g
e
n
f
a
c
e
s
Eigenfaces
Eigenfaces则为行数为
M
N
MN
MN,列数为
k
k
k的矩阵,代表k个特征脸。
那么,如何求得
E
i
g
e
n
f
a
c
e
s
Eigenfaces
Eigenfaces矩阵,求得
E
i
g
e
n
f
a
c
e
s
Eigenfaces
Eigenfaces矩阵之后,又如何进行坐标转换,求得
α
\alpha
α呢?
如何求特征脸( E i g e n f a c e s Eigenfaces Eigenfaces矩阵)
平均脸刻画的是大家一致的地方,那么特征脸就是要找到人脸上不同的地方,Eigenface 算法采用了协方差矩阵来定量刻画“人脸的不同”。然后再对协方差矩阵求特征向量,一个特征向量和其特征值对应“一张特征脸”
e
i
g
e
n
_
v
e
c
i
eigen\_vec_i
eigen_veci和“该特征脸的能量”
e
i
g
e
n
_
v
a
l
u
e
i
eigen\_value_i
eigen_valuei。将特征脸列向量进行合并,得到一个矩阵,便称之为
E
i
g
e
n
f
a
c
e
s
Eigenfaces
Eigenfaces矩阵。
E
i
g
e
n
f
a
c
e
s
=
[
e
i
g
e
n
_
v
e
c
1
,
e
i
g
e
n
_
v
e
c
2
,
.
.
.
,
e
i
g
e
n
_
v
e
c
k
]
Eigenfaces = [eigen\_vec_1, eigen\_vec_2, ..., eigen\_vec_k]
Eigenfaces=[eigen_vec1,eigen_vec2,...,eigen_veck]
我们倾向于选择能量较大的
e
i
g
e
n
_
v
a
l
u
e
i
eigen\_value_i
eigen_valuei,因为可以减少计算,抑制噪声。所以选择能量(
e
i
g
e
n
_
v
a
l
u
e
i
eigen\_value_i
eigen_valuei)排名前e个
e
i
g
e
n
_
v
a
l
u
e
i
eigen\_value_i
eigen_valuei
E
i
g
e
n
f
a
c
e
s
=
[
e
i
g
e
n
_
v
e
c
1
,
e
i
g
e
n
_
v
e
c
2
,
.
.
.
,
e
i
g
e
n
_
v
e
c
e
]
Eigenfaces = [eigen\_vec_1, eigen\_vec_2, ..., eigen\_vec_e]
Eigenfaces=[eigen_vec1,eigen_vec2,...,eigen_vece]
在这之后,还需要对这组基进行正交化处理,原因将在下节中说明。
如何坐标转换
坐标变换的过程是将原向量向各个基向量上进行分解,将得到的分量组合成新的向量坐标。如果任意选取基,会导致在分解的时候操作困难,而如果选取正交的基的话,则可以使用向量点乘实现投影,得到分量,所以需要对
e
i
g
e
n
_
v
e
c
eigen\_vec
eigen_vec进行正交化,这一点在我看到的博客中都未说明,极易忽略。
正交化后的
E
i
g
e
n
f
a
c
e
s
Eigenfaces
Eigenfaces矩阵则可以直接通过矩阵乘法来进行基变换。基变换公式为:
α
=
E
i
g
e
n
f
a
c
e
s
∗
(
F
a
c
e
p
i
x
e
l
−
A
v
e
r
a
g
e
f
a
c
e
p
i
x
e
l
)
\alpha=Eigenfaces*(Face_{pixel}-Averageface_{pixel})
α=Eigenfaces∗(Facepixel−Averagefacepixel)
如何反变换(得到 F a c e p i x e l Face_{pixel} Facepixel灰度图象)
反变换的过程也很简单, F a c e p i x e l = A v e r a g e f a c e p i x e l + α ∗ E i g e n f a c e s Face_{pixel}=Averageface_{pixel}+\alpha *Eigenfaces Facepixel=Averagefacepixel+α∗Eigenfaces即可。
算法实现
训练train
求解平均脸:先读入训练数据,将图像数据类型转换为double类型,将所有图像加在一起,再求平均值,得到平均脸
求解特征脸:此处使用到了一个简化算法,我们虽然要求的是
T
∗
T
T
(
M
N
∗
M
N
)
T*T^T(MN*MN)
T∗TT(MN∗MN)的特征向量
v
v
v和特征值
λ
\lambda
λ,但是可以证明,求
T
T
∗
T
(
k
∗
k
)
T^T*T(k*k)
TT∗T(k∗k)的特征向量
u
u
u和特征值
μ
\mu
μ,便可以得到
v
=
T
∗
u
v=T*u
v=T∗u,
λ
=
μ
\lambda=\mu
λ=μ,如此大大减少了时间复杂度。
保存特征脸和平均脸,训练过程便结束了。
评估evaluate
读入保存的特征脸和平均脸,读入训练数据和测试数据。
先把所有训练数据转化到特征脸空间,然后对每条测试数据,将测试数据转化到特征脸空间,计算其到每条训练数据的欧氏距离,将欧式距离最小的作为预测结果。
所有测试数据中,预测正确的数量为n,测试数据总数量为m,则rank-1识别率为
a
c
c
=
n
m
∗
100
acc=\frac{n}{m}*100%
acc=mn∗100
预测predict
读入保存的特征脸和平均脸,读入训练数据和待预测数据。
先把所有训练数据和待预测数据转化到特征脸空间,计算待预测数据到每条训练数据的欧氏距离,将欧式距离最小的作为预测结果。
重建reconstruct
读入保存的特征脸和平均脸,读入待重建数据。
先把待重建数据转化到特征脸空间,再将特征脸空间数据反变换到像素空间,得到重建结果。
实验结果
平均脸和前十个特征脸
平均脸如下图,比较糊,是因为没有使用眼睛标记进行仿射变换。
特征脸如下图,由于是浮点数,所以无法直接显示,于是使用热力图进行展示。
人脸图像的重构结果
人脸图像重构结果如下图所示,可以看出,随着使用的PC变高,重构人脸变得越来越接近真实图像。
识别结果可视化
以训练数据总量为宽,测试数据总量为高,构建距离矩阵D。
D
(
i
,
j
)
=
d
i
s
t
(
t
e
s
t
i
,
t
r
a
i
n
j
)
D_{(i,j)}=dist(test_i, train_j)
D(i,j)=dist(testi,trainj)
显示D图像,如下图。可以看出,对角线上有若干个(41个,对应41个人)深色小矩形,说明相同人的人脸数据距离比不同人的人脸数据之间的距离更小。可视化结果说明算法可以较好评价人脸图象之间的相似度。
Rank-1识别率-PC变化曲线
识别率变化曲线如下图所示。可以看出在PC在10以下时,随着PC的增加,识别率迅速提升,而PC在20以上后,PC的增加对识别率的贡献不大,最终,在PC=50时,能够达到88.29%的识别率。