MatConvNet使用入门之车牌数字字符识别

学习MatConvNet,有一个很经典的例子是车牌数字字符识别。

    相对于上一篇提到的利用已经训练好的模型imagenet-vgg-m-2048.mat等进行分类识别,这次我们需要利用自己的数据集对模型进行训练,然后利用图片进行测试。

    这里我们用到了车牌数据集,形式如下:

MatConvNet使用入门之车牌数字字符识别_第1张图片


1、读取图片用于训练。cnn_plate_setup_data.m  

%读取相应的图片和标签,并减去均值
function imdb =cnn_plate_setup_data(datadir)
inputSize =[20,20,1];
subdir=dir(datadir);
imdb.images.data=[];
imdb.images.labels=[];
imdb.images.set = [] ;
imdb.meta.sets = {'train', 'val', 'test'} ;
image_counter=0;
trainratio=0.8;
for i=3:length(subdir)%类别路径
        imgfiles=dir(fullfile(datadir,subdir(i).name));
        imgpercategory_count=length(imgfiles)-2;
        disp([i-2 imgpercategory_count]);
        image_counter=image_counter+imgpercategory_count;
        for j=3:length(imgfiles)%每个类别下的图片路径
            img=imread(fullfile(datadir,subdir(i).name,imgfiles(j).name));
            img=imresize(img, inputSize(1:2));
            img=single(img);
            [~,~,d]=size(img);
            if d==3
                img=rgb2gray(img);
                continue;
            end
            imdb.images.data(:,:,:,end+1)=single(img);
            imdb.images.labels(end+1)= i-2;
            if j-2


2、没有预训练模型,所以,需要我们自己构建网络结构。 cnn_plate_init.m

%设计网络结构
function net =cnn_plate_init()
rng('default');%rng(‘default’)是恢复matlab启动时默认的全局随机流,至于rng函数,用来保证每次生成的随机变量是一致的。
rng(0) ;
%这里设计的结构是conv1->pool1->relu->conv2->pool2->relu->conv3->softmax 
f=1/100 ;
net.layers = {};
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(3,3,1,20, 'single'), zeros(1, 20, 'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;%其中conv1的参数设置为20个3*3大小的卷积核,偏置为20个0,步长为1,没有补零,后面的层可以一一分析。
net.layers{end+1} = struct('type', 'pool', ...
                           'method', 'max', ...
                           'pool', [2 2], ...
                           'stride', 2, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'relu') ;
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(3,3,20,100, 'single'),zeros(1,100,'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'pool', ...
                           'method', 'max', ...
                           'pool', [2 2], ...
                           'stride', 2, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'relu') ;
net.layers{end+1} = struct('type', 'conv', ...
   'weights', {{f*randn(3,3,100,1000, 'single'),zeros(1,1000,'single')}}, ...
   'stride', 1, ...
   'pad', 0) ;
net.layers{end+1} = struct('type', 'softmaxloss') ;

% Meta parameters
net.meta.inputSize = [20 20 1] ;
net.meta.trainOpts.learningRate = logspace(-3, -5, 100);
net.meta.trainOpts.numEpochs = 50 ;
net.meta.trainOpts.batchSize = 1000 ;

% Fill in default values
net = vl_simplenn_tidy(net) ;

end


3、把网络结果串联起来进行训练,得到学习到的模型net。

%把网络结果串联起来进行训练
function [net, info] = cnn_plate()
run(fullfile(fileparts(mfilename('fullpath')),'..\matlab', 'vl_setupnn.m')) ;
datadir='.\ann';
opts.expDir = fullfile(vl_rootnn, 'data', 'plate-baseline') ;
opts.imdbPath = fullfile(opts.expDir, 'imdb.mat');
if exist(opts.imdbPath,'file')
    imdb=load(opts.imdbPath);
else
    imdb=cnn_plate_setup_data(datadir);%读取图片  建立用于训练的数据集  并把结果保存为imdb.mat
    mkdir(opts.expDir) ;
    save(opts.imdbPath, '-struct', 'imdb') ;
end
net=cnn_plate_init();%%设计网络结构
net.meta.normalization.averageImage =imdb.images.data_mean ;
opts.train.gpus = [];%opts.train.gpus=[]表示cpu。有的话中括号里面填GPU编号,如果只有一块GPU,中括号里填1
[net, info] = cnn_train(net, imdb, getBatch(opts), ...%利用数据集训练模型
  'expDir', opts.expDir, ...
  net.meta.trainOpts, ...
  opts.train, ...
  'val', find(imdb.images.set == 3)) ;%测试集


function fn = getBatch(opts)
% --------------------------------------------------------------------
    fn = @(x,y) getSimpleNNBatch(x,y) ;
end
function [images, labels]  = getSimpleNNBatch(imdb, batch)
    images = imdb.images.data(:,:,:,batch) ;
    labels = imdb.images.labels(1,batch) ;
    if opts.train.gpus > 0
        images = gpuArray(images) ;
    end
end
end

    同时,例子中还绘制了学习过程中训练集和测试集的error情况:

MatConvNet使用入门之车牌数字字符识别_第2张图片

随着迭代次数的增加,模型对训练集和验证集的识别效果都越来越好。



4、用第47个文件夹里的第一张图片做测试,利用学习到的模型识别这个图片中的字符是什么

addpath('../');
run(fullfile(fileparts(fileparts(mfilename('fullpath'))),...
  'matlab', 'vl_setupnn.m')) ;
addpath ../data/plate-baseline;
%datadir='E:\MachineLearning\caffe\caffe-windows-master\platerecognition\data\platerecognition\chars2';
datadir='.\ann';
class=47;%%test  
index=1;%%test  这里用第47个文件夹里的第一张图片做测试,利用模型识别这个图片中的字符是什么
subdir=dir(datadir);
imgfiles=dir(fullfile(datadir,subdir(class+2).name));
fprintf('这个车牌上的数字(字符)是:%s\n',subdir(class+2).name);
img=imread(fullfile(datadir,subdir(class+2).name,imgfiles(index+2).name));
imshow(img);
net=load('net-epoch-50.mat');%%取出我们的最终训练模型,这里只训练了50次
net=net.net;
im_=single(img);
im_=imresize(im_,net.meta.inputSize(1:2));
im_=im_ - net.meta.normalization.averageImage;
opts.batchNormalization = false ;
net.layers{end}.type = 'softmax';
res=vl_simplenn(net,im_);
scores=squeeze(gather(res(end).x));
[bestScore,best]=max(scores);
fprintf('利用模型识别到的这个车牌上的数字(字符)是:%s\n',subdir(best+2).name);
fprintf('score:%d\n',bestScore);

运行结果为:

MatConvNet使用入门之车牌数字字符识别_第3张图片

可以看出,学习到的模型的识别结果是正确的。

你可能感兴趣的:(MatConvNet)