人脸识别:特征脸(Eigenface)

Eigenface就是将人脸图像进行编码,映射到低维子空间上,在低维空间计算两幅人脸图像的距离,以此来进行人脸识别。映射到低维子空间的方法采用主成分分析(Principal Component Analysis,PCA)

1.将人脸图像(均为灰度图)拉成一个列向量存储在矩阵 AA1,A2,,An 中, ARd×n ,其中, d 是每张人脸图片的像素数目, n 是图像数目。为了保证后面的计算正常进行,我们假定图像的像素值已经转换成了double类型。

f = imread('face.jpg'); % f是uint8类型
f = im2double(f);  % f转换成double类型
f = reshape(f, [d, 1]); % f拉成列向量

在我们的例子中包含25张人脸图像,如下图所示

人脸识别:特征脸(Eigenface)_第1张图片

2.计算平均脸 A¯¯¯=i=1nAi ,平均脸也可以看做是一幅人脸图像

人脸识别:特征脸(Eigenface)_第2张图片

3.将原始图像每个维度中心化, Φi=AiA¯¯¯ , ΦΦ1,Φ2,,Φn ΦRd×n

4.对 Φ 进行主成分分析, ΦΦT=λiωi ,即求解 ΦΦT 的特征值和特征向量,将特征向量进行施密特正交化,对 λi 进行降序排列,选出前 s 个特征值对应的特征向量 Ω(ΩRd×n) 作为新空间的基,将原始数据投影到新空间上
Φnewi=ΩTΦi
在新空间中采用距离度量两幅图像的相似性

注: ΦΦT=λiωiλi 是原始数据在第 k 个方向上投影的方差值,为最大程度保留原始数据的信息,可以选择一个阈值 θ ,使得 s 满足下面的式子:
i=1s1λii=1nλi<θ and i=1sλii=1nλiθ

5.在我们的例子中,人脸图像数目 n 远小于图像的像素数目 d ,如果直接计算 ΦΦT 的特征值和特征向量,计算复杂度较高,对于100 × 100 大小的图片, ΦΦT 的大小为10000 × 10000,带来的存储和计算复杂度都是难以承受的,为此,我们可以先计算 ΦTΦ 的特征值和特征向量,即
ΦTΦμi=λiμi

ΦΦT(Φμi)=λi(Φμi)

ωi=Φμi ,则有 ΦΦT=λiωi

注意: ΦTΦRn×n ,而 ΦΦTRd×d ,通过这样计算出来的特征向量只有 n 个,那么对于剩余的特征向量怎么办呢?事实上, n d 维向量张成的空间维度最多为 n n<d ),我们可以直接采用这 n d 维向量作为它的基,这 n d 维向量可以用这组基完全表示,那么,采用另外一组基表示这个空间时,它最多需要 n 个基,换句话说,这 n d 维向量在剩下的特征向量上的投影都是0,即 ΦΦT 最多有n个不为0的特征值,原始数据在剩余的特征向量上的投影都是0,所以并不需要剩余的特征向量

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:n
    path = strcat('train/', s(k).name);
    f = imread(path);
    if(numel(size(f)) == 3)
       f = rgb2gray(f); 
    end
    f = imresize(f, [128, 128]);
    f = reshape(f, [d, 1]);
    f = im2double(f);
    img(:, k) = f;
end

mean_img = mean(img, 2);
for k = 1:n
   img(:, 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);
end

w = w(:, 1:face_num);
for k = 1:face_num
   w(:, k) = w(:, k)/norm(w(:, k)); 
end

eigenface = zeros(face_num, n);   % eigenface用于储存在人脸图像在特征空间的表达
for k = 1:n
    eigenface(:, 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:n
    d = norm(f - eigenface(:, k));
    if(distance > d)
        best_k = k;
        distance = d;
    end
end

path = strcat('train/', s(best_k).name);
subplot(1, 2, 2);
imshow(path);
title('数据库中最接近的图片');

你可能感兴趣的:(人脸识别)