OpenCV进阶之路:神经网络识别车牌字符
2016-03-28 08:49
399 查看
1. 关于OpenCV进阶之路
前段时间写过一些关于OpenCV基础知识方面的系列文章,主要内容是面向OpenCV初学者,介绍OpenCV中一些常用的函数的接口和调用方法,相关的内容在OpenCV的手册里都有更详细的解释,当时自己也是边学边写,权当为一种笔记的形式,所以难免有浅尝辄止的感觉,现在回头看来,很多地方描述上都存在不足,以后有时间,我会重新考虑每一篇文章,让成长系列对基础操作的介绍更加详细一些。OpenCV进阶之路相比于成长系列,不会有太多的基础函数的介绍,相对来说会更偏向于工程实践,通过解决实际问题来说明某些较高级函数的用法和注意事项,主要内容会集中在特征提取、机器学习和目标跟踪几个方向。所以这个系列文章知识点没有先后顺序之分,根据个人平时工作学习中遇到的问题而定。
这篇文章主要介绍OpenCV中神经网络的用法,并通过车牌字符的识别来说明一些参数设置,函数调用顺序等,而关于神经网络的原理在博客机器学习分类里已经详细的讲解与实现了,所以本文中就不多加说明。
2. 车牌字符识别
车牌识别是计算机视觉在实际工程中一个非常成功的应用,虽然现在技术相对来说已经成熟,但是围绕着车牌定位、车牌二值化、车牌字符识别等方向,还是不时的有新的算法出现。通过学习车牌识别来提升自己在图像识别方面的工程经验是非常好的,因为它非常好的说明了计算机视觉的一般过程:图像→预处理→图像分析→目标提取→目标识别
而整个车牌识别过程实际上相当于包含了两个上述过程:1,是车牌的识别;2,车牌字符的识别。
这篇文章其实主要是想介绍OpenCV中神经网络的用法,而不是介绍车牌识别技术。所以我们主要讨论的内容集中在车牌字符的识别上,关于定位、分割等不多加叙述叙述。
3. 字符特征提取
在深度学习(将特征提取作为训练的一部分)这个概念引入之前,一般在准备分类器进行识别之前都需要进行特征提取。因为一幅图像包含的内容太多,有些信息能区分差异性,而有些信息却代表了共性。所以我们要进行适当的特征提取把它们之间的差异性特征提取出来。这里面我们计算二种简单的字符特征:梯度分布特征、灰度统计特征。这两个特征只是配合本篇文章来说明神经网络的普遍用法,实际中进行字符识别需要考虑的字符特征远远要比这复杂,还包括相似字特征的选取等,也由于工作上的原因,这一部分并不深入的介绍。
1,首先是梯度分布特征,该特征计算图像水平方向和竖直方向的梯度图像,然后通过给梯度图像分划不同的区域,进行梯度图像每个区域亮度值的统计,以下是算法步骤:
<1>将图像由RGB图像转换为灰度图像;
<2>将图像归一化大小为8×4,并将图像展开为一行,组成特征向量。
4. OpenCV中的神经网络
关于神经网络的原理我的博客里已经写了两篇文章,并且给出了C++的实现,所以这里我就不提了,下面主要说明在OpenCV中怎么使用它提供的库函数。CvANN_MLP是OpenCV中提供的一个神经网络的类,正如它的名字一样(multi-layer perceptrons),它是一个多层感知网络,它有一个输入层,一个输出层以及1或多个隐藏层。
4.1. 首先我们来创建一个网络,我们可以利用CvANN_MLP的构造函数或者create函数。
layerSizes:一个整型的数组,这里面用Mat存储。它是一个1*N的Mat,N代表神经网络的层数,第i列的值表示第i层的结点数。这里需要注意的是,在创建这个Mat时,一定要是整型的,uchar和float型都会报错。
比如我们要创建一个3层的神经网络,其中第一层结点数为x1,第二层结点数为x2,第三层结点数为x3,则layerSizes可以采用如下定义:
后面两个参数则是SIGMOID激活函数中的两个参数α和β,默认情况下会都被设置为1。
4.2. 设置神经网络训练参数
神经网络训练参数的类型存放在CvANN_MLP_TrainParams这个类里,它提供了一个默认的构造函数,我们可以直接调用,也可以一项一项去设。term_crit:终止条件,它包括了两项,迭代次数(CV_TERMCRIT_ITER)和误差最小值(CV_TERMCRIT_EPS),一旦有一个达到条件就终止训练。
train_method:训练方法,OpenCV里提供了两个方法一个是很经典的反向传播算法BACKPROP,另一个是弹性反馈算法RPROP,对第二种训练方法,没有仔细去研究过,这里我们运用第一种方法。
剩下就是关于每种训练方法的相关参数,针对于反向传播法,主要是两个参数,一个是权值更新率bp_dw_scale和权值更新冲量bp_moment_scale。这两个量一般情况设置为0.1就行了;太小了网络收敛速度会很慢,太大了可能会让网络越过最小值点。
我们一般先运用它的默认构造函数,然后根据需要再修改相应的参数就可以了。如下面代码所示,我们将迭代次数改为了5000次。
4.3. 神经网络的训练
我们先看训练函数的接口,然后按接口去准备数据。outputs:输出矩阵。我们实际在训练中,我们知道每个样本所属的种类,假设一共有nClass类。那么我们将outputs设置为一个nSample行nClass列的矩阵,每一行表示一个样本的预期输出结果,该样本所属的那类对应的列设置为1,其他都为0。比如我们需要识别0-9这10个数字,则总的类数为10类,那么样本数字“3”的预期输出为[0,0,1,0,0,0,0,0,0,0];
sampleWeights:一个在使用RPROP方法训练时才需要的数据,所以这里我们不设置,直接设置为Mat()即可。
sampleIdx:相当于一个遮罩,它指定哪些行的数据参与训练。如果设置为Mat(),则所有行都参与。
params:这个在刚才已经说过了,是训练相关的参数。
flag:它提供了3个可选项参数,用来指定数据处理的方式,我们可以用逻辑符号去组合它们。UPDATE_WEIGHTS指定用一定的算法去初始化权值矩阵而不是用随机的方法。NO_INPUT_SCALE和NO_OUTPUT_SCALE分别用于禁止输入与输出矩阵的归一化。
一切都准备好后,直接开始训练吧!
4.4. 识别
识别是通过Cv_ANN_MLP类提供的predict来实现的,知道原理的会明白,它实际上就是做了一次向前传播。
5. 车牌字符识别测试
1,我们需要读取所有的训练样本,将它们的路径在保存在vector<string>中。这里面我的车牌字符,因为1和I、0和O是一样的,所以数字加字母一共34类,其中每类有200个样本图像,共34*200个训练样本。
2,计算特征。我们按顺序读入图像,调用特征计算函数,把得到的结合保存在input对应的行中,同时把图像对应的预期输出保存在output中。
3,创建神经网络,这里我们计算得到的特征维数为48维,所以我们简单的设计一个3层的神经网络,输入层有48个结点,隐藏层也为48个结点,输出层为34个结点。然后神经网络的训练方法选用BACKPROP,迭代次数设置为5000次。
4,调用训练函数进行训练,并保存训练得到的权值矩阵,直接调用save成员函数即可。
nnetwork.save(“mlp.xml”);
5,识别测试,我们可以用单张图像进行测试,也可以选定一个测试集去进行测试,比如可以用一半的图像作为训练集,一半的图像作为测试集。这里我们可以加载已经训练好的权值矩阵,而不用重新训练,只要开始有保存了xml文件。但是记得你还是要创建一个网络后,才能加载进来。
6. 字符样本的下载
看到文章下的评论多是需求字符样本的,希望拿到字符样本的同学不要将其用于商业用途或者创建分享下载的链接。博文里用的样本是每类200张图像的测试样本,下面给出一份每类50个图像的样本子集,我以为用来做学术测试已经够了,出于公司利益考虑,请勿再向我索要完整样本。百度网盘:http://pan.baidu.com/s/1mgLUWBm
相关文章推荐
- 针对TQ部分ARM开发板中QTCPServer不能接受数据的问题
- 带上下界网络流小练(Bzoj2502&&Bzoj2055&&Bzoj3698)
- tcp状态
- Linux系统/网络 笔记
- 基于tensorflow的MNIST手写字识别(一)--白话卷积神经网络模型
- 20159313《网络攻击与防范》第四周学习总结
- [BZOJ1146][CTSC2008]网络管理Network
- HTTP请求响应协议
- MVC |Web API | HttpClent
- java发送http请求 自动预约MZD记念馆团体票 分析第一步自动登陆carles抓包
- 厦门巨游网络科技有限公司(HOTPOWER)承接游戏UI外包
- tcp编码还是要注意大端和小端问题
- [计算机网络]各种时延的计算
- 强制转https
- 计算机网络分层及其作用
- httclient使用socket发送请求
- httpasi缓存
- Java学习笔记(网络编程)
- 网络学习概要
- CentOS网络配置四个方式