pca+svm手写数字识别

在上一篇博客里讲到在matlab中使用libsvm识别手写数字,识别精度不高,一是svm的参数没有设置好,二是在提取图像特征时,直接将图像展开为一行,没有做任何处理,导致其训练速度和识别精度都不够好,本文采用pca算法提取图像特征,然后再用svm进行分类。
主要分为两步:
1、pca特征提取
pca主成份分析,主要用来进行人脸识别,具体原理介绍可以参考这篇博客http://blog.codinglabs.org/articles/pca-tutorial.html ,提取pca特征主要有以下几个步骤:
(1)将图像归一化到固定大小n*n,然后展开为1*n^2的一维向量,假设有m个样本,则最终形成一个m*n^2的数组,每一行代表一个样本,本文所用的图像大小为28*28,样本类别为10,每个类别训练图为500张,则每一张图展开后就是一个1*756的一维向量,最终形成一个5000*756的数组dm;
(2)求每一个列向量的均值avg,其大小为1*n^2;
(3)差值a=dm-avg;
(4)协方差b=a*a’;
(5)求协方差矩阵b的特征值和特征向量,取前k个最大特征值及对应的特征向量T;
(6)令c=a’*T,c的大小为n^2*k,向量c则为原始图像到投影空间的投影向量;
(7)投影向量p=dm*c为样本的特征向量,其大小为m*k,即将一个n*n大小的图像映射为一个1*k的向量,每一行代表一个样本;
(8)将求得的投影向量p送到svm分类器中进行训练;

识别的时候,只需要将待识别的图像d(1*n^2)先减去均值avg,再与投影向量c相乘,即将原始图像d投影到其主成份分量所在的投影空间中,然后用训练好的svm模型进行识别。
matlab自带pca的函数,可以直接调用,当然也可以自己实现pca,过程也比较简单。

2、svm分类
libsvm中实现多分类采用的是one-versus-one法,参照http://blog.csdn.net/liulina603/article/details/8498759 。
整个流程的代码如下:

clear;clc;
% 训练样本数量10*500
train_count=10;
train_count_per_num=500;
% 能量
energy=90;
train_path_mask='F:\\MATLAB\\R2014a\\work\\libsvm-3.11\\data\\shouxie\\pca_svm\\train\\%01d\\%01d.bmp';
training_samples=[];
train_label=[];%训练标签

% img_size=10;% 归一化图像大小
% 训练,自带的pca函数
tic
for i=0:train_count-1
    for j=1:train_count_per_num
        img=imread(sprintf(train_path_mask,i,j));
%         img=imresize(img,[img_size img_size]); % 归一化
        if ndims(img)==3
            img=rgb2gray(img);
        end
        img=im2bw(img,5/255);
        training_samples=[training_samples;img(:)'];
    end    
    train_label(i*train_count_per_num+1:(i+1)*train_count_per_num)=ones(1,train_count_per_num)*i;
end
training_samples=double(training_samples);%一定要转double
train_label=train_label';  %训练的标签
% mu=mean(training_samples); %训练集中的平均值
[train_coeff,train_scores,~,~,train_explained,mu]=pca(training_samples); %pca
train_idx=find(cumsum(train_explained)>energy,1); %idx为前k个特征向量,explained特征值
train_coeff=train_coeff(:,1:train_idx); %投影向量
train_img_arr=train_scores(:,1:train_idx); %特征向量,训练的样本集

%svm训练
model = svmtrain(train_label, train_img_arr, '-s 0 -c 1.5 -t 0 -g 3'); 
save('shouxie_model','model'); %保存svm模型
xlswrite('train_coeff.xlsx',train_coeff); %保存特征向量
xlswrite('mu.xlsx',mu); %保存样本平均值,单样本进行测试的时候会用到

%使用训练集数据进行测试
[train_predict_label, train_accuracy, train_dec_values] =svmpredict(train_label, train_img_arr, model); % test the trainingdata

%测试
test_path_mask='F:\\MATLAB\\R2014a\\work\\libsvm-3.11\\data\\shouxie\\pca_svm\\test\\%01d\\%01d.bmp';
test_count=10;
test_count_per_num=100;
test_samples=[];
test_label=[];
for i=0:test_count-1
    for j=1:test_count_per_num
        img=imread(sprintf(test_path_mask,i,j));
%         img=imresize(img,[img_size img_size]); % 归一化
        if ndims(img)==3
            img=rgb2gray(img);
        end
        img=im2bw(img,5/255);
        test_samples=[test_samples;img(:)'];
    end    
    test_label(i*test_count_per_num+1:(i+1)*test_count_per_num)=ones(1,test_count_per_num)*i;
end
test_samples=double(test_samples);
test_label=test_label';
% test_img_arr=test_samples(:)-mu;
test_mu=repmat(mu,1000,1);
test_img_arr=test_samples-test_mu;
test_img_arr=test_img_arr*train_coeff; %测试集数据投影到投影向量上

%svm测试
[test_predict_label, test_accuracy, test_dec_values] =svmpredict(test_label, test_img_arr, model); 
toc

% test_img1=imread('F:\MATLAB\R2014a\work\libsvm-3.11\data\shouxie\pca_svm\test\0\10.bmp');
% % test_img1=imresize(test_img1,[img_size img_size]);
% test_img1=rgb2gray(test_img1);
% test_img1=im2bw(test_img1,5/255);
% test_img1=double(test_img1);
% test_img_arr1=test_img1(:)'-mu;
% test_img_arr=test_img_arr1*train_coeff;
% [predict_label, accuracy, dec_values] =svmpredict(1, test_img_arr, model); 

pca+svm手写数字识别_第1张图片
用训练样本进行测试的时候,Accuracy = 99.78% (4989/5000) ,用新的测试集时, Accuracy = 87.5% (875/1000),比直接使用原始图进行训练高多了,当然,其精度还可以进一步提升。改变-s -c -t -g 等参数进行训练时,可能会出现过拟合、欠拟合等情况,需要多次尝试确定其合适的参数值大小。参数调优可以参照这篇博客http://blog.csdn.net/chunxiao2008/article/details/50448154 ,感谢博主。

你可能感兴趣的:(图像处理)