您的位置:首页 > 编程语言 > MATLAB

基于MATLAB的PCA人脸识别实现

2017-11-27 19:13 981 查看

基于MATLAB的PCA人脸识别实现

前言

其实这个程序早就完成了,而且还要比另一篇基于opencv的博文还要早,这里主要是回顾一下。关于PCA人脸识别的步骤已经在另一篇博文中有讲解,这里就不多说了,直接上程序。

目录

基于MATLAB的PCA人脸识别实现
前言

目录

函数设计
1 函数调用过程

2 函数介绍

数据准备

主函数

源码

1. 函数设计

1.1 函数调用过程



1.2 函数介绍

从整体上分为训练和测试两大函数,训练函数pca_train将训练的模型数据以pca_data.mat形式保存到当前目录。测试函数pca_test执行时从pca_data.mat从加载数据。

训练函数:

pca_train(path,trainImageNameList, newSize, trainClassType, energy)
%pca_train(path,trainImageNameList, newSize, trainClassType, energy)
%功能:根据训练样本,计算并保存classType,newSize,originSize,平均脸,特征脸,投影矩阵,到pca_data.mat
%输入:
% path:训练样本路径
% trainImageNameList:训练图像名称列表(元胞数组)
% newSize:缩减后的图像尺度
% trainClassType:训练样本类别标号(列向量)
% energy:能量比
%输出:
%保存pca_data.mat到当前目录


测试函数:

testClassType = pca_test(path, testImageNameList, trueClassType)
%testClassType = pca_test(path, testImageNameList, trueClassType)
%功能:训练样本,得到特征空间的投影矩阵,并求测试样本的类别
%输入:
% path:测试样本路径
% testImageNameList:测试图像名称列表(元胞数组)
% trueClassType:测试真实类别
%输出:
%testClassType:分类结果


数据阵准备子函数:

[samples, samplesMean, rawNum, rolNum, originSize]=arrDataMat(path, imageNameList, newSize)
%[samples, samplesMean, rawNum, rolNum, originSize]=arrDataMat(path, imageNameList, newSize)
%子函数,根据图像名称列表,读取图像数据,并灰度化,转化成 样本数*[newSize(1)*newSize(2)]数据阵
%输入:
%path:图像路径
%imageNameList:图像名称列表,类型为元胞数组
%newSize:缩减后图像尺度
%输出:
%samples:数据矩阵(一行为一个样本)
%samplesMean:数据阵平均值(行向量)
%rawNum:样本数
%rolNum:原始的变量维数,即像素的行*像素的列
%originSize:缩减前图片尺寸


特征向量施密特正交化单位化:

vv = simitzj(v, d)
%vv = simitzj(v, d)
%功能:对输入的实对称的特征值,特征向量施密特正交化,单位化
%输入:
%v:特征向量
%d:特征值
%输出:
%vv:正交化单位化后的特征向量


2. 数据准备

训练样本图片与测试样本图片分别位于两个文件夹,在训练或测试时,需要获取训练或测试样本图片的名称列表(以cell数组形式),因此编写了一个函数用于获取指定目录下的所有文件名称,用于在主函数中调用。

fileList=getFileList(path)
% fileList=getFileList(path)
%输入:
%path:所获取的文件列表的路径
%输出:
%fileList:path路径下文件列表,cell数组


3. 主函数

path='D:\用户目录\Documents\MATLAB\Face_Image\face_1\';
trainpath=[path,'train\'];
testpath=[path,'test\'];
trainImageNameList=getFileList(trainpath);
testImageNameList=getFileList(testpath);
for i=1:size(trainImageNameList,1)
trainClassType(i,:)=ceil(i/5);
end
trueClassType = (1:40)';
newSize=[50,50];
energy=0.9;
pca_train(trainpath,trainImageNameList, newSize, trainClassType, energy);
testClassType = pca_test(testpath, testImageNameList, trueClassType);
%将人脸原图像与 特征脸反投影后的人脸对比
l=15; %要比对第几张
%显示一张人脸原图像
i1=imread([trainpath,trainImageNameList{l}]);
i1=rgb2gray(i1);
figure;
imshow(i1);
%将特征脸反投影回去
load pca_data;
zeroMeanTrainSamples2=trainNew*T'; %特征脸反投影得到零均值的人脸
trainSamples2=zeroMeanTrainSamples2+repmat(trainSamplesMean,size(zeroMeanTrainSamples2,1),1); %加上均值
i2=reshape(trainSamples2(l,:)',newSize(1),newSize(2)); %还原为矩阵
i2=imresize(i2,originSize); %还原为原始图像尺寸
figure;
imshow(i2);


执行结果:

平均脸:



一个人的人脸原图片:



投影后的图像:



识别准确度:



注:因为人脸样本图像未经过标准化处理,背景区域较大,可能导致识别率仅为0.95,而且在训练过程中由于图片尺寸太大会导致计算亮过大,不得不对图片缩减,投影后在还原为原始尺寸,导致pca投影后与原图像相比失真较大。

4. 源码

function pca_train(path,trainImageNameList, newSize, trainClassType, energy)
%pca_train(path,trainImageNameList, newSize, trainClassType, energy)
%功能:根据训练样本,计算并保存classType,newSize,originSize,平均脸,特征脸,投影矩阵,到pca_data.mat
%输入:
% path:训练样本路径
% trainImageNameList:训练图像名称列表(元胞数组)
% newSize:缩减后的图像尺度
% trainClassType:训练样本类别标号(列向量)
% energy:能量比
%输出:
%保存pca_data.mat到当前目录

save('pca_data.mat','trainClassType');
fprintf('保存trainClassType到pca_data.mat成功!\n');
save('pca_data.mat','newSize','-append');
fprintf('保存newSize到pca_data.mat成功!\n');

%step1:调用子函数,计算训练样本的数据阵,和平均脸
[trainSamples, trainSamplesMean, trainNum, ~, originSize]=arrDataMat(path, trainImageNameList, newSize);
trainMeanFace = reshape(trainSamplesMean',newSize(1),newSize(2));
save('pca_data.mat','trainSamplesMean','-append');
fprintf('保存trainSamplesMean到pca_data.mat成功!\n');
save('pca_data.mat','originSize','-append');
fprintf('保存originSize到pca_data.mat成功!\n');
figure;
trainMeanFaceOriginSize = imresize(trainMeanFace, originSize);
imshow(trainMeanFaceOriginSize); %显示平均脸
title('Mean face of the training samples');
%step2:求协方差阵的特征值和向量并排序,正交化单位化,求投影矩阵
%求样本的协方差矩阵,并求特征值和特征向量,确定出降的维数,求投影矩阵
%不直接求a'a的特征值特征向量,而是采用SVD的方法,利用aa'的特征值特征向量来求a'a的特征值和向量
trainZeroMeanSamples=trainSamples-repmat(trainSamplesMean,trainNum,1);%计算零均值的人脸样本
cov = trainZeroMeanSamples*trainZeroMeanSamples';%求协方差矩阵
[v, d] = eig(cov);
lamna = diag(d);
[D, indx] = sort(lamna,1,'descend');%对特征值进行排序
rankV = v(:,indx);%对特征向量排序
t = 0;
tt = sum(D);
for i=1:trainNum %选出累积能量占%99特征值
t = t + D(i);
ratio = t/tt;
if(ratio>=energy)
break;
end
end
T_len=i;%选出特征值的个数
T2 = rankV(:,1:i);%选出特征向量
D2 = D(1:i);%选出特征值
T3 = simitzj(T2,D2); %特征向量的归一化,正交化
%求a'a的特征值特征向量,还原为原始协方差的特征向量
L = repmat((1./sqrt(D2))',trainNum,1);
T=trainZeroMeanSamples'*(T3.*L);%投影矩阵
% Data{4} = T;
save('pca_data.mat','T','-append');
fprintf('保存T到pca_data.mat成功!\n');

%step3:求训练样本的特征脸
trainNew = trainZeroMeanSamples*T; %求训练样本特征脸
% Data{5} = trainNew;
% save('Data.mat','Data');
% disp('数据保存成功!');
save('pca_data.mat','trainNew','-append');
fprintf('保存trainNew到pca_data.mat成功!\n');
end


function testClassType = pca_test(path, testImageNameList, trueClassType)
%testClassType = pca_test(path, testImageNameList, trueClassType)
%功能:训练样本,得到特征空间的投影矩阵,并求测试样本的类别
%输入:
% path:测试样本路径
% testImageNameList:测试图像名称列表(元胞数组)
% trueClassType:测试真实类别
%输出:
%testClassType:分类结果

load ('pca_data.mat','trainClassType','newSize','trainSamplesMean','T','trainNew');

%调用子函数,将测试样本转化为数据阵
[testSamples, ~, testNum]=arrDataMat(path, testImageNameList, newSize);
testZeroMeanSamples = testSamples-repmat(trainSamplesMean,testNum,1);
testNew = testZeroMeanSamples*T;%求测试样本的特征脸
n = size(trainNew,1);
m = size(testNew,1);
dis = zeros(m,n);
for i=1:m %求距离矩阵
for j=1:n
dis(i,j) = sqrt(sum((testNew(i,:)-trainNew(j,:)).^2));
end
end
K=1; %KNN最近邻的k值
[~, sortDisIndex] = sort(dis, 2, 'ascend');
KnnClassType = zeros(m, n);
for i=1:m
KnnClassType(i,:)=trainClassType(sortDisIndex(i,:))';
end
testClassType = mode(KnnClassType(:,1:K), 2);
if nargin == 3
total = length(trueClassType);
count = 0;
for i=1:total
if testClassType(i) == trueClassType(i)
count = count+1;
end
end
rate = count/total;
fprintf('分类的准确度是%f\n',rate);
figure;
h=bar([rate,1-rate]);
set(h,'barwidth',.2);
set(gca,'xticklabel',{'true rate','false rate'});
end
end


%子函数:准备原始数据阵
function [samples, samplesMean, rawNum, rolNum, originSize]=arrDataMat(path, imageNameList, newSize) %[samples, samplesMean, rawNum, rolNum, originSize]=arrDataMat(path, imageNameList, newSize) %子函数,根据图像名称列表,读取图像数据,并灰度化,转化成 样本数*[newSize(1)*newSize(2)]数据阵 %输入: %path:图像路径 %imageNameList:图像名称列表,类型为元胞数组 %newSize:缩减后图像尺度 %输出: %samples:数据矩阵(一行为一个样本) %samplesMean:数据阵平均值(行向量) %rawNum:样本数 %rolNum:原始的变量维数,即像素的行*像素的列 %originSize:缩减前图片尺寸

rawNum = size(imageNameList,1); %rawNum:样本数
rolNum=newSize(1)*newSize(2); %原始维度
samples = zeros(rawNum, rolNum);
img = imread([path,imageNameList{1}]);
originSize = size(img);
originSize = originSize(1:2);
clear img;
%准备样本矩阵
for k=1:rawNum
imageTemp_ = imread([path,imageNameList{k}]);
imageTemp = im2double(imageTemp_);
if length(size(imageTemp))==3
imageTemp = rgb2gray(imageTemp); %灰度化
imageTemp = histeq(imageTemp); %直方图均衡化
end
imageTemp2 = imresize(imageTemp, newSize);
imageTemp3 = imageTemp2(:)';
samples(k,:) = imageTemp3;
end
samplesMean = mean(samples); %样本均值
end


%子函数,进行施密特正交化,对实对称矩阵的特征向量求正交矩阵
function vv = simitzj(v, d) %vv = simitzj(v, d) %功能:对输入的实对称的特征值,特征向量施密特正交化,单位化 %输入: %v:特征向量 %d:特征值 %输出: %vv:正交化单位化后的特征向量
ii=1;
k=0;
nn=length(d);
vv=zeros(size(v));
while ii<=nn
jj=ii-k;
b=0;
while jj<ii
b=b+dot(vv(:,jj),v(:,ii))/dot(vv(:,jj),vv(:,jj))*vv(:,jj);
jj=jj+1;
end
vv(:,ii)=v(:,ii)-b;
ii=ii+1;
if ii<=nn && d(ii)==d(ii-1)
k=k+1;
else
k=0;
end
end
for ii=1:nn
vv(:,ii)=vv(:,ii)/sqrt(dot(vv(:,ii),vv(:,ii)));
end
end


function fileList=getFileList(path)
% fileList=getFileList(path)
%输入:
%path:所获取的文件列表的路径
%输出:
%fileList:path路径下文件列表,cell数组
list=dir(path);
n=size(list,1);
fileList=cell(n-2,1);
k=1;
for i=1:n
if strcmp(list(i).name,'.') || strcmp(list(i).name, '..')
continue;
end
fileList{k}=list(i).name;
k=k+1;
end
end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  matlab 脸部识别