Matlab实现PCA人脸识别
寒假来了,阿汪先生总结了这一学期里学到的一些东西,并来和大家分享一下。
一、理论知识基础
1、一些前辈的经验分享(不局限于这些)
(1)PCA人脸识别详解——初学者必看.
(2)理解主成分分析 (PCA).
(3)LLE算法.
(4)拉格朗日乘子法.
2、阿汪先生做的一些笔记和用到的资料
原理资料上讲的很好,阿汪做了一些批注。水平不够,大家见谅呀!^-^
(1)05-人脸图像超分辨率重建.
(2)6.5-基于K-L变换的特征提取.
(3)Matlab_PCA_图像降维和人脸匹配_笔记.
主要用到的资料:
- 人脸识别与人体动作识别技术及应用 [专著] / 曹林著.——北京:电子工业出版社,2015.8,ISBN:978-7-121-26660-7.
- 模式识别及MATLAB实现 [专著] / 杨杰主编.——北京:电子工业出版社,2017.8,ISBN:978-7-121-32127-6.
二、注解代码程序
1、重塑训练数据-T()
function T = CreateDatabase(TrainDatabasePath)
%此函数重塑训练数据库的所有2D图像放入一维列向量中。
%然后,将这些一维列向量放在一行中构造2D矩阵“ T”。
%一个2D矩阵,包含所有1D图像矢量。
%假设训练数据库中的所有P图像的MxN大小相同。
%所以一维的长度列向量是MN,“ T”将是MNxP 2D矩阵。
%%%%%%%%%%%%%%%%%%%%%%%% 文件管理
TrainFiles = dir(TrainDatabasePath);
Train_Number = 0;
for i = 1:size(TrainFiles,1)
if not(strcmp(TrainFiles(i).name,'.')|strcmp(TrainFiles(i).name,'..')|strcmp(TrainFiles(i).name,'Thumbs.db'))
Train_Number = Train_Number + 1; % N训练数据库中所有图像的数量
end
end
%%%%%%%%%%%%%%%%%%%%%%%% 一维图像向量构建二维矩阵
T = [];
for i = 1 : Train_Number
str = int2str(i);
str = strcat('\',str,'.jpg');
str = strcat(TrainDatabasePath,str);
img = imread(str);
img = rgb2gray(img);
[irow ,icol] = size(img);
temp = reshape(img',irow*icol,1); % 将2D图像重塑为1D图像矢量
T = [T temp]; % 更新2D矩阵'T'
end
2、PCA过程-[m, A, Eigenfaces]
function [m, A, Eigenfaces] = EigenfaceCore(T)
%使用主成分分析(PCA)确定最多辨别脸部图像之间的特征。
%%该函数获得一个二维矩阵,其中包含所有训练图像矢量,并返回从训练数据库中提取的3个输出。
%
% T - %一个2D矩阵,包含所有1D图像矢量。
% - 假设训练数据库中的所有P图像的MxN大小相同。
% - 所以一维的长度列向量是MN,“ T”将是MNxP 2D矩阵。
%
% m - (M*Nx1) 培训数据库的平均值
% Eigenfaces - (M*Nx(P-1)) 训练数据库协方差矩阵的特征向量
% A - (M*NxP) 居中图像向量矩阵
%%%%%%%%%%%%%%%%%%%%%%%% 计算平均图像
m = mean(T,2); %计算平均面部图像m =(1 / P)* sum(Tj's)(j = 1:P)
Train_Number = size(T,2);
%%%%%%%%%%%%%%%%%%%%%%%% 计算每个图像与平均图像的偏差
A = [];
for i = 1 : Train_Number
temp = double(T(:,i)) - m; % 计算训练集中Ai = Ti-m中每个图像的差异图像
A = [A temp]; % 合并所有居中图像
end
%%%%%%%%%%%%%%%%%%%%%%%% 特征脸法的快照法
%从线性代数理论我们知道,对于一个PxQ矩阵,该矩阵可以具有的非零特征值的最大数量为min(P-1,Q-1)。
%由于训练图像的数量(P)通常小于像素的数量(M * N),因此可以找到的最不为零的特征值等于P-1。
%因此,我们可以计算A'* A(一个PxP矩阵)而不是A * A'(一个M * NxM * N矩阵)的特征值。
%显然,A * A'的尺寸比A'* A大得多。 因此,维数将减小。
L = A'*A; % L是协方差矩阵C = A * A'的替代。
[V,D] = eig(L); %D的对角元素是L = A'* A和C = A * A'的特征值。
%%%%%%%%%%%%%%%%%%%%%%%% 排序和消除特征值
%矩阵L的所有特征值都被排序,小于指定的阈值,将被消除。
%因此,非零特征向量的数量可能少于(P-1)。
L_eig_vec = [];
for i = 1 : size(V,2)
if( D(i,i)>1 )
L_eig_vec = [L_eig_vec V(:,i)];
end
end
%%%%%%%%%%%%%%%%%%%%%%%% 计算协方差矩阵'C'的特征向量
%可以从L的特征向量中恢复协方差矩阵C的特征向量的百分比(“特征面”)。
Eigenfaces = A * L_eig_vec; % A:居中的图像矢量
3、欧式距离比较面部特征-OutputName
function OutputName = Recognition(TestImage, m, A, Eigenfaces)
%此函数通过将图像投影到面部空间中来比较两个面部,然后测量它们之间的欧几里得距离。
% TestImage - 待检测图片所在路径
%
% m -(M * Nx1)培训数据库的平均值
% - “ EigenfaceCore”功能的输出。
%
% Eigenfaces - %特征脸-(M * Nx(P-1))个特征向量
% - 训练的协方差矩阵百分比
% -“ EigenfaceCore”功能的输出。
%
% A -(M * NxP)居中图像矩阵
% - “ EigenfaceCore”函数的输出。
%%%%%%%%%%%%%%%%%%%%%%%%将居中的图像矢量投影到面部空间
%将所有居中的图像通过乘以投影到面部空间本征面的基础。
%每张脸的投影向量将是其对应的特征向量。
ProjectedImages = [];
Train_Number = size(Eigenfaces,2);
for i = 1 : Train_Number
temp = Eigenfaces'*A(:,i);%将中心图像投影到面部空间
ProjectedImages = [ProjectedImages temp];
end
%%%%%%%%%%%%%%%%%%%%%%%% 从测试图像中提取PCA功能
InputImage = imread(TestImage);
temp = InputImage(:,:,1);
[irow,icol] = size(temp);
InImage = reshape(temp',irow*icol,1);
Difference = double(InImage)-m; %居中测试图像百分比
ProjectedTestImage = Eigenfaces'*Difference; % 测试图像特征向量
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%计算欧式距离投影测试图像和投影之间的欧几里得距离百分比计算所有居中训练图像的百分比。
%测试图片是的人应该认为与该图片中的相应图像具有最小距离培训数据库。
Euc_dist = [];
for i = 1 : Train_Number
q = ProjectedImages(:,i);
temp = ( norm( ProjectedTestImage - q ) )^2;
Euc_dist = [Euc_dist temp];
end
[ ~,Recognized_index] = min(Euc_dist);
OutputName = strcat(int2str(Recognized_index),'.jpg');
4、使用示例-example
% 清除变量
clear all
clc
close all
% 自定义和设置初始目录路径
TrainDatabasePath = uigetdir('F:\Matlab_2016b_64bit\code_matlab\face\face_test\code', 'Select training database path' );
TestDatabasePath = uigetdir('F:\Matlab_2016b_64bit\code_matlab\face\face_test\code', 'Select test database path');
prompt = {'选择待检测的图片编号(1~10)之间'};
%选择需要匹配的图片,并进入已知库中进行搜索匹配
dlg_title = 'Input of PCA-Based Face Recognition System';
num_lines= 1;
def = {'1'};
TestImage = inputdlg(prompt,dlg_title,num_lines,def);
TestImage = strcat(TestDatabasePath,'\',char(TestImage),'.jpg');
%每次循环TestImage存的都是 TestDatabasePathTest\TestImage.jpg
im = imread(TestImage);
%返回的数组A包含图像数据。
%若文件包含灰色图像,A是M*N的数组;若文件包含真彩色图像,A是M*N*3的数组。
% 创建人脸数据库
T = CreateDatabase(TrainDatabasePath); %根据训练图片路径生成2维矩阵
[m, A, Eigenfaces] = EigenfaceCore(T); %生成特征量
OutputName = Recognition(TestImage, m, A, Eigenfaces);
% 选择需要识别的图片
SelectedImage = strcat(TrainDatabasePath,'\',OutputName);
SelectedImage = imread(SelectedImage);
% 显示图片
imshow(im) %显示待测试图片原图
title('Test Image');
figure,im1=rgb2gray(im);
imshow(im1); %显示待测试图片灰度图
title('Test Image Gray');
figure,imshow(SelectedImage);%显示匹配到的图片
title('Equivalent Image');
str = strcat('Matched image is : ',OutputName);
disp(str)
三、使用过程
1、选择训练数据集
- 训练数据集:
2、选择测试数据集
- 测试数据集
- 是不是对某个闪入的美男子有点蒙,我们等下来说明他存在的意义
(当然是为了让我有动力继续健身下去,嘿嘿~)
- 是不是对某个闪入的美男子有点蒙,我们等下来说明他存在的意义
3、选择待检测的人脸图片编号
4、输出匹配结果
四、后续
我们是不是忘了这个男子…………
那么他对我们的意义呢?(除了养眼和激励健身减肥……)
我们重新来运行这个工程……
到选择测试图片那一步……
我们来看下运行结果……
震惊!!!为什么棱角分明的彭哥哥变成了“油腻”大叔???(岁月也没这么无情的呀……)
很简单,我们在回头看一下两个数据集的内容……
你会发现,我们的训练集中并没有我们的男神彭于晏哥哥……
如果你真的理解了PCA降维的原理……
你会明白:PCA会在平均脸的数据特征基础上,选择与输入图片(测试集中)数据欧式距离最接近的图片(训练集中)输出……
所以,我们不得不承认:这个大叔的面部数据是“最适”男神面部数据特征的,…………
//所以也不难理解为什么现在那么多软件、企业想要你的面部数据了,是想为他们训练模型提供数据呀……
//阿汪先生用的数据集是耶鲁大学开源人脸数据,大家也可以用PS软件自己制作学习所需的面部数据集,图片属性是:200*200像素、绿色背景。
//水平有限,能者见笑,大家见谅。(抱拳了……)
来源:CSDN
作者:阿汪先生
链接:https://blog.csdn.net/qq_43499622/article/details/103930327