本文章大致分为5个板块,分别是MNIST数据库,深度学习神经网络的构建,图像预处理,图像识别,简单的英文字母识别展示。
1.MNIST数据库
总所周知,MNIST数据库是专门用于为手写数字识别系统提供数据库的,本手写数字识别系统所利用的MNIST数据库来自于http://yann.lecun.com/exdb/mnist/网站,需要将网站中的四个文件都给下载下来。该MNIST数据库中含有60000张手写数字图片,每一张图片的大小都为28*28,而且10000张图片用于测试,50000张图片用于训练。
2.深度学习网络的构建
本深度学习网络的构建利用到的是Matlab R2020a版本,其中有一个软件叫做deepNetworkDesigner,这是该版本的Matlab软件所自带的。
接下来就是深度学习网络的构建,其结构图如下所示:
其中的参数设置,imageinput的参数inputsize更改为28,28,1;conv的参数filterSzie更改为5,5,然后Numfilter更改为6;maxpool的参数PoolSize和Stride都更改为2,2;conv的参数filterSzie更改为5,5,然后Numfilter更改为16;fc的参数OutputSize更改为120;fc的参数OutputSize更改为84;fc的参数OutputSize更改为10。(以上按照图中的连接顺序进行说明,若未提及,则不需要更改参数。)最后将该结构导出为代码,此处只是为了参照结构设置是否正确,完整的代码会在后面呈现。
layers = [
imageInputLayer([28 28 1],"Name","imageinput")
convolution2dLayer([5 5],6,"Name","conv_1","Padding","same")
tanhLayer("Name","tanh_1")
maxPooling2dLayer([2 2],"Name","maxpool_1","Padding","same","Stride",[2 2])
convolution2dLayer([5 5],16,"Name","conv_2","Padding","same")
tanhLayer("Name","tanh_2")
maxPooling2dLayer([2 2],"Name","maxpool_2","Padding","same","Stride",[2 2])
fullyConnectedLayer(120,"Name","fc_1")
fullyConnectedLayer(84,"Name","fc_2")
fullyConnectedLayer(10,"Name","fc_3")
softmaxLayer("Name","softmax")
classificationLayer("Name","classoutput")];
3.图像预处理
本手写数字识别系统的预处理部分的代码涉及到图像规范化、图像去噪处理、图像二值化、图像膨胀处理,并将此部分代码命名为s3_。
%% 图像规范化
%初始化,读入图像,图像数据为m*n*color
test_image=X;
imshow(test_image);
img=test_image;
%变化后的图像
[row,col,color] = size(img);%获得图像的行列数及色板数
row = round(row*3);%新图像的行
col = round(col*3);%新图像的列
%使新图像初始化
%使用class获得原图像的数据类型,使得新图像得数据类型与原图像相同
img_new=zeros(row,col,color,class(img));
%对新图像的行列色板赋色
for i = 1:row
for j = 1:col
for n = 1:color
x = round(i/3);
y = round(j/3);
%为了防止x和y为0,对x和y进行加一处理
if x == 0
x = 1+x;
end
if y == 0
y = y+1;
end
img_new(i,j,n) = img(x,y,n);
end
end
end
test_image=img_new;
%% 图像去噪处理 中值滤波法
% test_image1 = imnoise(test_image,'salt & pepper',0.02)
% test_image2 = medfilt3(test_image1)
%
% test_image = imnoise(test_image,'salt&pepper',0.02)
test_image = medfilt3(test_image);
%% 图像二值化
shape = size(test_image);
dimension = numel(shape);
if dimension > 2
test_image = rgb2gray(test_image);
end
test_image = imresize(test_image,[28,28]);
test_image = imbinarize(test_image,0.8);
test_image = imcomplement(test_image);
% % 显示原图像
% figure;
% imshow(test_image);
% title("Original Image");
%% 图像膨胀
B=[0 1 0;1 1 1;0 1 0];
Z=imdilate(test_image,B);
test_image = Z;
% % 显示新图像
% figure;
% imshow(Z);
% title("New Image");
axes(h3);
imshow(test_image);
4.图像识别
代码呈现:
此部分代码命名为s1
datapath="./Mnist/";
filenameImagesTrain=strcat(datapath,'train-images-idx3-ubyte');
filenameLabelsTrain=strcat(datapath,'train-labels-idx1-ubyte');
filenameImagesTest=strcat(datapath,'t10k-images-idx3-ubyte');
fielnameLabelsTest=strcat(datapath,'t10k-labels-idx1-ubyte');
XTrain=processMNISTimages(filenameImagesTrain);
YTrain=processMNISTlabels(filenameLabelsTrain);
XTest=processMNISTimages(filenameImagesTest);
YTest=processMNISTlabels(fielnameLabelsTest);
%%
% 搭建神经网络
layers = [
imageInputLayer([28 28 1],"Name","imageinput")
convolution2dLayer([5 5],6,"Name","conv_1","Padding","same")
tanhLayer("Name","tanh_1")
maxPooling2dLayer([2 2],"Name","maxpool_1","Padding","same","Stride",[2 2])
convolution2dLayer([5 5],16,"Name","conv_2","Padding","same")
tanhLayer("Name","tanh_2")
maxPooling2dLayer([2 2],"Name","maxpool_2","Padding","same","Stride",[2 2])
fullyConnectedLayer(120,"Name","fc_1")
fullyConnectedLayer(80,"Name","fc_2")
fullyConnectedLayer(10,"Name","fc_3")
softmaxLayer("Name","softmax")
classificationLayer("Name","classoutput")];
options=trainingOptions('sgdm',...%优化器
'LearnRateSchedule','piecewise',...%学习率
'LearnRateDropFactor',0.2,...%
'LearnRateDropPeriod',5,...
'MaxEpochs',20,...%最大学习整个数据集的次数
'MiniBatchSize',128,...%每次学习样本数
'Plots','training-progress');%画出整个训练过程
doTraining = true;
if doTraining
trainNet=trainNetwork(XTrain,YTrain,layers,options);
end
save Minist_LeNet5 trainNet;%保存训练后的模型
yTest=classify(trainNet,XTest);
accuracy=sum(yTest==YTest)/numel(YTest);
%%
% 处理Mnist数据集图像
function X = processMNISTimages(filename)
[fileID,errmsg] = fopen(filename,'r','b');
if fileID < 0
error(errmsg);
end
magicNum = fread(fileID,1,'int32',0,'b');
if magicNum == 2051
fprintf('\nRead MNIST image data...\n')
end
numImages = fread(fileID,1,'int32',0,'b');
fprintf('Number of images in the dataset: %6d ...\n',numImages);
numRows = fread(fileID,1,'int32',0,'b');
numCols = fread(fileID,1,'int32',0,'b');
X = fread(fileID,inf,'unsigned char');
X = reshape(X,numCols,numRows,numImages);
X = permute(X,[2 1 3]);
X = X./255;
X = reshape(X, [28,28,1,size(X,3)]);
% X = dlarray(X, 'SSCB');
fclose(fileID);
end
% 处理Mnist数据集标签
function Y = processMNISTlabels(filename)
[fileID,errmsg] = fopen(filename,'r','b');
if fileID < 0
error(errmsg);
end
magicNum = fread(fileID,1,'int32',0,'b');
if magicNum == 2049
fprintf('\nRead MNIST label data...\n')
end
numItems = fread(fileID,1,'int32',0,'b');
fprintf('Number of labels in the dataset: %6d ...\n',numItems);
Y = fread(fileID,inf,'unsigned char');
Y = categorical(Y);
fclose(fileID);
end
此部分代码命名为s5
load('Minist_LeNet5.mat');
%test_result = Recognition(trainNet, test_image);
test_result = classify(trainNet, test_image);
ch=test_result;
set(h6,'String',ch,...
'FontSize',30);
此部分代码命名为s6
%op
%读取图像文件,用对话框方式读取文件。
[filename,pathname]=uigetfile({'*.bmp';'*.jpg';'*.png';...
'*.gif';'*.*'},...
'Pick an Image File');
X=imread([pathname,filename]);
%显示图像
axes(h0);%将h0设置为当前坐标轴句柄
imshow(X);%在h0上显示原始图像
交互界面代码命名为smain,可以直接运行(如果上述操作正确的话)
clear all
clc;
%形成用户界面
clear all;
%添加图形窗口
H=figure('Color',[0 1 0],...
'position',[400 300 500 400],...
'Name','基于深度学习神经网络的手写数字识别',...
'NumberTitle','off',...
'MenuBar','none');
%画坐标轴对象,显示原始图像
h0=axes('position',[0.1 0.6 0.3 0.3]);
%添加训练神经网络按钮
h1=uicontrol(H,'Style','push',... %uicontrol(user interface control,用户界面控制),包括按钮、滑标、文本框及弹出式菜单
'Position',[280 300 80 60],...
'String','网络训练',...
'FontSize',14,...
'Call','s1');
%添加图像打开按钮
h2=uicontrol(H,'Style','push',...
'Position',[380 300 80 60],...
'String','选择图片',...
'FontSize',14,...
'Call','s6');
%画坐标轴对象,显示经过预处理之后的图像
h3=axes('position',[0.1 0.2 0.3 0.3]);
%添加预处理按钮
h4=uicontrol(H,'Style','push',...
'Position',[380 200 80 60],...
'String','图像预处理',...
'FontSize',10,...
'Call','s3_');
%添加识别按钮
h5=uicontrol(H,'Style','push',...
'Position',[350 100 80 60],...
'String','数字识别',...
'FontSize',14,...
'Call','s5');
%添加显示识别结果的文本框
h6=uicontrol(H,'Style','text',...
'Position',[250 10 100 80],...
'String','识别结果',...
'FontSize',16,...
'Fore',[0 0 1]);
5.简单英文字母识别展示
这个程序比较垃圾,我个人的理解是只能识别给定图片的26张英文字母。慎用,还需改进。
此部分代码命名为y0
%open
%读取文件
[filename,pathname] =uigetfile({'*.bmp';'*.png';'*.jpg';'*.gif';'*.*'},...
'Pick an image File');
X=imread([pathname,filename]);
axes(h0);
imshow(X);
此部分代码命名为y1
%y1
M = 1;%人数
N = M*26;%样本数
%获取26个大写英文字母的数据
for kk = 0:N-1
p1 = ones(16,16);%初始化16*16的二值化图像
m = strcat('word\',int2str(kk),'.bmp');%形成文件名
x = imread(m,'bmp');%读取图像
bw = im2bw(x,0.5);%对图像进行二值化处理
%用矩形截取
[i,j] = find(bw==0);%查找像素为黑色的坐标
%取边界坐标
imin = min(i);
jmin = min(j);
imax = max(i);
jmax = max(j);
bw1 = bw(imin:imax,jmin:jmax);%截取
%调整比例,使其缩放成16*16
rate = 16/max(size(bw1));
bw1 = imresize(bw1,rate);%会存在转换误差
%将图像转化为16*16
[i,j] = size(bw1);
i1 = round((16-i)/2);
j1 = round((16-j)/2);
p1(i1+1:i1+i,j1+1:j1+j) = bw1;
p1 = -1.*p1+ones(16,16);
%将p1转换成输入向量
for m = 0:15
p(m*16+1:(m+1)*16,kk+1) = p1(1:16,m+1);
end
end
%形成目标向量
for kk = 0:M-1
for ii = 0:25
t(kk+ii+1) = ii;
end
end
%设置输入向量
pr(1:256,1) = 0;
pr(1:256,2) = 1;
net = newff(pr,[25 1],{'logsig' 'purelin'},'traingdx','learngdm');
net.trainParam.epochs = 2500;
net.trainParam.goal = 0.001;
net.trainParam.show = 10;
net.trainParam.lr = 0.05;
net = train(net,p,t);
save E53net net;
此部分代码命名为y2
p(1:256,1)=1;
load E53net net;%加载训练后的BP网络
p1 = ones(16,16);%初始化16*16的二值化图
bw = im2bw(X,0.5);%对图像进行二值化处理
%用矩形截取
[i,j] = find(bw==0);%查找像素为黑色的坐标
%取边界坐标
imin=min(i);
imax=max(i);
jmin=min(j);
jmax=max(j);
bw1 = bw(imin:imax,jmin:jmax);%截取
%调整比例,使其缩放成16*16
rate = 16/max(size(bw1));
bw1 = imresize(bw1,rate);%会存在转换误差
%将图像转化为16*16
[i,j] = size(bw1);
i1 = round((16-i)/2);
j1 = round((16-j)/2);
p1(i1+1:i1+i,j1+1:j1+j) = bw1;
p1 = -1.*p1+ones(16,16);
% B=[0 1 0;1 1 1;0 1 0];
% p1=imdilate(p1,B);
axes(h3);
imshow(p1);
此部分代码命名为y3
%recognize
%生成向量形式
for m=0:15
q(m*16+1:(m+1)*16,1)=p1(1:16,m+1);
end
%识别
%[a,Pf,Af]=sim(net,q)
a=sim(net,q);
a=round(a); %取整数
switch a
case 0,ch='A';
case 1,ch='B';
case 2,ch='C';
case 3,ch='D';
case 4,ch='E';
case 5,ch='F';
case 6,ch='G';
case 7,ch='H';
case 8,ch='I';
case 9,ch='J';
case 10,ch='K';
case 11,ch='L';
case 12,ch='M';
case 13,ch='N';
case 14,ch='O';
case 15,ch='P';
case 16,ch='Q';
case 17,ch='R';
case 18,ch='S';
case 19,ch='T';
case 20,ch='U';
case 21,ch='V';
case 22,ch='W';
case 23,ch='X';
case 24,ch='Y';
case 25,ch='Z';
end
%显示识别结果
set(h6,'String',ch,...
'FontSize',30);
此部分代码命名为ymain,可以直接运行。(需要确保有数据库)
clear all
clc;
%形成用户界面
clear all;
%添加图形窗口
H=figure('Color',[0 1 0],...
'position',[400 300 500 400],...
'Name','基于BP学习神经网络的手写英文字母的识别',...
'NumberTitle','off',...
'MenuBar','none');
%画坐标轴对象,显示原始图像
h0=axes('position',[0.1 0.6 0.3 0.3]);
%添加训练神经网络按钮
h1=uicontrol(H,'Style','push',... %uicontrol(user interface control,用户界面控制),包括按钮、滑标、文本框及弹出式菜单
'Position',[280 300 80 60],...
'String','网络训练',...
'FontSize',14,...
'Call','y1');
%添加图像打开按钮
h2=uicontrol(H,'Style','push',...
'Position',[380 300 80 60],...
'String','选择图片',...
'FontSize',14,...
'Call','y0');
%画坐标轴对象,显示经过预处理之后的图像
h3=axes('position',[0.1 0.2 0.3 0.3]);
%添加预处理按钮
h4=uicontrol(H,'Style','push',...
'Position',[380 200 80 60],...
'String','图像预处理',...
'FontSize',10,...
'Call','y2');
%添加识别按钮
h5=uicontrol(H,'Style','push',...
'Position',[350 100 80 60],...
'String','英文字母识别',...
'FontSize',14,...
'Call','y3');
%添加显示识别结果的文本框
h6=uicontrol(H,'Style','text',...
'Position',[250 10 100 80],...
'String','识别结果',...
'FontSize',16,...
'Fore',[0 0 1]);
6.仿真结果显示
网盘链接:https://pan.baidu.com/s/1bnSiGxVuSKGILhAk4K9h5w
提取码:r2qk