EasyPR--开发详解(2)车牌定位
这篇文章是一个系列中的第三篇。前两篇的地址贴下:介绍、详解1。我撰写这系列文章的目的是:1、普及车牌识别中相关的技术与知识点;2、帮助开发者了解EasyPR的实现细节;3、增进沟通。
EasyPR的项目地址在这:GitHub。要想运行EasyPR的程序,首先必须配置好openCV,具体可以参照这篇文章。
在前两篇文章中,我们已经初步了解了EasyPR的大概内容,在本篇内容中我们开始深入EasyRP的程序细节。了解EasyPR是如何一步一步实现一个车牌的识别过程的。根据EasyPR的结构,我们把它分为六个部分,前三个部分统称为“Plate Detect”过程。主要目的是在一副图片中发现仅包含车牌的图块,以此提高整体识别的准确率与速度。这个过程非常重要,如果这步失败了,后面的字符识别过程就别想了。而“Plate Detect”过程中的三个部分又分别称之为“Plate Locate” ,“SVM train”,“Plate judge”,其中最重要的部分是第一步“Plate Locate”过程。本篇文章中就是主要介绍“Plate Locate”过程,并且回答以下三个问题:
1.此过程的作用是什么,为什么重要?
2.此过程是如何实现车牌定位这个功能的?
3.此过程中的细节是什么,如何进行调优?
1.“Plate Locate”的作用与重要性
在说明“Plate Locate”的作用与重要性之前,请看下面这两幅图片。

图1 两幅包含车牌的不同形式图片
左边的图片是作者训练的图片(作者大部分的训练与测试都是基于此类交通抓拍图片),右边的图片则是在百度图片中“车牌”获得(这个图片也可以称之为生活照片)。右边图片的问题是一个网友评论时问的。他说EasyPR在处理百度图片时的识别率不高。确实如此,由于工业与生活应用目的不同,拍摄的车牌的大小,角度,色泽,清晰度不一样。而对图像处理技术而言,一些算法对于图像的形式以及结构都有一定的要求或者假设。因此在一个场景下适应的算法并不适用其他场景。目前EasyPR所有的功能都是基于交通抓拍场景的图片制作的,因此也就导致了其无法处理生活场景中这些车牌照片。
那么是否可以用一致的“Plate Locate”过程中去处理它?答案是也许可以,但是很难,而且最后即便处理成功,效率也许也不尽如人意。我的推荐是:对于不同的场景要做不同的适配。尽管“Plate Locate”过程无法处理生活照片的定位,但是在后面的字符识别过程中两者是通用的。可以对EasyPR的“Plate Locate”做改造,同时仍然使用整体架构,这样或许可以处理。
有一点事实值得了解到是,在生产环境中,你所面对的图片形式是固定的,例如左边的图片。你可以根据特定的图片形式来调优你的车牌程序,使你的程序对这类图片足够健壮,效率也够高。在上线以后,也有很好的效果。但当图片形式调整时,就必须要调整你的算法了。在“Plate Locate”过程中,有一些参数可以调整。如果通过调整这些参数就可以使程序良好工作,那最好不过。当这些参数也不能够满足需求时,就需要完全修改EasyPR的实现代码,因此需要开发者了解EasyPR是如何实现plateLocate这一过程的。
在EasyPR中,“Plate Locate”过程被封装成了一个“CPlateLocate”类,通过“plate_locate.h”声明,在“plate_locate.cpp”中实现。
CPlateLocate包含三个方法以及数个变量。方法提供了车牌定位的主要功能,变量则提供了可定制的参数,有些参数对于车牌定位的效果有非常明显的影响,例如高斯模糊半径、Sobel算子的水平与垂直方向权值、闭操作的矩形宽度。CPlateLocate类的声明如下:
class CPlateLocate
{
public:
CPlateLocate(); //! 车牌定位
int plateLocate(Mat, vector<Mat>& ); //! 车牌的尺寸验证
bool verifySizes(RotatedRect mr); //! 结果车牌显示
Mat showResultMat(Mat src, Size rect_size, Point2f center); //! 设置与读取变量
//... protected:
//! 高斯模糊所用变量
int m_GaussianBlurSize; //! 连接操作所用变量
int m_MorphSizeWidth;
int m_MorphSizeHeight; //! verifySize所用变量
float m_error;
float m_aspect;
int m_verifyMin;
int m_verifyMax; //! 角度判断所用变量
int m_angle; //! 是否开启调试模式,0关闭,非0开启
int m_debug;
};
注意,所有EasyPR中的类都声明在命名空间easypr内,这里没有列出。CPlateLocate中最核心的方法是plateLocate方法。它的声明如下:
//! 车牌定位
int plateLocate(Mat, vector<Mat>& );
方法有两个参数,第一个参数代表输入的源图像,第二个参数是输出数组,代表所有检索到的车牌图块。返回值为int型,0代表成功,其他代表失败。plateLocate内部是如何实现的,让我们再深入下看看。
2.“Plate Locate”的实现过程
plateLocate过程基本参考了taotao1233的博客的处理流程,但略有不同。
plateLocate的总体识别思路是:如果我们的车牌没有大的旋转或变形,那么其中必然包括很多垂直边缘(这些垂直边缘往往缘由车牌中的字符),如果能够找到一个包含很多垂直边缘的矩形块,那么有很大的可能性它就是车牌。
依照这个思路我们可以设计一个车牌定位的流程。设计好后,再根据实际效果进行调优。下面的流程是经过多次调整与尝试后得出的,包含了数月来作者针对测试图片集的一个最佳过程(这个流程并不一定适用所有情况)。plateLocate的实现代码在这里不贴了,Git上有所有源码。plateLocate主要处理流程图如下:

图2 plateLocate流程图
下面会一步一步参照上面的流程图,给出每个步骤的中间临时图片。这些图片可以在1.01版的CPlateLocate中设置如下代码开启调试模式。
CPlateLocate plate;
plate.setDebug();
临时图片会生成在tmp文件夹下。对多个车牌图片处理的结果仅会保留最后一个车牌图片的临时图片。
1、原始图片。

2、经过高斯模糊后的图片。经过这步处理,可以看出图像变的模糊了。这步的作用是为接下来的Sobel算子去除干扰的噪声。

3、将图像进行灰度化。这个步骤是一个分水岭,意味着后面的所有操作都不能基于色彩信息了。此步骤是利是弊,后面再做分析。

4、对图像进行Sobel运算,得到的是图像的一阶水平方向导数。这步过后,车牌被明显的区分出来。

5、对图像进行二值化。将灰度图像(每个像素点有256个取值可能)转化为二值图像(每个像素点仅有1和0两个取值可能)。

6、使用闭操作。对图像进行闭操作以后,可以看到车牌区域被连接成一个矩形装的区域。

7、求轮廓。求出图中所有的轮廓。这个算法会把全图的轮廓都计算出来,因此要进行筛选。

8、筛选。对轮廓求最小外接矩形,然后验证,不满足条件的淘汰。经过这步,仅仅只有六个黄色边框的矩形通过了筛选。

8、角度判断与旋转。把倾斜角度大于阈值(如正负30度)的矩形舍弃。左边第一、二、四个矩形被舍弃了。余下的矩形进行微小的旋转,使其水平。

10、统一尺寸。上步得到的图块尺寸是不一样的。为了进入机器学习模型,需要统一尺寸。统一尺寸的标准宽度是136,长度是36。这个标准是对千个测试车牌平均后得出的通用值。下图为最终的三个候选”车牌“图块。

这些“车牌”有两个作用:一、积累下来作为支持向量机(SVM)模型的训练集,以此训练出一个车牌判断模型;二、在实际的车牌检测过程中,将这些候选“车牌”交由训练好的车牌判断模型进行判断。如果车牌判断模型认为这是车牌的话就进入下一步即字符识别过程,如果不是,则舍弃。
3.“Plate Locate”的深入讨论与调优策略
好了,说了这么多,读者想必对整个“Plate Locate”过程已经有了一个完整的认识。那么让我们一步步审核一下处理流程中的每一个步骤。回答下面三个问题:这个步骤的作用是什么?省略这步或者替换这步可不可以?这个步骤中是否有参数可以调优的?通过这几个问题可以帮助我们更好的理解车牌定位功能,并且便于自己做修改、定制。
由于篇幅关系,下面的深入讨论放在下期。
版权说明:
本文中的所有文字,图片,代码的版权都是属于作者和博客园共同所有。欢迎转载,但是务必注明作者与引用来源。任何未经允许的剽窃以及爬虫抓取都属于侵权,作者和博客园保留所有权利。
参考文献:
1.http://my.phirobot.com/blog/2014-02-opencv_configuration_in_vs.html
2.http://blog.csdn.net/jinshengtao/article/details/17883075
3.http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
4.http://blog.csdn.net/xiaowei_cqu/article/details/7829481
EasyPR--开发详解(2)车牌定位的更多相关文章
- EasyPR--开发详解(6)SVM开发详解
在前面的几篇文章中,我们介绍了EasyPR中车牌定位模块的相关内容.本文开始分析车牌定位模块后续步骤的车牌判断模块.车牌判断模块是EasyPR中的基于机器学习模型的一个模块,这个模型就是作者前文中从机 ...
- iOS原生地图开发详解
在上一篇博客中:http://my.oschina.net/u/2340880/blog/414760.对iOS中的定位服务进行了详细的介绍与参数说明,在开发中,地位服务往往与地图框架结合使用,这篇博 ...
- wpf 客户端【JDAgent桌面助手】开发详解(四) popup控件的win8.0的bug
目录区域: 业余开发的wpf 客户端终于完工了..晒晒截图 wpf 客户端[JDAgent桌面助手]开发详解-开篇 wpf 客户端[JDAgent桌面助手]详解(一)主窗口 圆形菜单... wpf 客 ...
- iOS应用开发详解
<iOS应用开发详解> 基本信息 作者: 郭宏志 出版社:电子工业出版社 ISBN:9787121207075 上架时间:2013-6-28 出版日期:2013 年7月 开本:16开 ...
- 基于H5的微信支付开发详解
这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...
- ****基于H5的微信支付开发详解[转]
这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...
- 【转发】NPAPI开发详解,Windows版
NPAPI开发详解,Windows版 9 jiaofeng601, +479 9人支持,来自Meteor.猪爪.hanyuxinting更多 .是非黑白 .Yuan Xulei.hyolin.Andy ...
- 热烈祝贺华清远见《ARM处理器开发详解》第2版正式出版
2014年6月,由华清远见研发中心组织多名业 内顶尖讲师编写的<ARM处理器开发详解>一书正式出版.本书以S5PV210处理器为平台,详细介绍了嵌入式系统开发的各个主要环节,并注重实践,辅 ...
- 嵌入式Linux应用程序开发详解------(创建守护进程)
嵌入式Linux应用程序开发详解 华清远见 本文只是阅读文摘. 创建一个守护进程的步骤: 1.创建一个子进程,然后退出父进程: 2.在子进程中使用创建新会话---setsid(): 3.改变当前工作目 ...
- PayPal 开发详解(七):运行REST API SAMPLE
1.编译成功,修改配置文件 sdk_config.properties ,使用我们申请的测试帐号执行收款测试,clientId 和 clientSecret 参见 PayPal 开发详解(五) 2.将 ...
随机推荐
- POJ 2991–Crane【线段树+几何】
题意: 把手臂都各自看成一个向量,则机械手的位置正好是手臂向量之和.旋转某个关节,其实就是把关节到机械手之间的手臂向量统统旋转. 由于手臂很多,要每个向量做相同的旋转操作很费时间.这时就可以想到用线段 ...
- Redis 数据库入门指南
Redis 是一个开源数据库,它使用内存数据结构存储,可作为数据库.缓存和消息代理使用.Redis 支持丰富的数据结构,有:字符串(Strings).哈希(Hashs).列表(Lists).集合(Se ...
- 【转】Oracle执行计划解释
Oracle执行计划解释 一.相关的概念 Rowid的概念:rowid是一个伪列,既然是伪列,那么这个列就不是用户定义,而是系统自己给加上的. 对每个表都有一个rowid的伪列,但是表中并不物 ...
- POJ 1979 题解
Red and Black Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 31722 Accepted: 17298 D ...
- Android 学习笔记之一 “Unable to establish loopback connection”
今天碰到一个错误:Unable to establish loopback connection,在网上找各种方法都解决不了,后来看一个帖子说是要关闭系统防火墙,尝试了下还是不行.最后是进任务管理器杀 ...
- XDocument获取指定节点
string xmlFile = @"D:\Documents\Visual Studio 2013\Projects\Jesee.Web.Test\ConsoleApplication1\ ...
- [Android] Shape背景制作半圆或半边框
实现原理使用layer-list对shape进行叠加显示. 直接上代码: <layer-list xmlns:android="http://schemas.android.com/a ...
- nodejs 单元测试
之前项目开发因为改进度,基本都是粗放式开发.为了提高代码质量,单元测试是必不可少的. 针对restful api ,用supertest 测试框架.针对nodejs,引入mocha 和should 可 ...
- debian下使用Sphinx异常“Could not import extension sphinx.builders.linkcheck (exception: cannot import name SSLError)”的解决
最近使用到Sphinx编译文档,出现如下异常: Extension error:Could not import extension sphinx.builders.linkcheck (except ...
- java分享第十五天(log4j 格式详解)
log4j 格式详解 log4j.rootLogger=日志级别,appender1, appender2, -. 日志级别:ALL<DEBUG<INFO<WARN<ERRO ...