【项目实战一】基于人工神经网络ANN的车牌识别
前言:车牌识别技术的发展与推广有利于加强对道路交通的管理,与人民出行安全息息相关。该项目实战非常适合各位读者作为本科毕业设计、课程设计或者其它进行学习,相信对大家会有很大帮助,如果需要完整源码,大家可以在评论区留言,小编会在第一时间提供给你们。最后,非常欢迎大家对本文内容批评指正!
目录
1、车牌识别系统的设计方案
2、车牌识别系统的代码实现
2.1 图像预处理
2.2 车牌分割
2.3 字符分割
2.4 字符识别
3、车牌识别系统的功能展示
1、车牌识别系统的设计方案
本文的车牌识别系统是基于Matlab编程语言具体实现的,主要包括图像预处理,车牌分割,字符分割,字符识别4个模块,其中字符识别是基于ANN完成的,所以还需要先训练好ANN人工神经网络,具体流程如图1所示。另外,为了方便更好得将系统功能展示出来,小编特意设计了一个人机交互界面,如图2所示,使项目看起来更加完整。
图1
图2
2、车牌识别系统的代码实现
2.1 图像预处理
在图像识别任务中,图像前期的预处理工作十分重要,它有可能会直接影响图像的识别效果,所以必须根据各自的项目特点做出正确的图像预处理。在本文的车牌识别项目前期工作中主要对输入图像进行了灰度化处理和直方图均衡化两项操作。因为直方图均衡化处理之后,原来占比较少的像素灰度会被分配到别的灰度去,像素相对集中,提高了图像的局部对比度和清晰度,可以有效增强图像。
现在用一个例子来详细介绍一下直方图均衡化的原理,假设原图像像素值分布为:
255 | 128 | 200 | 50 |
50 | 200 | 255 | 50 |
255 | 200 | 128 | 128 |
200 | 200 | 255 | 50 |
均衡化操作过程:
灰度值 | 像素个数 | 概率 | 累积概率 | 根据函数映射后的灰度值 | 取整 |
50 | 4 | 0.25 | 0.25 | 0.25×(255-0)=63.75 | 64 |
128 | 3 | 0.1875 | 0.4375 | 0.4375×(255-0)=111.56 | 112 |
200 | 5 | 0.3125 | 0.75 | 0.75×(255-0)=191.25 | 191 |
255 | 4 | 0.25 | 1 | 1×(255-0)=255 | 255 |
均衡化后的像素值分布:
255 | 112 | 191 | 64 |
64 | 191 | 255 | 64 |
255 | 191 | 112 | 112 |
191 | 191 | 255 | 64 |
项目中图像预处理的代码如下:
function pushbutton8_Callback(hObject, eventdata, handles)
%图像增强
image = handles.I;
gray = rgb2gray(image);
new_gray = histeq(gray); % 直方图均衡 ,图像增强
axes(handles.axes3);
imshow(new_gray);
2.2 车牌分割
一幅图像中往往由很多元素组成,我们必须根据元素的特点,比如形状,颜色等,筛选出感兴趣域。由于小编做的是车牌识别,所以必须先从图像中确定车牌的所在位置,并且将车牌区域从图像中分割出来。因为车牌的背景颜色是蓝色,如图3所示,本项目就是根据颜色这一特点先确定车牌所在区域的大概位置,再通过Canny边缘检测和形态学将车牌的准确位置从图像中分割出来,如图4所示。
图3
图4
这部分代码实现如下:
function pushbutton9_Callback(hObject, eventdata, handles)
%边缘检测
image = handles.I;
gray = rgb2gray(image);
new_gray = histeq(gray);
if size(new_gray,1)>1000new_gray_1 = imresize(new_gray,0.1);
elsenew_gray_1 =new_gray;
end
bw = edge(new_gray_1,'canny');
axes(handles.axes4);
imshow(bw);% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
%% 车牌定位Color = 2; % 颜色标记 蓝 handles.Color = Color;Image = handles.I;DI = Image(:,:,3);
GI = (Image(:,:,1)<100 & Image(:,:,2)<150 & Image(:,:,3)>120 ...& abs(double(Image(:,:,2))-double(Image(:,:,3)))>30);axes(handles.axes5);
imshow(GI);
handles.GI = GI;
guidata(hObject, handles);% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
%% 分割车牌
d = handles.GI;se = ones(40); % 腐蚀膨胀模版d = imdilate(d,se);% 再做膨胀运算
d = imerode(d,se); % 先做腐蚀运算
% 先膨胀后腐蚀的过程称为开运算。用来填充物体内细小空洞、连接邻近物体、平滑其边界的同时并不明显改变其面积。
d = bwareaopen(d,100); % 移除小对象 小区域肯定是噪声STATS = regionprops(d);
area = [];for i = 1:size(STATS,1)area = [area;STATS(i).Area];
end
[value,index] = max(area); Bound = round(STATS(index).BoundingBox);xmin = Bound(2);
xmax = Bound(2)+Bound(4);
ymin = Bound(1);
ymax = Bound(1)+Bound(3);II = handles.I(xmin:xmax,ymin:ymax,:);axes(handles.axes6);
imshow(II);handles.Divice = II;
guidata(hObject, handles);
2.3 字符分割
将车牌所在区域从图像中准确分割出来后,我们就要开始车牌识别的准备工作了,就是将车牌中的所有字符单独分割开,从而方便后续的字符识别工作,这部分代码如下:
function pushbutton11_Callback(hObject, eventdata, handles)
%% 字符分割
I_VER_JZ_S = handles.chepaiyu;
thresh = handles.chepaiyuT;I_1=rgb2gray(I_VER_JZ_S);
K=im2bw(I_1,thresh);
[kuan,chang]=size(K);
% STATS = regionprops(K);
%
% % for i = 1:size(STATS,1)
% STATS(i).Area>
% rectangle('Position',STATS(4).BoundingBox,'EdgeColor','r');
% [x,y]=find(K==1)
a1=length(x);
[x,y]=find(K==0)b1=length(y);if a1>b1K1=~K;elseK1=K;end[a b] = size(K1);
sumK = sum(K1); %寻找阈值
T=1;
myb = find(sumK>=T); %所在的列为myb
myf = zeros(1,length(myb)); %大于阈值的列的数目for ii = 2:length(myb)if myb(ii)-myb(ii-1)<=2myb(ii-1) = 0; %myb不为0的点位跳变的前边缘_index elsemyf(ii) = myb(ii); %myf不为0的点对应跳变的后边缘_indexend
end
myd = find(myb~=0); %找到跳变的前边缘
MYE = myb(myd); %对应列号
myh = find(myf~=0); %找到跳变的后边缘
myi = myf(myh);
MYB = [1 myi];for ii = 1:length(MYE)part=sumK(1,MYB(ii):MYE(ii))sumP=sum(part,2)
end% 面积最大的前7个
for ii = 1:length(MYE) part1=sumK(1,MYB(ii):MYE(ii))sumP1=sum(part1,2)ss(ii) = sumP1;
end
[value index] = sort(ss,'descend');if length(MYE)>7nnnn = index(1:7);
elsennnn = index;
end
count = 1;
[value index] = sort(nnnn);
for num = 1:length(nnnn)
% if sumP1(1)> (chang*kuan)*0.0126 switch countcase 1axes(handles.axes8);case 2axes(handles.axes9);case 3axes(handles.axes10); case 4axes(handles.axes11); case 5axes(handles.axes12); case 6axes(handles.axes13); otherwiseaxes(handles.axes14); endii = value(num);imshow(K1(:,MYB(ii):MYE(ii)));images_test1 = imresize(K1(:,MYB(ii):MYE(ii)),[24 12]); imwrite(images_test1,strcat(num2str(ii),'.jpg'));images_test(:,count) = double(reshape(images_test1,288,1)); count = count+1;
end
handles.testnum = images_test;
guidata(hObject, handles);
2.4 字符识别
字符识别是车牌识别项目的最后一步,也是最重要的一步,有很多方法都可以实现字符识别,比如基于模板匹配的方法等,而本文采用的是一种基于人工神经网络(ANN)模型的方法。该ANN模型有3层神经网络,第一层(输入层)包含288个神经元,因为输入图像的尺寸固定是12×24;第二层(隐含层)包含30个神经元;第三层(输出层)包含44个神经元,之所以是44个神经元,是因为数据集中的车牌一共可能出现44种字符,分别是10个数字“0-9”、24个大写英文字母“A-Z"、10个各省的简称:”鄂“,”赣“,”沪“,”京“,”辽“,”苏“,”皖“,”豫“,”粤“,”浙“。
模型创建的代码:
%% 读取样本数据
DATADIR='.\sample\'; % 待处理图像目录
dirinfo=dir(DATADIR); % 获取图像目录所有文件信息
Name={dirinfo.name}; % 获取文件名
Name(1:2)=[]; % 去除文件夹固有信息
[nouse num_of_char]=size(Name); % 获取类别数量
count = 1;
images = [];
labels = [];
for cnt=1 :num_of_char % for 循环读取所有文件夹pathname=horzcat(DATADIR, Name{cnt},'\'); % 把路径和名字融合一起sub_dirinfo=dir(pathname); % 获取图像目录所有文件信息sub_Name={sub_dirinfo.name}; % 获取文件名sub_Name(1:2)=[]; [nouse num_of_image]=size(sub_Name); for i = 1: num_of_imageimage = imread(horzcat(pathname,sub_Name{i}));if size(image,3) >1 image = rgb2gray(image);endbw = im2bw(image,graythresh(image));bw1 = double(reshape(bw,288,1));images = [images,bw1];labels(count) = cnt;count = count +1;end
end
%% 设置神经网络参数并训练
input_layer_size = 288; % 12x24 输入图像大小
hidden_layer_size = 30; % 隐含层个数
num_labels = num_of_char; % 标签个数 X = images';
y = labels'; initial_Theta1 = randInitializeWeights(input_layer_size, hidden_layer_size); %初始化神经网络参数
initial_Theta2 = randInitializeWeights(hidden_layer_size, num_labels); %初始化神经网络参数
initial_nn_params = [initial_Theta1(:) ; initial_Theta2(:)];
options = optimset('MaxIter', 1200);
lambda = 1;
costFunction = @(p) nnCostFunction(p, ... % 用训练样本计算最优参数input_layer_size, ...hidden_layer_size, ...num_labels, X, y, lambda);
[nn_params, cost] = fmincg(costFunction, initial_nn_params, options);
Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ...hidden_layer_size, (input_layer_size + 1));
Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), ...num_labels, (hidden_layer_size + 1));
save model.mat Theta1 Theta2 Name
模型训练的代码:
function [X, fX, i] = fmincg(f, X, options, P1, P2, P3, P4, P5)
% 最小值搜索
if exist('options', 'var') && ~isempty(options) && isfield(options, 'MaxIter')length = options.MaxIter;
elselength = 100;
endRHO = 0.01; % a bunch of constants for line searches
SIG = 0.5; % RHO and SIG are the constants in the Wolfe-Powell conditions
INT = 0.1; % don't reevaluate within 0.1 of the limit of the current bracket
EXT = 3.0; % extrapolate maximum 3 times the current bracket
MAX = 20; % max 20 function evaluations per line search
RATIO = 100; % maximum allowed slope ratioargstr = ['feval(f, X']; % compose string used to call function
for i = 1:(nargin - 3)argstr = [argstr, ',P', int2str(i)];
end
argstr = [argstr, ')'];if max(size(length)) == 2, red=length(2); length=length(1); else red=1; end
S=['Iteration '];i = 0; % zero the run length counter
ls_failed = 0; % no previous line search has failed
fX = [];
[f1 df1] = eval(argstr); % get function value and gradient
i = i + (length<0); % count epochs?!
s = -df1; % search direction is steepest
d1 = -s'*s; % this is the slope
z1 = red/(1-d1); % initial step is red/(|s|+1)while i < abs(length) % while not finishedi = i + (length>0); % count iterations?!X0 = X; f0 = f1; df0 = df1; % make a copy of current valuesX = X + z1*s; % begin line search[f2 df2] = eval(argstr);i = i + (length<0); % count epochs?!d2 = df2'*s;f3 = f1; d3 = d1; z3 = -z1; % initialize point 3 equal to point 1if length>0, M = MAX; else M = min(MAX, -length-i); endsuccess = 0; limit = -1; % initialize quantetieswhile 1while ((f2 > f1+z1*RHO*d1) | (d2 > -SIG*d1)) & (M > 0) limit = z1; % tighten the bracketif f2 > f1z2 = z3 - (0.5*d3*z3*z3)/(d3*z3+f2-f3); % quadratic fitelseA = 6*(f2-f3)/z3+3*(d2+d3); % cubic fitB = 3*(f3-f2)-z3*(d3+2*d2);z2 = (sqrt(B*B-A*d2*z3*z3)-B)/A; % numerical error possible - ok!endif isnan(z2) | isinf(z2)z2 = z3/2; % if we had a numerical problem then bisectendz2 = max(min(z2, INT*z3),(1-INT)*z3); % don't accept too close to limitsz1 = z1 + z2; % update the stepX = X + z2*s;[f2 df2] = eval(argstr);M = M - 1; i = i + (length<0); % count epochs?!d2 = df2'*s;z3 = z3-z2; % z3 is now relative to the location of z2endif f2 > f1+z1*RHO*d1 | d2 > -SIG*d1break; % this is a failureelseif d2 > SIG*d1success = 1; break; % successelseif M == 0break; % failureendA = 6*(f2-f3)/z3+3*(d2+d3); % make cubic extrapolationB = 3*(f3-f2)-z3*(d3+2*d2);z2 = -d2*z3*z3/(B+sqrt(B*B-A*d2*z3*z3)); % num. error possible - ok!if ~isreal(z2) | isnan(z2) | isinf(z2) | z2 < 0 % num prob or wrong sign?if limit < -0.5 % if we have no upper limitz2 = z1 * (EXT-1); % the extrapolate the maximum amountelsez2 = (limit-z1)/2; % otherwise bisectendelseif (limit > -0.5) & (z2+z1 > limit) % extraplation beyond max?z2 = (limit-z1)/2; % bisectelseif (limit < -0.5) & (z2+z1 > z1*EXT) % extrapolation beyond limitz2 = z1*(EXT-1.0); % set to extrapolation limitelseif z2 < -z3*INTz2 = -z3*INT;elseif (limit > -0.5) & (z2 < (limit-z1)*(1.0-INT)) % too close to limit?z2 = (limit-z1)*(1.0-INT);endf3 = f2; d3 = d2; z3 = -z2; % set point 3 equal to point 2z1 = z1 + z2; X = X + z2*s; % update current estimates[f2 df2] = eval(argstr);M = M - 1; i = i + (length<0); % count epochs?!d2 = df2'*s;end % end of line searchif success % if line search succeededf1 = f2; fX = [fX' f1]';fprintf('%s %4i | Cost: %4.6e\r', S, i, f1);s = (df2'*df2-df1'*df2)/(df1'*df1)*s - df2; % Polack-Ribiere directiontmp = df1; df1 = df2; df2 = tmp; % swap derivativesd2 = df1'*s;if d2 > 0 % new slope must be negatives = -df1; % otherwise use steepest directiond2 = -s'*s; endz1 = z1 * min(RATIO, d1/(d2-realmin)); % slope ratio but max RATIOd1 = d2;ls_failed = 0; % this line search did not failelseX = X0; f1 = f0; df1 = df0; % restore point from before failed line searchif ls_failed | i > abs(length) % line search failed twice in a rowbreak; % or we ran out of time, so we give upendtmp = df1; df1 = df2; df2 = tmp; % swap derivativess = -df1; % try steepestd1 = -s'*s;z1 = 1/(1-d1); ls_failed = 1; % this line search failedendif exist('OCTAVE_VERSION')fflush(stdout);end
end
fprintf('\n');
训练完模型后,模型参数被保存在model.mat文件中,然后只要加载保存的模型参数就能实现字符识别,其代码实现如下:
function pushbutton5_Callback(hObject, eventdata, handles)
%% 字符识别
images_test_all = handles.testnum;
load model.mat
for i = 1:size(images_test_all,2) images_test = double(images_test_all(:,i));pred(i) = predict(Theta1, Theta2, images_test');
end
chepai = [];
for i = 1:size(pred,2)if pred(i)>0 chepai = [chepai,Name{pred(i)}];end
end
set(handles.text2,'string',chepai);
3、车牌识别系统的功能展示
【项目实战一】基于人工神经网络ANN的车牌识别相关推荐
- 福利 | 从生物学到神经元:人工神经网络 ( ANN ) 简介
文末有数据派THU福利哦 [ 导读 ] 我们从鸟类那里得到启发,学会了飞翔,从牛蒡那里得到启发,发明了魔术贴,还有很多其他的发明都是被自然所启发.这么说来看看大脑的组成,并期望因此而得到启发来构建智能 ...
- 实现人工神经网络ANN对医疗数据分类
2.3 使用ANN对医疗数据分类 IBM在2015年5月宣布推出Watson Health服务,收集健康数据交给Watson超级计算机进行分析.目前IBM Waston Health最主要的应用便是在 ...
- 深度学习(一)多层感知器MLP/人工神经网络ANN
目录 一.定义和公式 1. 多层感知器 Multi Layer Perceptron MLP 2. MLP实现非线性分类 3. Keras介绍 二. 代码实战 1. 建立MLP模型实现二分类 1.1 ...
- 干旱预测方法总结及基于人工神经网络的干旱预测案例分析(MATLAB全代码)
本案例采用SPEI干旱指数,构建ANN和BP神经网络预测模型,并开展1~3个月预见期的干旱预测,对比分析干旱预测模型的适用性,为流域干旱预警和管理提供技术依据. 干旱预测 1 干旱预测方法 1.1 统 ...
- MATLAB实现数字识别系统,基于人工神经网络的MATLAB手写数字识别系统
<基于人工神经网络的MATLAB手写数字识别系统>由会员分享,可在线阅读,更多相关<基于人工神经网络的MATLAB手写数字识别系统(8页珍藏版)>请在人人文库网上搜索. 1.基 ...
- DL之ANN/DNN: 人工神经网络ANN/DNN深度神经网络算法的简介、应用、经典案例之详细攻略
DL之ANN/DNN: 人工神经网络ANN/DNN深度神经网络算法的简介.应用.经典案例之详细攻略 相关文章 DL:深度学习(神经网络)的简介.基础知识(神经元/感知机.训练策略.预测原理).算法分类 ...
- android中私有方法 继承,Android项目实战系列—基于博学谷(五)个人资料
由于这个模块内容较多,篇幅较长,请耐心阅读. 个人资料模块分为两个部分 [x] [个人资料]() [x] [资料修改]() 一.个人资料 1.个人资料界面 (1).创建个人资料界面 在com.buxu ...
- 基于人工神经网络的识别C语言,实验一基于人工神经网络的数码识别.doc
实验一基于人工神经网络的数码识别 <人工智能导论>课程 基于人工神经网络的数码识别 班级:计1103学号:201107010330姓名:贾梦洁 成绩评定:评阅老师:日 期: 实验报告正文一 ...
- ann matlab,人工神经网络ann及其matlab仿真.ppt
人工神经网络ann及其matlab仿真 人工神经网络 的研究方法及应用刘 长 安2004. 12. 31 引 言 利用机器模仿人类的智能是长期以来人们认识自然.改造自然和认识自身的理想. 研究ANN目 ...
- android注册文件打开,Android项目实战系列—基于博学谷(三)注册与登录模块
由于这个模块内容较多,篇幅较长,请耐心阅读. 注册与登录模块分为三个部分 [x] [欢迎界面]() [x] [注册界面]() [x] [登录界面]() 一.欢迎界面 1.创建工程,命名为BoXueGu ...
最新文章
- 算法了解:RCNN、SPP-Net、Fast-RCNN、Faster-RCNN
- Java是否支持默认参数值?
- Spring Boot(五):spring data jpa的使用
- 【转】 最新版chrome谷歌浏览器Ajax跨域调试问题
- <力扣>-----利用哈希表来判断是否存在重复元素
- html流动布局,自适应css布局——流动布局新时代
- 2021_Nov_9_Supervision_STEMM_What_You_Need_In_Advance?
- java自由块_JAVA 静态的自由块和非静态的自由块
- c语言获取五子棋盘光标位置,跪求C语言五子棋悔棋部分实现
- 三维重建:三维空间中平面的旋转公式
- 源码免杀处理的技巧与tips
- stream去重_重复数据如何处理?List集合去重的四种方式
- Mysql学习总结(18)——Mysql主从架构的复制原理及配置详解
- html文档head,HTML的head标签
- 在EXCEL中使用SQL语言对工作表进行操作
- Android 开机自启动
- 如何设计 user 表?加入第三方登录呢?
- 【python黑帽子2】netcat.py编写及使用说明
- 在Hisi3531环境中为wm8978芯片添加音量调节功能及测试
- 惠普打印机双击之后没有扫描_惠普打印机 找不到 扫描图标 怎么办,急需扫描一些证件 ,求救...
热门文章
- jvm分析工具JProfiler详解
- 【查找资料】冰点文档下载免费下载百度、豆丁、丁香、畅享、MBALib、道客巴巴、Book118等文库文档
- plc中PROFIBUS通信处理器介绍
- (01)f103,4pin四脚的 oled(01)
- 通用24CXXX读写程序(GCC),兼容24C系列存储器(24C01到24C1024),支持跨器件跨页读写,支持连续
- 雅虎相册批量下载v3.0 公布!支持相册主人登录 欢迎大家试用
- 嵌入式“Hello World!”——点亮流水灯
- 金士顿U盘不断自动连接断开解决方法
- DDcGAN:用于多分辨率图像融合的双判别器生成对抗网络
- ppt视频音画不同步怎么解决?ppt音画同步设置方法