基于MATLAB的PCA人脸识别实现

来源:互联网 发布:sublimetext3 mac 编辑:程序博客网 时间:2024/05/17 04:52

基于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);endtrueClassType = (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;    endendT_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));    endendK=1; %KNN最近邻的k值[~, sortDisIndex] = sort(dis, 2, 'ascend');KnnClassType = zeros(m, n);for i=1:m    KnnClassType(i,:)=trainClassType(sortDisIndex(i,:))';endtestClassType = 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'});endend
%子函数:准备原始数据阵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;endsamplesMean = 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;    endendfor ii=1:nn    vv(:,ii)=vv(:,ii)/sqrt(dot(vv(:,ii),vv(:,ii)));endend
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;endend
原创粉丝点击