(1)实验文件夹中提供facedata数据库,该数据库包括训练数据(train文件夹),该训练数据有40人(每人5张训练照片);测试数据(test文件夹)包括40人(每人5张测试照片)。数据库中还提供了数据归一化函数(scaling),可在训练前将数据进行归一化。
(2)实验推荐按照如下步骤进行程序实现,可将程序分为3大模块(三个函数)实现,分别如下:
①读训练数据模块 Face=ReadFaces(numFaces, nPerson);
nPerson=40; 共40人;
numFaces= 5; 每人5张脸训练;
要求200张人脸每张放一行或者一列,返回20010304大小的人脸数据矩阵Face。
②提取人脸数据矩阵Face的主成分
如: k=49; 49个主成分(可自行定义主成分数量)
[pcaFaces, V, meanVec] =fastPCA(Face, k);
其中:
pcaFaces:维度20049,数据矩阵Face向V投影后的人脸主成分(每个人脸只有49个特征);
V:维度 1030449 特征协方差矩阵前49个特征向量;
meanVec: 维度110304,样本均值。
③主程序模块,在主程序中首先实现,1),2)步骤的数据读取和降维,然后对数据归一化,处理标签数据并置乱,训练,测试,输出准确度函数。
①主函数main.m
clc;clear;close all;
numFaces = 5;
nPerson = 40;
k = 49; %提取主成分个数
% 读取
train_path = './facedata/train/';
Train_Face = ReadFaces(train_path,numFaces,nPerson);
% 降维
[pcaFaces,V,meanVec] = fastPCA(Train_Face,k);
%pcaFace : 人脸主成分,200*49
%V : 特征空间, 10304*49
%meanVec : 样本均值, 1*10304
%归一化
[Traindata, lowVec, upVec] = scaling(pcaFaces);
%Traindata : 200*49 人脸特征
%生成人脸标签
T = zeros(200,40);
for i = 1:40
for j = 1:5
T( (i-1)*5+j,i ) = 1;
end
end
%标签矩阵接到PCA特征后,置乱后训练
gx2(:,1:k) = Traindata;
gx2(:,(k+1):(k+40)) = T;
xd = gx2(randperm(200));
gx = xd(:,1:k);
d = xd(:,(k+1):(k+40));
P = gx';
T = d';
net = newff(P,T,44,{'purelin','purelin'},'traingdx');
net.trainparam.epochs = 5000;
net.trainparam.goal = 0.0001;
net.divideFcn = '';
[net,tr] = train(net,P,T);
Accuracy = TEST(net,V,meanVec,lowVec, upVec)
②ReadFaces.m
function face = ReadFaces(path,numFaces,nPerson)
%读取训练数据,要求200张人脸每张放一行或者一列
%返回200*10304大小的人脸数据矩阵Face
%numFaces = 5; 每人五张人脸照片训练
%nPerson = 40; 共40人
file = dir([path 's*']);
%nPerson = length(train_file);
face = [];
for i = 1:nPerson
t_son_path = [path,file(i).name,'/'];
pgm = dir([t_son_path,'*.pgm']);
%numFaces = length(pgm);
for j = 1:numFaces
I = imread([t_son_path,pgm(j).name]);
[m,n] = size(I);
I = reshape(I,1,m*n);
face = [face;I];
end
end
face = double(face);
end
③fastPCA.m
function [pcaFaces,V,meanVec] = fastPCA(Face,k)
%提取人脸数据矩阵Face的主成分
%Face : 人脸数据
%k : 主成分个数
%pcaFaces : 数据矩阵Face向V投影后的人脸主成分
% 每个人了保留k个特征,维度200 * k;
%V: 特征协方差矩阵前k个特征向量;维度10304*k
%meanVec : 样本均值;维度1*10304
%每行为一个样本
[n,p] = size(Face); %200*10304
%样本均值
meanVec = mean(Face); % 1*10304
% meanFace = uint8(reshape(meanVec,112,92));
% figure,imshow(meanFace);title('平均脸');
%去中心化
Z = (Face - repmat(meanVec,n,1)); %200*10304
%样本协方差矩阵
covMatT = Z * Z'; %200*200
%计算covMatT的前k个本征值和本征向量
[V,D] = eigs(covMatT,k); %200*200
%V : 主对角线上的特征值,200*k
%D : 各列中包含对应的特征向量 ,k*k
%特征脸V:
V = Z'*V; %10304*k
%本征向量归一化为单位本征向量
for i = 1:k
V(:,i) = V(:,i)/norm(V(:,i));
end
%线性变换(投影)降维至k维
pcaFaces = Z * V; %200*k = 200*10304 * 10304*k;
end
④scaling.m
function [SVFM, lowVec, upVec] = scaling(VecFeaMat, bTest, lRealBVec, uRealBVec)
% Input: VecFeaMat --- 需要scaling的 m*n 维数据矩阵,每行一个样本特征向量,列数为维数
% bTest --- =1:说明是对于测试样本进行scaling,此时必须提供 lRealBVec 和 uRealBVec
% 的值,此二值应该是在对训练样本 scaling 时得到的
% =0:默认值,对训练样本进行 scaling
% lRealBVec --- n维向量,对训练样本 scaling 时得到的各维的实际下限信息
% uRealBVec --- n维向量,对训练样本 scaling 时得到的各维的实际上限信息
%
% output: SVFM --- VecFeaMat的 scaling 版本
% upVec --- 各维特征的上限(只在对训练样本scaling时有意义,bTest = 0)
% lowVec --- 各维特征的下限(只在对训练样本scaling时有意义,bTest = 0)
if nargin < 2
bTest = 0;
end
% 缩放目标范围[-1, 1]
lTargB = -1;
uTargB = 1;
[m n] = size(VecFeaMat);
SVFM = zeros(m, n);
if bTest
if nargin < 4
error('To do scaling on testset, param lRealB and uRealB are needed.');
end
if nargout > 1
error('When do scaling on testset, only one output is supported.');
end
for iCol = 1:n
if uRealBVec(iCol) == lRealBVec(iCol)
SVFM(:, iCol) = uRealBVec(iCol);
SVFM(:, iCol) = 0;
else
SVFM(:, iCol) = lTargB + ( VecFeaMat(:, iCol) - lRealBVec(iCol) ) / ( uRealBVec(iCol)-lRealBVec(iCol) ) * (uTargB-lTargB); % 测试数据的scaling
end
end
else
upVec = zeros(1, n);
lowVec = zeros(1, n);
for iCol = 1:n
lowVec(iCol) = min( VecFeaMat(:, iCol) );
upVec(iCol) = max( VecFeaMat(:, iCol) );
if upVec(iCol) == lowVec(iCol)
SVFM(:, iCol) = upVec(iCol);
SVFM(:, iCol) = 0;
else
SVFM(:, iCol) = lTargB + ( VecFeaMat(:, iCol) - lowVec(iCol) ) / ( upVec(iCol)-lowVec(iCol) ) * (uTargB-lTargB); % 训练数据的scaling
end
end
end
⑤TEST.m
function [Accuracy] = TEST(net,V,meanVec,lowVec, upVec)
test_path = './facedata/test/';
file = dir([test_path 's*']);
accu = 0;
for i=1:40
t_son_path = [test_path,file(i).name,'/'];
pgm = dir([t_son_path,'*.pgm']);
for j=1:5 %读入40 x 5 副测试图像
I = imread([t_son_path,pgm(j).name]);
b=I(1:10304);
TestFace=double(b);
[m,n] = size(TestFace);
TestFace = (TestFace-repmat(meanVec,m,1)) * V;
TestFace = scaling(TestFace,1,lowVec, upVec);
X = TestFace;
Z = sim(net,X');
[zi,index2] = max(Z);
if index2 == i
accu = accu+1;
end
end
end
Accuracy = accu/200; %输出识别率
end