Eigenface就是将人脸图像进行编码,映射到低维子空间上,在低维空间计算两幅人脸图像的距离,以此来进行人脸识别。映射到低维子空间的方法采用主成分分析(Principal Component Analysis,PCA)
1.将人脸图像(均为灰度图)拉成一个列向量存储在矩阵 A={A1,A2,⋯,An} 中, A∈Rd×n ,其中, d 是每张人脸图片的像素数目,
f = imread('face.jpg'); % f是uint8类型
f = im2double(f); % f转换成double类型
f = reshape(f, [d, 1]); % f拉成列向量
在我们的例子中包含25张人脸图像,如下图所示
2.计算平均脸 A¯¯¯=∑i=1nAi ,平均脸也可以看做是一幅人脸图像
3.将原始图像每个维度中心化, Φi=Ai−A¯¯¯ , Φ={Φ1,Φ2,⋯,Φn} , Φ∈Rd×n
4.对 Φ 进行主成分分析, ΦΦT=λiωi ,即求解 ΦΦT 的特征值和特征向量,将特征向量进行施密特正交化,对 λi 进行降序排列,选出前 s 个特征值对应的特征向量
Φnewi=ΩTΦi
在新空间中采用距离度量两幅图像的相似性
注: ΦΦT=λiωi,λi 是原始数据在第 k 个方向上投影的方差值,为最大程度保留原始数据的信息,可以选择一个阈值
5.在我们的例子中,人脸图像数目 n 远小于图像的像素数目
ΦTΦμi=λiμi
ΦΦT(Φμi)=λi(Φμi)
令 ωi=Φμi ,则有 ΦΦT=λiωi
注意: ΦTΦ∈Rn×n ,而 ΦΦT∈Rd×d ,通过这样计算出来的特征向量只有 n 个,那么对于剩余的特征向量怎么办呢?事实上,
warning: ΦΦT 类似于 Φ 的协方差矩阵,也可以对协方差矩阵求解特征值和特征向量,采用5的方法求解时,千万不要先求解 ΦT 的协方差矩阵,再求解特征值和特征向量,个中差异请自行体会
下面撸代码,运行前需要在同一个文件夹建立一个train文件夹,在里面放入人脸图片,直接运行会提示你选择要识别的图片
clear all
s = dir('train');
s(1:2) = [];
d = 128 * 128; % 每张图片像素总数
n = length(s); % 训练集内照片总数
img = zeros(d, n);
for k = 1:npath = strcat('train/', s(k).name);f = imread(path);if(numel(size(f)) == 3)f = rgb2gray(f); endf = imresize(f, [128, 128]);f = reshape(f, [d, 1]);f = im2double(f);img(:, k) = f;
endmean_img = mean(img, 2);
for k = 1:nimg(:, k) = img(:, k) - mean_img;
end
[w, a, explained] = pcacov(img' * img);
w = img * w;
face_num = 0; % face_num用于存储需要特征脸的数目,协方差>=95%
per = 0;
while(per<95)face_num = face_num + 1;per = per + explained(face_num);
endw = w(:, 1:face_num);
for k = 1:face_numw(:, k) = w(:, k)/norm(w(:, k));
endeigenface = zeros(face_num, n); % eigenface用于储存在人脸图像在特征空间的表达
for k = 1:neigenface(:, k) = w' * img(:, k);
end[file, path] = uigetfile({'*.*', 'All Files'}, '选择您要识别的图片:');
path = strcat(path,file);
f = imread(path);
subplot(1, 2, 1);
imshow(f);
title('要识别的图片');
if(numel(size(f)) == 3)f = rgb2gray(f);
end
f = imresize(f, [128, 128]);
f = reshape(f, [d, 1]);
f = im2double(f);
f = f - mean_img;
f = w' * f; % 将要识别的图片投影到特征空间上% 在数据库中找寻与识别图片最相近的图片
distance = Inf;
best_k = 0;
for k = 1:nd = norm(f - eigenface(:, k));if(distance > d)best_k = k;distance = d;end
endpath = strcat('train/', s(best_k).name);
subplot(1, 2, 2);
imshow(path);
title('数据库中最接近的图片');