这篇是本博客第二篇文章的续文,即关于SVM和SRC做人脸识别我所做的代码实现(Matlab)。虽然说目前绝大部分都是用深度学习来做人脸识别,而且效果一骑绝尘,但是某些特定条件下(比如小样本)传统方法依然是值得大家回顾与学习的。 至于理论部分,请见: https://blog.csdn.net/weixin_43795395/article/details/88729251
所用到的Yale数据集,重新上传了百度云:
链接: https://pan.baidu.com/s/1FBsuYheRwX4WTmjrE0cmTw 提取码: 1mxn
Now!
完整代码已上传至Github:https://github.com/maxee1900 走过路过不要忘了点个星星啊@!@
% Face recognition on yale data---SVM方法
% by Ma Xin. 2018.6.22
clear all
clc
close all
%% 读取人脸数据、降采样
yaleData = 'C:\Users\maxee\Desktop\matlab\yaleBExtData ';
dataDir = dir(yaleData); %dir 列出指定路径下的所有子文件夹和子文件
for i = 3:40
facefile = [yaleData,'\',dataDir(i).name];
oneperson = dir ([facefile, '\*.pgm']);
Asample = [];
for j = 1:length(oneperson)-1
image = imread([oneperson(j).folder,'\',oneperson(j).name]);
downsample = image(1:4:192, 1:4:168);
imagedouble = double(downsample); %转化为double型
faceshape = reshape(imagedouble,1,48*42); %reshape按列顺序转换,不是随机的
Asample = [Asample;faceshape]; %m行样本,n行维度
end
Allsample{i-2} = Asample; %构成1*38的cell数组
end
%% 构造训练集合(p=7,13,20)
p = 13;
TrainData = [];
TestData = [];
TrainLabel = [];
TestLabel = [];
for i = 1:length(Allsample)
% traindata and testdata for every person
[m,~] = size(Allsample{i});
randse = randperm(m); %得到随机数列,因为不是所有的文件夹中都有64幅图像可用,故取m
train_onep = Allsample{i}(randse(1:p),:);
test_onep = Allsample{i}(randse(p+1:m),:);
trainlabel_onep = i * ones(p,1);
testlabel_onep = i * ones(m-p,1);
% sum to all traindata and testdata
TrainData = [TrainData; train_onep];
TestData = [TestData; test_onep];
TrainLabel = [TrainLabel; trainlabel_onep];
TestLabel = [TestLabel; testlabel_onep];
end
%% PCA降维至50,100,200维(原维度为2016)
trainsamples = TrainData';
testsamples = TestData';
[Pro_Matrix,Mean_Image]=my_pca(trainsamples,1000);
%Pro_Matrix为投影矩阵
train_project=Pro_Matrix'*trainsamples;
test_project=Pro_Matrix'*testsamples;
TrainData = train_project';
TestData = test_project';
%% 归一化
%所有训练集和测试集
Data = [TrainData;TestData];
Label = [TrainLabel;TestLabel];
%样本顺序打乱形成新的数据
a = size(Data,1);
b = randperm(a);
RandData = Data(b,:);
RandLabel = Label(b);
Guiyi = mapminmax(RandData',-1,1);
NormData = Guiyi';
%% 构造最终的训练集和测试集,训练及测试
trainNum = size(TrainData,1);
DataNum = size(Data,1);
TrainSample = NormData(1:trainNum,:);
TrainSample_label = RandLabel(1:trainNum);
TestSample = NormData(trainNum+1:DataNum,:);
TestSample_label = RandLabel(trainNum+1:DataNum);
%训练模型,计算训练所用时间
t1 = clock;
model = svmtrain(TrainSample_label,TrainSample,'-s 0 -t 2 -c 50'); %选用高斯核函数
t2 = clock;
SVMtrainTime = etime(t2,t1);
%测试并计算平均每幅图片分类所用时间
t3 = clock;
[predicted_label, accuracy, decision_values] = svmpredict(TestSample_label,TestSample,model);
t4 = clock;
TestTime = etime(t4,t3);
t = TestTime / size(TestSample,1);
fprintf('模型训练时间为:%3.4fs\n',SVMtrainTime);
fprintf('平均每幅图片分类所用时间为:%3.4fs\n',t);
(说明:其中引用了其他作者的L1范数优化算法代码SolveHomotopy_CBM_std.m,因为篇幅较长本文中省略。)
% Face recognition on yale data---稀疏表示方法(SRC)
% by Ma Xin. 2018.6.22
clear all
clc
close all
%精度 测试时间 实验次数
Accu = zeros(1,10);
Time = zeros(1,10);
for k = 1:10
clearvars -except Accu Time k %清除其他变量
%% 读取人脸数据、降采样,形成数据集和标签集
yaleData = 'C:\Users\maxee\Desktop\matlab\yaleBExtData ';
dataDir = dir(yaleData); %dir 列出指定路径下的所有子文件夹和子文件
label = [];
allsamples = [];
for i = 3:40
facefile = [yaleData,'\',dataDir(i).name];
oneperson = dir ([facefile, '\*.pgm']);
Asample = [];
for j = 1:length(oneperson)-1
image = imread([oneperson(j).folder,'\',oneperson(j).name]);
downsample = image(1:4:192, 1:4:168);
imagedouble = double(downsample); %转化为double型
faceshape = reshape(imagedouble,48*42,1); %reshape按列顺序转换,不是随机的
Asample = [Asample,faceshape];
allsamples = [allsamples,faceshape]; %所有数据样本:m列样本,n行维度
label = [label,i-2]; %所有标签集
end
Allsample{i-2} = Asample; %构成1*38的cell数组
end
%% 分出训练集和测试集 (p=7,13,20)
p = 13;
trainsamples = [];
testsamples = [];
trainlabels = [];
testlabels = [];
for i = 1:length(Allsample)
m = size(Allsample{i},2);
randse = randperm(m);
train_one = Allsample{i}(:,randse(1:p));
test_one = Allsample{i}(:,randse(p+1:m));
trainlabel_one = i * ones(1,p);
testlabel_one = i * ones(1,m-p);
trainsamples = [trainsamples,train_one];
testsamples = [testsamples,test_one];
trainlabels = [trainlabels,trainlabel_one];
testlabels = [testlabels,testlabel_one];
end
%% PCA降维至50,100,200
[Pro_Matrix,Mean_Image]=my_pca(trainsamples,100);
%Pro_Matrix为投影矩阵
train_project=Pro_Matrix'*trainsamples;
test_project=Pro_Matrix'*testsamples;
%% 单位化
trainNorm = normc(train_project);
testNorm = normc(test_project);
%% 识别并计算准确率
testNum = size(testNorm,2); %总测试数
trainNum = size(trainNorm,2); %总训练数
labelpre = zeros(1,testNum); %标签预测分配内存
classnum = length(Allsample);
h = waitbar(0,'please wait...'); %进度条函数,数值在0~1
for i = 1:testNum
t1 = clock;
xp = SolveHomotopy_CBM_std(trainNorm,testNorm(:,i),'lambda',0.01);
%针对第i个测试样本,用Homotopy方法求优化解,稀疏表示优化算法之一,用到了L1和L2范数
r = zeros(1, classnum);
for j = 1:classnum
%将xp中元素处理后归于xn.其中xp中与j类对应的元素保留,其他的为0
xn = zeros(trainNum,1);
index = (j==trainlabels); %index为bool变量
xn(index) = xp(index); %index与xp中位置自动对齐
r(j) = norm((testNorm(:,i) - trainNorm * xn)); %误差的2范数
end
[~,pos] = min(r); %返回r中误差最小的位置
labelpre(i) = pos;
t2 = clock;
testtime(i) = etime(t2,t1);
per = i / testNum;
waitbar(per,h,sprintf('第%d次实验:%2.0f%%',k,per*100)); %显示每个样本测试进度条
end
close(h);
Avtest_time = mean(testtime,2);
accuracy = sum(labelpre == testlabels) / testNum;
fprintf('第%d次实验识别率为:%5.2f%%\n\n',k,accuracy*100);
fprintf('第%d次实验平均每幅图片分类所用时间为:%6.4fs\n',k,Avtest_time);
%% 保存第K次实验精度与测试时间
Accu(k) = accuracy;
Time(k) = Avtest_time;
end
function [Pro_Matrix,Mean_Image]=my_pca(Train_SET,Eigen_NUM)%输入:
%Train_SET:训练样本集,每列是一个样本,每行一类特征,Dim*Train_Num
%Eigen_NUM:投影维数
%输出:
%Pro_Matrix:投影矩阵
%Mean_Image:均值图像
[Dim,Train_Num]=size(Train_SET);
Mean_Image=mean(Train_SET,2); %各行的均值 维度的均值
Train_SET=bsxfun(@minus,Train_SET,Mean_Image); %每一行的元素减去每一行的均值
R=Train_SET*Train_SET'/(Train_Num-1); %
[eig_vec,eig_val]=eig(R); %特征向量和特征值
eig_val=diag(eig_val); % 取矩阵的对角线返回到向量
[~,ind]=sort(eig_val,'descend');
%按降序排列 ~为排列好的向量 ind为其对应在元向量的索引
W=eig_vec(:,ind); %原特征向量的矩阵,重新按列排列
Pro_Matrix=W(:,1:Eigen_NUM); %取1:投影维数
写博不易,您的支持让知识之花绽放得更美丽 ~_~