车牌识别采购、研发纵览

文章来源 —— 绿睿科技: 车牌识别 雕刻机 三维网页

车牌识别采购、研发纵览

车牌识别采购、研发纵览

《车牌识别采购、研发纵览》是目前最详细的关于车牌识别的资料。本书分两部分:

第一编,介绍车牌识别的技术知识,包括目前我国主要的车牌识别产品名单、车牌识别产品必备/附加的功能,以及车牌识别的应用范围;

第二编,介绍车牌识别的研发知识,其中包括,车牌识别程序的模块、车牌识别程序内核模块的各种类型以及各个子模块的详细算法。

第一编对于广大车牌识别采购人员十分重要;对于广大车牌识别开发人员,要在熟悉了解第一编的基础之上,研读第二编。

第1编 采购

这是《车牌识别采购、研发纵览》的前半部分,是广大车牌识别采购者的必读部分。对于车牌识别研发人员来说也是有很大的参考价值,而且对后面的开发有极大的帮助。

第1章 车牌识别供应商

通过本章,采购人员可以对我国的车牌识别技术水平有一个概括性的认识;研发人员也应该能够了解到这一技术目前的成熟程度。

第1节 车牌识别供应商列表

车牌识别并没有统一的国际标准。本章仅仅列举我国的车牌识别供应商。(因为车牌识别市场比较热门,下面的表格难免遗漏一些新的成员)

名称 网址 备注
绿睿(推荐) www.voicing.cn 高识别率,速度快
SoftWell www.szsoftwell.com 较高识别率,速度慢
PlateDSP www.platedsp.com 识别率较高,速度快
CubicPlate www.cubicimage.com 普及较广,识别率,速度都是中游水平
SupPlate www.dragonskytech.com 速度都是中游水平
汉王 www.hanwang.com.cn 无法拿到试用软件
车牌识别供应商 列表

第2节 车牌识别供应商举例——绿睿科技

车牌识别属于知识密集型产业。研发车牌识别需要大量的高级软件人才。绿睿科技公司正是一家拥有大量软件人才的公司。她座落于我国的硅谷——北京中关村。“爱国,勤奋踏实,艰苦创业”是该公司的主题。绿睿公司希望能和合作伙伴一起,实现我国的产业升级和结构性调整,提升合作伙伴产品的附加值。让更多的国内公司积极参与世界经济产业链条中,上游的竞争。

绿睿科技以研发为主,而以市场推广为辅;绿睿集中精力提高产品质量,而将更多利润让给合作伙伴。

绿睿科技全体同仁艰苦创业,于2009年推出车牌识别这一智能交通领域产品。绿睿拥有该产品的核心技术和独立的知识产权,而且不断地对产品进行更新换代。

有关绿睿科技更详细的资料请登陆该公司官方网站:www.voicing.cn。以下是该公司的标示:

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第2章 车牌识别的应用

车牌识别主要用于智能交通领域。随着计算机软硬件的不断升级,车牌识别所依赖的环境日臻完善,车牌识别的功能越来越丰富,应用场合也越来越多。

第1节 车牌识别应用列表

用途 描述
停车场管理 对持用相同的RFID的车辆,检查车牌是否相同。智能停车场对车牌识别的要求主要集中在准确度方面,对时间要求不是很苛刻。
车辆稽查 治安卡口 在城市的交通要道,架设“电子眼”,及时获取“肇事逃逸”车辆地理信息。对车牌识别准确度和速度都有较高要求。另外整个系统应该有强大的数据支持,保存历史资料。
高速公路收费 目前很多高速公路是“贷款筑路,收费还钱”。联网收费时,需要通过车牌识别系统计算汽车高速公路里程。
移动稽查 官方为打击走私、偷税、违禁等的非法活动,对疑犯车辆进行跟踪。用车牌识别系统快速检查过往车辆。
地磅称重管理 用于库存管理。
交通信息采集 对卡口车辆进行统计,依靠车牌识别对过往车辆计数。获得车流密度随时间变化的关系。
路桥、隧道收费 类似高速公路,实现过往车辆自动收费。同时记录车辆过往时的照片,方便收费系统核实。
重要机关单位汽车出入口管理 重要机关单位(比如驻军部队)管理出入车辆。要求车牌识别系统能够识别军用车牌。
闯红灯记录 车牌识别系统实时接收红灯信号,根据路口逻辑计算车道上是否允许通过车辆,对违规车辆进行记录,并自动提交罚单。
城市交通管理 配合指纹识别,人脸识别对城市交通进行管理。比如限制超载,或者记录车内乘客过少(为了保护环境,轿车内最好有三个以上的人)情况。
车牌识别应用列表 列表

第2节 车牌识别应用举例——智能停车场

智能停车场是车牌识别的典型应用。利用智能停车场系统公司、企业、机关等对车辆可以进行方便的管理;智能停车场系统还有助于提高单位形象,加强内部管理。

智能停车场系统包括,RFID卡、读卡器、道闸、感应线圈、视频系统、MIS系统和车牌识别模块。其中视频系统包括摄像机,视频传输电缆,视频显示终端。停车场一般有多个出入口。所有出入口都配置有联网的计算机,组成MIS系统,负责对车辆数据的记录和处理。出入口同时都配置,车牌识别设备,对进出车辆信息进行采集工作。

当车辆进入停车场时,司机必须刷RFID卡。智能停车场系统根据RFID卡信息对车辆的合法性进行判断,并允许合法车辆通过道闸进入停车场。同时,智能停车场系统记录车辆进入时的视频信息。

当车辆离开停车场时,司机也必须刷RFID卡。根据RFID卡信息,系统找到该车进入停车场的时间点;并计算停车时间长度,提供收费依据。

为了防止不法分子的破坏,智能停车场系统要根据数据库信息,进行RFID卡信息和车牌信息的比对。一旦发现RFID卡信息和车牌信息不匹配,立即报警。所以智能停车场系统必须集成车牌识别模块。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第3章 配套产品

车牌识别作为一项核心技术必须结合其他技术才能被广泛应用。同时资优价廉的车牌识别软件必然会提高相关产品的销售量,其他产品因此实现高附加值。

第1节 照明光源

目前来说,照明光源普遍采用电光源(把电能转换成光能)。因为车牌识别系统本身也消耗电能,所以车牌识别的照明光源全部采用电光源。从发光原理上讲,点光源一般分为以下三大类。

热辐射光源 利用电流的热效应。让光源达到三千度以上的温度。光源便开始发出可见光。热辐射光源通常色温较低,比如我们平常见到黄色光源。性能优良的车牌识别系统不会受此影响。

气体放电发光 这类光源是利用气体在通过电流时发光的原理制成的。某些光源色彩丰富,但是并不适合车牌识别。荧光灯使用的是水银蒸气发光,虽然发出白光,但是光线分散,不容易投射到车牌上。也不是夜间车牌识别理想光源。

半导体光源 在电场作用下半导体p-n节发光,电能利用效率高,是近年来新开发的光源类型。可以采用高功率白色的半导体光源,同时也方便将光束投射到车牌上。是夜间车牌识别的理想光源。

第2节 信息系统

信息系统,全称为管理信息系统—Management Information System,亦即所谓的MIS系统。

MIS系统主要指惊醒日常事务操作的系统。这种系统对各种事件的属性进行记录,并且可以输出统计信息。

MIS系统的核心是CS(也就是所谓的客户端/服务器 client/server)结构,也有基于BS结构的MIS系统,但是CS的MIS系统足以满足车牌的需要,所以BS的车牌识别系统并不多见。下图为一电力系统的MIS系统:

需要指出的是,MIS系统和车牌识别同为软件。在整个车牌识别系统中互相配合工作。一般来说,MIS系统理论较为成熟,开发难度不大;而车牌系统理论并没有完全成熟,开发难度极大。但是MIS系统必须针对单个项目单独开发,不容易复制。这就大大提高了MIS系统本身的成本,通常情况下MIS系统要比车牌识别核心模块报价高。因为车牌识别软件较容易复制,从而分担成本。

第3节 相机

车牌识别只能用数码相机,不可以使用传统的模拟相机。数码相机利用感光电子元件把光学信号转换成数字图像信号。感光元件有两种CCD和CMOS。CCD相机质优价高,对车牌识别来说没有必要。如果是对于普通的车牌识别系统,CMOS相机足以满足要求。

相机种类很多,具体到车牌识别相机也有很多种。这里列举一下适合车牌识别使用的相机。

工业相机:性能较好,它速度快,清晰度高。有的借助图像采集卡可以得到更好的效果。适合条件比较恶劣的环境。

监视摄像头:这是目前普及最广的用于车牌识别的相机。产品技术都比较成熟。架设车牌识别系统时完全可以利用一有的监视系统。对原有系统进行升级。

QQ摄像头:根据摩尔定律,电子产品——QQ摄像头的性能不断提高,价格不断下降。目前的QQ摄像头性能已经达到或者超过普通监视摄像头的性能水平;而价格十分便宜。将来可能成为车牌识别相机的首选。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第4节 视频传输

视频传输设备主要分为模拟传输和数字传输两种形式。

虽然数字传输方式具有很多优点。但是模拟技术比较成熟,产品种类多,所以模拟传输也比较普及。模拟视频信号,到达计算机前转换成数字信号即可进行车牌识别。

数字信号普遍采用以太网传输,使用超五类线。其传输速率高大1000兆,传输距离远达100米完全可以满足车牌识别的需要。数字视频信号经过压缩后,可以节省带宽,不过这对相机有一定的要求。目前车牌识别系统中的视频信号很少压缩。

另外在特殊场合下,并不需要传输视频,而仅仅需要传输单帧图像即可。比如交通路口,闯红灯的汽车触发相机拍照,相机仅把这时抓拍的图片传至计算机即可,大大节省了带宽。同时这样方法也适合停车场。

第5节 RFID

RFID的英文全称是Radio Frequency Identification。中文名称:射频识别、射频标示,俗称电子标签。RFID最大的特点就是非接触式自动识别。这一过程是通过射频信号完成的。

当RFID卡进入读卡器识别范围时,读卡器会发出射频信号。这时RFID卡就会感应出电流,RFID芯片利用感应出的电流提供能量,也发出射频信号,这个信号加载有标示信息。读卡器捕获到RFID卡发出的射频信号,即可得到RFID卡的ID值。

RFID被广泛应用于停车场和高速路收费系统中。为了更加安全的使用RFID,经常需要把RFID卡的ID值和汽车车牌号绑定起来。这就需要整个系统中集成车牌识别模块。

第4章 软件接口

车牌识别做为一个软件模块,需要提供软件接口,才能够被整合到整个车牌识别系统中,正常工作。

车牌识别适合何种软件接口,下面将一一介绍:

第1节 DLL

DLL的全称是Dynamic Linkable Library,中文名称是动态链接库。他不能单独的运行,需要其它程序加载。DLL最大的优点是应用程序共享代码和其他只读资源,有效地节省系统开支。

更为重要的是DLL迎合了程序的模块思想。所谓的模块就是一个功能相对完整的软件“零件”。一台机器的零部件可能来自于不同的生产厂家;同样的道理,车牌识别应用系统中,车牌识别模块可以由其它厂家提供。

车牌识别系统中,相机驱动程序本质上也是一个动态连接库。

除了windows系统外,linux系统也有类似的思想,不过叫做elf。其中的字母l标示连接的意思。同样地,车牌识别的动态库也可以提供linux的版本。

第2节 ActiveX

ActiveX的本质也是上一节中提到的动态链接库。不过ActiveX的接口更为方便。AcitveX由开发人员事先打包,可以方便的嵌入包括浏览器的各种软件之中。很多语言包括Java都支持ActiveX控件。

ActiveX没有很好的跨平台性,目前仅仅能在windows上运行。虽然如此,但是考虑车牌系统目前也都是在windows系列操作系统上运行,所以车牌识别模块封装成ActiveX控件的优越性也不会打折扣。

另外网页上的ActiveX有一定的安全问题,但是这并不会影响到车牌识别系统的安全性。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第3节 COM

和ActiveX控件一样,COM的本质也是动态链接库,COM也是有一种共享代码的方法。有了COM,软件工程就可以像是搭积木一样进行,甚至普通人都可以编程序。

对COM的调用者来说,他们看到的每个COM是一个类,类有接口。类和接口都是用GUID标示的。这里的GUID本质上是一个全球唯一的数,任何编程语言都可以处理。

但是目前车牌识别模块,提供COM借口得并不是很多。原因在于COM技术已经过时,微软已经放弃了对COM的维护工作。COM也不如ActiveX控件来得方便。

COM同样也只能用到Windows系列操作系统上。

第5章 触发

车牌识别系统,最简单的流程是系统从相机取出图像,然后进行识别。如果相机视野内有车牌,那么系统记录当前的图像和车牌号。如果视野内没有车牌,则要丢弃当前的图像。

但是如果计算机对图像处理较慢,那么当计算机正处理当前图像的时候,下一幅图像已经准备好了。这样的话,计算机就无法响应用户的操作。用户就会感觉计算机较慢,或者死机。

解决的方法就是利用“触发技术”。

第1节 视频触发

本章一开始提到的车牌系统的最简单的流程,就是视频触发。根据视频信号,如果相机视野内有车牌,整个系统启动一个操作。如果相机视野内没有车牌,整个系统处于休眠状态。

如果车牌识别模块的运算速度较快,视频触发一般没有大的问题。但是较快的速度,势必影响识别率。低识别率是视频触发固有的缺点,虽然随着硬件速度的提高,这个缺点变得越来越小。

为了弥补视频触发的不足,人们引入了“线圈触发”的概念。

第2节 线圈触发

当有汽车功过道闸的时候,汽车会触发感应线圈。接下来,感应线圈触发相机拍照。然后图片传送到计算机,计算机对图像进行识别。最后系统记录识别信息和图像信息。在没有图像到来的时候,整个系统处于休眠状态。计算机也没有必要识别车牌,这个时候计算机的任务较少,可以很好的响应用户操作。

对车牌识别软件来说,识别时间限制被大大放宽。可以更为准确的定位识别车牌。所以一般线圈触发的系统,车牌识别率都很高。

线圈触发被广泛应用于停车场和交通路口环境中。

在施工过程中,线圈的铺设可能会有一定的额外工作量。相对于视频触发的系统,这一工作显然是多余的。这是线圈触发系统的一个缺点。

第3节 RFID触发

当汽车通过道闸的时候,用户需要主动刷RFID卡。刷卡机读取用户RFID卡信息后,触发相机拍照。接下来,照片被传送到计算机,进行车牌识别操作。这便是RFID触发的工作流程。

显然,这种触发方式拥有和线圈触发相同的识别率。但却无法应用于交通路口。RFID卡触发实际上受到RFID卡普及程度的限制。

也有上述多种触发技术结合的方案。比如视频触发和线圈触发相结合,这样既能满足系统在无法埋设感应线圈场合下的应用,又能在有感应线圈的环境中提高识别率。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第6章 车牌识别必备功能

第1节 基础功能

车牌定位

车牌定位是车牌识别的基础。也是车牌识别过程中最重要的部分。车牌定位的成功率直接决定车牌识别率。当光线环境比较好、分辨率较大的时候,车牌定位比较容易;但是如果光线环境不好,分辨率较低,车牌定位就比较困难。另外还有很多因素影响车牌定位的成功率,比如图像因观察角度造成的旋转、拉伸和斜切;再比如车牌遭到污染。上述情况都会影响车牌成功定位。

如果增加车牌定位的容忍值,虽然会提高车牌定位的成功率,但是会出现错误定位的情况:把背景图像的一部分,当作车牌。当图像内没有车牌时,质量不好的车牌识别软件比较容易出现这种错误。

字符识别

字符识别功能包括识别汉字、英文字母和阿拉伯数字。汉字的范围一般来说仅仅包括省、自治区和直辖市的简称。在所有的英文字母中,I和O,分别不容易和1和0区分。但是字母I和O可以做为发证机关代号,在车牌中出现,因为发证机关代号不可以取数字1和0。

0和D或者Q无法区分是字符识别经常出现的错误。8和B对于质量较差的车牌识别软件成功区分的概率也很小。

在同一地区,大部分车牌的省、自治区和直辖市的简称都是相同的,所以相对于字母数字的识别率,汉字的识别率不是很重要,另一方面汉字识别技术也不是很成熟;有的车牌识别软件干脆没有汉字识别功能。

第2节 拓展功能

多车牌识别

在同一副图像中有两个或者两个以上的车牌。多车牌识别软件可以对这些车牌全部成功识别。相对地,有些车牌识别软件只能对其中之一进行定位识别,有的是根据车牌距离中心点的距离选择,有的根据车牌在图像中的大小选择,有的甚至是随机选择。

车牌精确定位

在环境比较好的情况下,有时车牌识别软件无法正确识别字符。原因在于车牌本身受到一些干扰,其中包括固定螺丝和车牌边框。

对于蓝色车牌,较新的固定螺丝会反射光线;在图像中,螺丝呈现白色和字符颜色相近,干扰正常的识别程序。对于黄色车牌,比较旧的螺丝,或者悬空的螺丝孔,同样也会干扰正常的识别。

标准尺寸的车牌,车牌边框不会对车牌识别进行干扰。但是实际上,车牌并不都是按统一的标准制作的。有些车牌把边框向有文字的方向移动,腾出的空间用于标示汽车的品牌。但是这些非标准尺寸的车牌却给车牌定位带来了一定的干扰。

所以质量好的车牌识别软件,要对车牌进行精确定位,排除各种干扰。

国家标准

车牌识别依据的是《GA36-2007中华人民共和国机动车号牌》,互联网上有可供下载的pdf版本。

第2编 研发

以下部分为车牌识别研发人员参考资料。

第1章 开发环境

车牌识别实质上包括两部分的内容,一是车牌定位,二是字符识别。

车牌定位主要的工作是图像处理。目前来说图像处理的开发软件环境局限于c/c++。因为c/c++效率高,执行速度快。字符识别主要是人工智能。人工智能的开发环境较多,但是都不成熟。其中Prolog是目前比较好的人工智能语言之一。当考虑到统一开发环境时,一般字符识别也使用c/c++。

车牌识别硬件环境的选择比较丰富。除了选择主流的Intel和Amd的机器,高性能AMR机的也是比较好的选项。如果要嵌入到相机之中,AMR机是最好的选择。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第1节 软件环境

c c++的开发环境

c/c++语言是一种中级语言,它既有高级语言的简单性,又有和低级语言的相近的高效率。c/c++语言的高级语言特性,使得其描述车牌识别中比较复杂的逻辑较为方便。而其低级语言的特性,使得用c/c++语言开发的车牌识别程序执行速度快,内存开销小。

c/c++语言也十分容易移植,车牌识别的核心程序,在Windows系列操作系统上调试通过后,很容易移植到Linux系列操作系统上,而Linux系列操作系统也可以是在Arm机上运行的。

c是面向结构的,c++是面向对象的。这使得c/c++方便描述复杂的数据结构和算法。适合车牌识别中的字符识别操作。

c/c++语言的资料丰富,技术成熟。网上图像处理方面的程序较多是用c/c++编写,很容易把它们放到自我开的车牌识别程序中去。

c/c++开发环境也比较好,vc支持可视化编程,调试时变量跟踪异常方便,将c/c++不稳定性降到最低。

最为重要的是多数车牌识别程序都是基于c/c++的。

人工智能语言——Prolog

Prolog是目前为止中为重要的人工智能语言之一。他的语法中含有谓词,跟自然语言极为相似。使用Prolog描述完规则和事实后,Prolog内部进行演绎推理,自动给出结果;无需程序员关心内部操作。这样能够就大大加速了车牌识别的研发进程。

Prolog中的事实,用来描述对象和对象之间的关系。事实由谓词和对象组成。比如 Close(current_character,2). 表示当前识别的字符有两个封闭区域(车牌识别中“B”和“8”中的情况)。

Prolog中的规则由多个相关的简单句子组成。规则中结论放在前面,条件放在后面。例如:Q(character):-Anisomerous(character),Close(character,1). 表示如果字符只有一个封闭区域,而其不对称的话,那么这个字符是“Q”。

Prolog中的目标可以在事实和规则提交之后自动得到。

Prolog拥有和c语言的接口,Prolog可以融入c/c++的工程中。方便将整个车牌程序整合在一起。

Matlab

使用Matlab开发车牌识别比较快,但是最后发行软件的时候不容易脱离开Malab的环境。可以用Matlab研究车牌识别算法,但是开发车牌识别Malab并不是首选。

第2节 硬件环境

英特尔奔腾及其兼容机

因为车牌识别需要大量的并行计算,所以多核的CPU,占优势。如果不是通过系统,而是车牌识别软件本身分配给各个核心任务,效率会更高。

设计较好的车牌识别系统占用内存并不大,只有几兆。目前CPU Cache完全可以满足要求,整个识别过程,CPU不需要跟内存通信。

超线程技术也有助于车牌识别速度的提高。因为车牌识别程序并行计算的计算量较大,超线程技术也是针对有大量并行计算的软件设计的。

英特尔和AMD,都推出了64位的CPU,这一点对车牌识别可能并没有多大的帮助。

浮点计算对车牌识别软件的意义不大,因为浮点计算比较慢,设计良好的车牌识别软件,尽量使用整型运算。

从环保角度出发,CPU的功率越小越好。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览
arm机

Arm机是典型的精简指令系统。执行速度快,也是车牌识别的一个不错的硬件环境。

按性价比计算Arm机要比奔腾机好。如果算上周边芯片组成计算机系统,Arm机更占据成本优势。

Arm机基于Linux操作系统,车牌识别产品不会包含Windows的版本费用。Windows下面也有良好的Arm机调试环境。更可以移植已经在Windows环境下调试成功的软件。

同样地,64位的Arm机对车牌识别软件没有很大的帮助。

Arm机市面上较少,不容易购买,这是其一大缺点。

第2章 整体结构

第1节 整体结构分类

2.2.1.1是否回溯

举例来说,根据车牌的特征在整个图片中定位车牌的时候,如果车牌在图像中受到了环境的干扰,可能无法找到图片。为了解决这个问题,引用了回溯算法:当无法定位车牌的时候,增加对车牌错误的容忍程度,从新去寻找车牌。

有无回溯算法,对车牌识别的性能影响重大。无回溯算法的车牌识别软件速度快,但是定位成功率不高。适合视频触发的应用。有回溯算法的车牌识别软件定位成功率高,但是速度较慢。有时在成功定位车牌后,经过字符识别,发现字符识别率较低,重新定位车牌。这样速度便会更慢。有回溯算法的车牌识别软件一般应用于有触发线圈的场合。

2.2.1.2试探和计算

车牌识别中的定位操作,首先有一个判断某一区域是不是车牌的标准,然后对所有可能的区域依次根据这个标准判断。算法完成时,符合标准的区域便是车牌的位置。这是最原始的思路。这个算法在时间上并不占优势,但是这是车牌定位的基础,改进后的程序仍然沿用这个算法的绝大多数的函数。

上述算法,对所有的区域进行试探。在试探之前没有做计算,判断有没有必要对当前区域和标准进行比较。

另外一种算法就是“暴力”算法的改进形式。尽量避免没有必要的试探。或者根据已经试探失败的结果,去否定某一个较大区域试探的必要性。

2.2.1.3开发流程

实际上车牌识别代码量并不是很大,如果不停的手工输入;用不到一天的时间,即可大功告成。但是程序需要反复调试,才可以走向成熟。所以工作量是很大的。

另外车牌识别还有其本身的特点——理论并不成熟。这就给车牌识别带来了更多的工作量。一般来说,开发车牌识别程序,先按照最原始最朴素的思想编码,然后是不断地优化。这将贯彻到整个车牌识别的开发过程中去。

第2节 必备模块

车牌识别最基本的流程是:将采集后的图像二值化,然后依次经过车牌定位、字符分割、去除干扰,最后是字符识别。有时还会加入本节前面部分所叙述的思想(比如回溯)。

下面将分五章具体介绍每一个模块。

第3章 二值化

二值化是车牌识别的第一步。二值化前后的对比如图:

二值化的算法很简单,首先有一个亮度的阈值(threshold),对每一个像素的亮度和这个阈值做比较,根据比较结果得出车牌的前景和背景。用c/c++描述如下:

void CLPR::Binary(int threshold)
{int y;for(y=0;y<m_height;y+++){int x;for(x=0;x<m_width;x++){unsigned char red,green,blue;GetPixel(red,green,blue,x,y);int bright;bright=red+green;if(m_search_blue_plate){if(bright<=threshold)SetBinary(x,y,BACKGROUND);elseSetBinary(x,y,FOREGOUND);}else //we are searching yellow plate{if(bright>=threshold)SetBinary(x,y,FOREGOUND);elseSetBinary(x,y,BACKGROUND);}}}
}

二值化算法虽然简单,但是阈值却不容易寻找。本章后面的部分,将重点介绍各种求解阈值的算法。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第1节 OTSU

OTSU算法的思想是:把输入图像首先转换成灰度图象,然后对图像进行直方图分析。如果直方图呈双峰分布。那么双峰之间的“谷”就是阈值。从统计学角度讲,阈值两边的距离最大。

由于车牌识别的特殊性,图象象素点的亮度为该象素点的红色分量和绿色分量的和,并且忽略蓝色分量。这一点对蓝色车牌和黄色车牌都是适用的。

OTSU算法仅对直方图呈双峰分布的图像有效。

全部代码如下:

void LPR::OTSU()
{//直方图统计{int index;for(index=0;index<m_bright_level_count;index++)m_pixel_number[index]=0;}{int y;for(y=0;y<=m_height;y++){int x;for(x=0;x<=m_width;x++){int bright;bright=Bright(x,y);m_pixel_number[bright]++;}}}//真正求阈值double sum;sum=0;int n;n=0;int k;for(k=0;k<=(m_bright_level_count-1);k++){sum+=k*m_pixel_number[k];n+=m_pixel_number[k];}double c_sum;c_sum=0.0;double f_max;f_max=-1.0;int n1;n1=0;for(k=0;k<(m_bright_level_count-1);k++){n1+=m_pixel_number[k];if (n1==0) continue;int n2;n2=n-n1;if(n2==0) break;c_sum+=(double)k*m_pixel_number[k];double m_1,m_2;m_1=c_sum/n1;m_2=(sum-c_sum)/n2;double sb;sb=(m_1-m_2)*(m_1-m_2)*(double)n1*(double)n2;if (f_max<sb){f_max=sb;m_prepare_threhold=(int)(k+0.5);}}
}

第2节 Matlab算法

使用Matlab进行车牌识别,也是一个比较好的选择。在Matlab的环境中首先把输入的彩色图像使用命令rgb2gray转换成灰度图像。有了灰度图像就可以使用命令graythresh获得阈值了。最后使用命令im2bw对图像进行二值化。十分方便!代码如下:

I=imread('blood1.tif');

imhist(I);

% 人工观察灰度直方图,发现灰度120处有谷,确定阈值T=120

I1=im2bw(I,120/255);

% im2bw函数需要将灰度值转换到[0,1]范围内

figure,imshow(I1);

改进为

I=imread('blood1.tif');

imhist(I);

I1=graythresh(I);

% im2bw函数需要将灰度值转换到[0,1]范围内

figure,imshow(I1);

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第4章 车牌定位

图像二值化,占用车牌识别中的大部分时间。在二值化之后,车牌识别将变得比较容易。

车牌定位为二值化后的第一步。下面分小节分别介绍各种车牌定位算法。

第1节 角点定位方法

车牌识别过程中,角点定位的基本思想是:

在所有的边界点中,如果某些点的曲率半径比较小,那么这些点叫做“角点”:如下图所示(角点用红点表示):

图中字符上和车牌的四角都有角点。但是这并不影响车牌的定位。

根据距离最大的四个角点,得到了车牌的四个角,从而定了车牌。从角点定位的原理看出,如果经过旋转后车牌并不会影响角点定位的成功率和速度。

该算法的实现可以采取遍历匹配的算法,实现如下:

void LPR::GetConere()
{int y;for(y=0;y<m_height;y++){int x;for(x=0;x<m_width;x++){if(Line(x,y,x+4,y)>=3){if(Line(x,y,x,y+4)>=3){if(Line(x+1,y+1,x+4,y+4)<=1)Add(x,y,LEFT_TOP_CONNER);}if(Line(x,y,x,y-4)>=3){if(Line(x+1,y-1,x+4,y-4)<=1)Add(x,y,LEFT_DOWN_CONNER);}}if(Line(x,y,x-4,y)>=3){if(Line(x,y,x,y+4)>=3){if(Line(x-1,y+1,x-4,y+4)<=1)Add(x,y,RIGHT_TOP_CONNER);}if(Line(x,y,x,y-4)>=3){if(Line(x-1,y-1,x-4,y-4)<=1)Add(x,y,RIGHT_DOWN_CONNER);}}}}
}

函数Line(x1,y1,x2,y2)返回过两点(x1,y1),(x2,y2)的直线,前景的象素个数。

注意这里的4,是检验角点的区域范围,如果区域过大,图像旋转时就会影响车牌定位的成功率。

第2节 上下定位方法

仔细观察二值化后的图像,在车牌的上边和下边各有一条较长的背景线(上图用红线表示)。根据这两条背景线可以准确的定位车牌。定位算法如下:

int LPR::HorizontalLine(int x,int y,int count)
{int ret;ret=0;int x_loop;for(x_loop=0;x_loop<count;x_loop++)if(!IsForegournd(x+x_loop,y))ret++;return ret;
}

IsForegournd(x,y)为询问点(x,y)是不是前景点的函数。

该算法比角点定位算法要快,但是不适合经过旋转后的车牌。虽然经过改进后也可以识别出旋转后的车牌,但是速度很慢,不能出现在成熟的产品中。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第3节 变化率定位法

图中有三条直线,如果沿着这三条直线扫描的话,会发现:黑色的扫描线前景占很大的比例,绿色的扫描线背景占很大的比例;红色的扫描线前景背景比例都不突出,但是前景背景交替较为频繁。这说明根据前景背景变化率可以定位车牌。

这种算法可以有效防止车牌旋转的干扰。

获得变化率的代码如下:

double CLPR::ScanLine(int x,int y,int count)
{bool current_foreground;current_foreground=IsForeground(x,y);int change_times;change_times=0;int loop;for(loop=1;loop<count;loop++){if(current_foreground){if(!IsForeground(x+loop,y)){change_times++;current_foreground=false;}}else{if(IsForeground(x+loop,y)){change_times++;current_foreground=true;}}}double ret;ret=change_times;ret/=(count+1);//do not div 0return ret;
}

第5章 字符分割

在车牌识别过程中,车牌定位后的工作便是分割字符。本章将分若干节介绍字符分割的算法。

第1节 连续点分割法

对于一个数字或者字母,前景的点是连续的。用填充算法对种子点填充即可得到整个字符。

当然汉字就不是了,所以这种分割算法仅仅适合数字或者字母。但是当整个车牌的数字和字母都得到之后,剩下的那个必定是汉字。

这个思想用c/c++描述如下:

void LPR::Scan()
{int y;for(y=m_plate_top;y<=m_plate_bottom;y++){int x;for(x=m_plate_left;x<=m_plate_right;x++){if(IsForeGround(x,y)&&!IsVisited(x,y)){Fill(x,y);}}}
}

Fill是种子填充,算法有多种。下面分别介绍。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览
2.5.1.1递归填充算法

递归填充算法的基本思想是,首先访问当前点,然后访问当前点的四个邻居。

每次访问时,要做一个记号,否则递归过程无法结束。

具体到车牌识别,每访问一个点,还要记录该点的坐标,从而得到当前字符点的集合。

void LPR::Fill(int x,int y)
{if(!IsForground(x,y))return ;if(IsVisited(x,y))return ;AddPixelToCharacter(x,y);MarkPixelVisited(x,y);Fill(x+1,y);Fill(x,y+1);Fill(x-1,y);Fill(x,y-1);
}

可以看出用c/c++描述的填充算法十分简单。

2.5.1.2递归扫描线算法

基本的递归填充算法,函数递归调用较为频繁,引起系统资源消耗巨大。人们后来又提出了改进了的“扫描线种子填充算法”。其基本思想是:在种子的左右两边水平扫描暂时不需要递归,以减少不必要的函数调用。水平扫描结束后,仅仅考虑扫描线两个端点即可。算法如下:

void LPR::Fill(int x,int y)
{int (*stack)[2];stack=(int (*)[2])new int [m_width*2];int stack_length;stack_length=0;stack[stack_length][0]=x;stack[stack_length][1]=y;stack_length++;while(true){if(stack_length==0)break;x=stack[stack_length-1][0];y=stack[stack_length-1][1];stack_length--;int left_x;for(left_x=x-1;left_x>=0;left_x--)if(!IsForeGround(left_x,y)||IsVisited(left_x,y))break;left_x++;for(x=left_x;x<m_width;x++){if(!IsForeGround(x,y)||IsVisited(left_x,y))break;Visit(x,y);}int right_x;right_x=x;if(right_x>=m_width)right_x=m_width-1;left_x--;if(left_x<0)left_x=0;int down_y;down_y=y+1;if(down_y<m_height){for(x=left_x;x<=right_x;x++){if(IsForeGround(x,down_y)&&!IsVisited(left_x,y)){stack[stack_length][0]=x;stack[stack_length][1]=down_y;stack_length++;}}}int up_y;up_y=y-1;if(up_y>=0){for(x=left_x;x<=right_x;x++){if(IsForeGround(x,up_y)&&!IsVisited(left_x,y)){stack[stack_length][0]=x;stack[stack_length][1]=up_y;stack_length++;}}}}delete [] (int*)stack;
}

虽然扫描线种子填充算法,比基本的种子填充算法复杂一些,但是在车牌识别测试后发现,扫描线种子填充算法比种子填充算法要快三分之一左右。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第2节 边界法

边界法和连续点分割法很相似,只不过连续的边界点,而不是所有的前景点。边界法需要事先得到前景像素中的边界点,这可能会花费一些时间。但是这样会加速得到连续点的递归操作。边界点如下图:

得到边界点的算法如下:

void CLPR::GetEdge()
{int y;for(y=0;y<m_height;y++){int x;for(x=0;x<m_width;x++){if(IsForeground(x,y)){if(!IsForeground(x-1,y))SetEdge(x,y);else if(!IsForeground(x+1,y))SetEdge(x,y);else if(!IsForeground(x,y-1))SetEdge(x,y);else if(!IsForeground(x,y+1))SetEdge(x,y);}}}
}

连接边界点的算法和连接前景点的算法完全相同。

第3节 根据尺寸分割

从理论上讲,图片和实物相比,尺寸上有了很大的变化。并不一定图片和实物几何意义上的相似。也就是说未必图像和实物成比例。但是实验证实,在一到两个像素范围内,在水平方向上,实物和图像基本上成比例。

请观察下图:

这个是来自于《GA36-2007中华人民共和国机动车号牌》的车牌尺寸说明。根据这幅图片,我们可以在一定位的车牌上,找到各个字符的坐标。请看下面的代码:

void GetCharacterPosition(int character_position[7],int plate_left,int plate_right)
{static const int mm[]={3+45/2,character_position_mm[0]+12+45,character_position_mm[1]+12+10+12+45,character_position_mm[2]+12+45,character_position_mm[3]+12+45,character_position_mm[4]+12+45,character_position_mm[5]+12+45,character_position_mm[6]+45/2+1,};int index;for(index=0;index<sizeof(mm)/sizeof(mm)-1;index++)character_position[index]=plate_left+(-plate_left+plate_right)*mm[index]/mm[sizeof(mm)/sizeof(mm[0])-1];
}

上面的代码技巧性很大,需要读者认真揣摩。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第6章 去除干扰

干扰车牌识别的因素很多。比如车牌旋转、污染、固定螺丝和车牌边框等等。下面分小节分别介绍去除各种干扰的方法。

第1节 去除噪音

去除噪音的原理是:每一个字符,都是很大的一个连续块,但是噪音确是比较小的多个连续块。通过递归算法得到每个字符中各个块的大小,保留最大的块,其余块当作噪音删掉。算法很简单,这里不再列出代码。

第2节 去除螺丝干扰

去除螺丝的工作要和字符本身的特征联系在一起。对不同的字符、相同字符不同部位的螺丝,都要分别编码。工作量很大。下面分小节举几个例子:

2.6.2.10986等左上方螺丝

这种情况如下图所示:

在比较圆的9的上部出现了一个螺丝,比较明显。可以删掉,代码如下:

void CLPR::DeleteLeftUpSmallScrewCharacterRound()
{bool possible_screw;int possible_screw_start;int possible_screw_end;if(m_character_index==5){possible_screw=false;{int seek;for(seek=0;seek<=1;seek++){possible_screw_start=m_min_y+seek;int screw_right;if(ExpandHorizontal(screw_right,possible_screw_start,possible_screw_start,m_max_x,SUB)){if(screw_right>=m_delta_x/2){possible_screw=true;break;}}}}int delta_x;if(possible_screw)    {possible_screw=false;for(possible_screw_end=possible_screw_start+1;possible_screw_end<m_min_y+m_delta_y*2/5;possible_screw_end++){delta_x=RecognizeCharacterLocateVeritcalSmallSideScrewGetDeltaX(true,possible_screw_end,true);int left;if(!ExpandHorizontal(left,possible_screw_end,possible_screw_end,m_min_x,ADD))continue;if(left>m_delta_x/2)continue;int right;if(!ExpandHorizontal(right,possible_screw_end,possible_screw_end,m_max_x,SUB))continue;if(right>delta_x/2)continue;if(possible_screw_end+4>m_center_y)continue;int distance1;distance1=HorizontalDistance(possible_screw_end,possible_screw_end);int distance2;distance2=HorizontalDistance(possible_screw_end+2,possible_screw_end+2);int distance3;distance3=HorizontalDistance(possible_screw_end+4,possible_screw_end+4);if(!(distance1<=distance2&&distance2<=distance3&&distance1<distance3&&distance1>0))continue;if(distance3<delta_x*3/4)continue;int seek;for(seek=2;seek<=4;seek++){if(ChangeTimeHorizontal(possible_screw_end+seek,possible_screw_end+seek)==4){possible_screw=true;break;}}if(possible_screw)break;}}if(possible_screw){int left;if(!ExpandHorizontal(left,possible_screw_end-1,possible_screw_end-1,m_min_x,ADD))possible_screw=false;else{if(left>=m_delta_x/2)possible_screw=false;}}if(possible_screw){bool known_letter;known_letter=false;if(!known_letter){m_min_y=possible_screw_end;RecognizeCharacterAdjustVertical();}}}
}

以上代码拷贝自绿睿车牌识别工程,实际上是比较旧的版本。读者可以进行修改,并放入自己工程中。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览
2.6.2.2EFT5等右上方螺丝

这种情况如下图所示:

在比较平的5的上部出现了一个螺丝,十分明显。删掉螺丝的代码如下:

void CLPR::RightUpSmallSideScrewCharacterWide()
{if(!(m_character_index==1||m_character_index==4))return ;int possible_screw_start;possible_screw_start=RecognizeCharacterLocateVeritcalRightUpSmallSideScrewGetStart();if(possible_screw_start==-1)return ;bool possible_screw;int possible_screw_end;possible_screw=false;int delta_x;for(possible_screw_end=possible_screw_start+1;possible_screw_end<m_center_y;possible_screw_end++){int distance;distance=HorizontalDistance(possible_screw_end,possible_screw_end);delta_x=RecognizeCharacterLocateVeritcalSmallSideScrewGetDeltaX(false,possible_screw_end,true);if(distance>delta_x*0.63){int seek;for(seek=1;seek<=3;seek++){int left;if(ExpandHorizontal(left,possible_screw_end-seek,possible_screw_end-seek,m_min_x,ADD)){if(left>=delta_x/2){possible_screw=true;break;}}}}if(possible_screw)break;}if(!possible_screw)return ;{int y;y=possible_screw_end-1;int left;if(ExpandHorizontal(left,y,y,m_min_x,ADD)){if(left<m_delta_x/2){int distance;distance=HorizontalDistance(y,y);if(distance>delta_x*0.25)return ;}}}if(possible_screw_end>m_locate_up_contrack_limit)return ;bool known_letter;known_letter=false;if(!known_letter){m_min_y=possible_screw_end;RecognizeCharacterAdjustVertical();}
}

以上代码也是来自绿睿车牌识别的一个老版本。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第3节 去除边框

普通的车牌边框对车牌识别的准确度影响不大。但是某些车牌并不符合标准的车牌尺寸。比如下图:

对于没有经过旋转的车牌,去除边框的算法很容易。在车牌定位之后,就可以估算出车牌字符的大小。如果在字符宽度范围内,都是前景的颜色,没有发生前景背景交替,那么这个连续部分必定是车牌的边框。代码如下:

void CLPR::DeleteFrame()
{int y;for(y=m_plate_top;y<=m_plate_bottom;y++){int x;for(x=m_plate_left;x<=m_plate_right;x++){if(ScanLine(x,y,m_character_width*5/4)==0){SetToBackground(x,y,x+m_character_width*5/4,y);}}}
}

SetToBackground(x1,y1,x2,y2)将x1,y1,x2,y2组成的矩形(这里是一条水平线)里的前景变成背景。这样就删除了边框。

如果车牌旋转角度不大,上述算法也同样适用,但需要在去除完边框后,再做一遍去除噪音点的操作。

如果车牌旋转角度很大,需要换用其它算法。

第4节 旋转

2.6.4.1根据车牌的旋转旋转字符

车牌是个刚体,也就是说它不能发生形变。车牌的旋转角度和字符的旋转角度相同。根据车牌的旋转角度逆向旋转就可以纠正字符。

对于较大的车牌,纠正旋转后的字符,识别率大大提高。对于较小的字符,纠正旋转过程可能丢失某些重要的信息,以致降低识别率。

角点车牌定位方法比较容易得到车牌自身的旋转角度。甚至车牌拉伸和斜切的参数也可以求出来。这样就可以对字符作更精细的恢复,减少字符识别的负担。

2.6.4.2在字体识别时容忍旋转

如果车牌定位本身不精确,很难得到字符本身的旋转信息。这就需要根据不同的字符,纠正旋转。但是一旦知道了字符值,也就没有任何必要做旋转纠正。所以字符识别需要增加对字符旋转的容忍能力。

第7章 字符识别

因为车牌字体是印刷字体。对于印刷字符识别,一般的思路是和模板比对。这样做最大的好处在于编程方便。

但是有两个坏处,第一速度较慢,第二识别率不高。如果用编程语言逐一描述字符的特点即可纠正这两个问题,当工作量很大。

第1节 模板匹配

车牌字符的字体可以在《GA36-2007中华人民共和国机动车号牌》找得到。下面程序有所有汉字的字体。

#define LPT_FONT_WIDTH 16
#define LPT_FONT_HEIGHT (LPT_FONT_WIDTH*2)bool LPRFontGet(int character_index,int x,int y)
{static const int mask[][LPT_FONT_WIDTH*LPT_FONT_HEIGHT/(sizeof(int)*8)]={{0x01800180,0x03800380,0xfffffffe,0x00000000,0x3ffc0000,0x3ddc3ffc,0x381c381c,0x381c381c,0x3ffc381c,0x01801ffc,0x19b80180,0x399c39b8,0x319c319c,0x718e718c,0x61e6618e,0x01e061e6},{0x07000700,0x7fce070c,0x7fdc7fdc,0x77007708,0xffe47700,0x770effee,0x77c8771c,0x7fc07fc0,0x071c0708,0x7fec071c,0x07cc7fec,0x070c070c,0xffeeffee,0x0706ffe6,0x07060707,0x07000704},{0x06600660,0x7e7f7e7f,0x06601e7f,0xfe7e7e7e,0x00003c62,0x3ffc3ffc,0x3ffc318c,0x3f9c3ffc,0x3ffc318c,0x0c603ffc,0x7ffe7c60,0x0c607ffe,0xffff0c60,0x0c20ffff,0x383c1e70,0x0000701e},{0x7ffc7ffc,0x06607ffc,0x66640660,0x766e666e,0x0664366c,0xffff0660,0xffffffff,0x00000000,0x1ff81ff8,0x18181ff8,0x18181818,0x1ff81ff8,0x18181818,0x18181818,0x1ff81ff8,0x18181818},{0x0c300c30,0x7fff7fff,0x0c307fff,0x7ffe7c3e,0x60067ff6,0x0ff06ff6,0x7ffe0000,0x01fe7ffe,0x33fc21f0,0x1fc43b9c,0x17701ee0,0x37cc379c,0x667036e4,0x671c6638,0x03e6438e,0x004001c0},{0x7fcc6008,0x7fdc7fdc,0x3c387818,0x0c001c18,0x0c1e0c00,0x0c1e0c1e,0x0c180c18,0x0c180c18,0x0c180c18,0x0c180c18,0x0c180c18,0x0c180c18,0x0f180f18,0x007c0738,0xffee00fe,0x7f007fc6},{0x03800380,0x03800380,0xffff0380,0xffffffff,0x03800380,0x03800380,0x7ffc0380,0x00007ffc,0x00000000,0x3ffc3ffc,0x301c301c,0x301c301c,0x301c301c,0x301c301c,0x3ffc3ffc,0x001c301c},{0x7ffc7ffc,0x718c7ffc,0x7dac718c,0x7fec7dbc,0x73cc77ec,0x7ffc738c,0x7ffc7ffc,0x01800180,0x7ffc7ffc,0x01807ffc,0xfffe0180,0xffffffff,0x32440000,0x666c766c,0xeeee666e,0x0000eee6},{0x07040000,0x0e1e060e,0x00080e1c,0xffc0ffc0,0xe1c6ffc4,0xe1dce1ce,0xe1c0e1c8,0xe1c4e1c0,0xffdcffcc,0x01cce1cc,0x01cc01cc,0x01cc01cc,0x00c600ce,0x00e600c6,0x007600e7,0x00000074},{0x1c301c30,0xfffe1c30,0xfffefffe,0x1c301c30,0x00001c30,0x01c001c0,0x0ffc01c0,0x0cc00ffc,0x0cc00cc0,0x3ccc3cdc,0x7c6e3cec,0x6e666e66,0x0e302e70,0x0e1c0e38,0x078e0e1c,0x01800786},{0x60c00000,0x7cce78c4,0x0cdc1ccc,0x0cc00cc0,0xfff60ff0,0xfccefcc6,0x6cc06ccc,0x6dc06cc0,0x6cec6dc4,0x6cec6cfc,0x6ccc6ccc,0x6ccc6ccc,0x6cc66cc6,0x66c66ec6,0x67e666c6,0x00206260},{0x0e000000,0x0c1c0e18,0x7f8c7f8c,0x61bf7fbf,0x61b761bf,0x3f373f37,0x00373f37,0x7fbf0037,0x7fb3ffbf,0x1f331f33,0x1f331f33,0x1b3f1f33,0x1b3f1b3f,0x5b071b07,0xfbc0db00,0x000079c0},{0x000c0000,0xffd8ffdc,0xe010e038,0xe187e187,0xeff7c187,0xcff7eff7,0xcdb7cdb7,0xcdb7cdb7,0xcff7cff7,0xc1b7cdf7,0xcd87c9b7,0xcf87cd87,0xdbf7dff7,0xc007c807,0xe007c007,0x00077007},{0x06180200,0xfe7efe18,0x6f00667e,0x39b63fa6,0x677e7c34,0x3c00437e,0x187e3c7e,0x7fe61866,0x007e7fe6,0x7f667f66,0x4b7e437e,0x5b185b18,0x087f4b18,0x3c180c7f,0x67983618,0x00186318},{0x00c00040,0x0ff01de0,0x07180ff8,0x3fff3ffe,0x3398339a,0x3ff83ff8,0x31983198,0x3ffc3ff8,0xffff0000,0xff80fffe,0x3ff80000,0x38183ff8,0x3ff83ff8,0x38183ff8,0x3ff83ff8,0x38003818},{0x06000200,0x3f3e3e3e,0x19b0333e,0x7fde7fdc,0x491849cc,0x7f7f4908,0x0c6c7f7f,0x4f0c0e6c,0x6dcc6f8c,0x3f0c3e8c,0x6dcc3f0c,0x6e0c6ecc,0x498c6b0c,0x4c4eccec,0x07000e06,0x01000300},{0x7bde79de,0xdb567bde,0xdb56db56,0x4bdecb52,0x68006bde,0x6bfc3800,0x48006bfc,0x4fff4800,0x4c184fff,0x4df84c18,0x4df84df8,0x4d804d80,0x6d804d80,0x6cc06dc0,0x0cf82cc0,0x00100c70},{0x00c000c0,0xfcce40c4,0xdcc8fccc,0xdff0dcc0,0xdcc0dff0,0xfccefcc7,0xddccddcc,0xdfe0ddc0,0xdee4dfe0,0xfcecfcec,0xdcfcfcfc,0xdcd4dcf4,0xdcd6dcd6,0xfcc6dcc6,0xdd80fdc6,0x0080dc80},{0x00e00040,0x3ffe0060,0x3ffe3ffe,0x3dae318e,0x31ae35ee,0x3ffc3ffc,0x35ec31cc,0x3dac3dec,0x3f8c318c,0x3ffc3ffc,0xffff0000,0x07ffffff,0x3ff00030,0x38003ff8,0x1f801800,0x03800f80},{0x38381838,0x38383838,0x7e387e38,0x38fe7e38,0x38fe38fe,0xfe3c3838,0xfe3cfe3c,0x00fc00fc,0x19fe18fe,0x183e18be,0x7e387e3e,0x18387e38,0x18381838,0x18381838,0x7f387f38,0x00387f38},{0x0e000000,0x0c000e00,0xffff0c3f,0x001cffdc,0x7f9c001c,0x7f9c7f9c,0x61bf61bf,0x618c61bf,0x7f8c7f8c,0x0e0c7f8c,0x7fbc0e2c,0x6fde6ffc,0x6ec66ece,0xee606ee2,0x4f60ce60,0x03000f00},{0x06040000,0x061c060c,0x1b100f18,0x31c03b80,0xe0e071e0,0x0f064f62,0x000c000e,0x43e063e0,0x4a604be0,0x4be84a60,0x4a6c4bec,0x4bec4a6c,0x4a6c4bec,0x42644a64,0x63664266,0x21606364},{0xe000e000,0xe718e018,0xe718e718,0xe318e318,0xe318e318,0xe318e318,0xe318e318,0xe318e318,0xe31ce31c,0xe31ce31c,0xe31ce31c,0xe31ce31c,0xe31ce31c,0xe30ee30c,0xe006e30e,0xe000e000},{0x03800380,0x3ffc3ffc,0x339c3ffc,0x3f9c339c,0x3ffc3ffc,0x03800380,0x7fffffff,0x00000000,0x3ffc3ffc,0x301c3ffc,0x339c339c,0x339c339c,0x01c0319c,0x1ce00dc0,0x703c3870,0x2004601e},{0x3ff83ff8,0x00003ff8,0x00000000,0x00000000,0x00000000,0x00000000,0xffffffff,0x018003ff,0x00c001c0,0x00e000c0,0x0c700860,0x18301c30,0x38181838,0x3f9c3c18,0x61fc7ffc,0x2000601c},{0x0c600420,0x7ffe0c60,0x7fe07ffe,0x60004460,0x78065806,0x7ff67ff6,0x1ff61836,0x5afe1ff6,0x5ff0dafe,0x7cfe5ff0,0x74fe74ff,0x32f637f6,0x32f632f6,0xf8167fd6,0x6e187c1a,0x00006718},{0x0c000c00,0x0c3e0c00,0x7ff60c3e,0x7ff67ff6,0x0c1e0c16,0x6cde4cde,0x6db66df6,0x2db66db6,0x0c360c36,0xfff6fff6,0x0e370c37,0x0e370e37,0x1b1f1f1f,0x31c73b87,0x60e771c7,0x40206067},{0x18381800,0x18381838,0x18381838,0x18381838,0x7fff1838,0x1838ffff,0x18381838,0x18381838,0x1ff81ff8,0x18381ff8,0x18381838,0x18381838,0x18381838,0x1ff81838,0x18381ff8,0x00381838},{0x03800180,0x7ffc7f80,0x03807ffc,0x3ffc0380,0x3ffc3ffc,0xffff0380,0xffffffff,0x3ffc0000,0x3ffc3ffc,0x301c301c,0x3ffc3ffc,0x301c301c,0x3ffc3ffc,0x301c301c,0x381c301c,0x0810381c},{0x01800100,0x03800380,0xfffe0380,0xe006fffe,0xe006e006,0x0000e006,0x00000000,0xffff0000,0xffffffff,0x03800380,0x03800380,0x03800380,0x03800380,0x03800380,0x03c00380,0x00c003c0},{0x40300020,0x3dfef830,0x0dfe0dfe,0x0c000c00,0x0ccc0ccc,0x7c600ccc,0x6fff7ff8,0x6c306fff,0x6c306c30,0x6dfe6dfe,0x6cbc6c30,0x65bc6dfc,0x67b667b6,0x66376636,0x63386630,0x00086338},{0x0d840c00,0x0d8e0d84,0x7fec0d8c,0x7fe07fe8,0x0d820d80,0x7ff70d82,0x7ff47ff6,0x18c059c4,0x7fe030e0,0x6ff47ff0,0x48cc48dc,0x0fc408c4,0x4fc60fc6,0x60c640c6,0x7fc27fc7,0x00003fc0},{0x03000100,0x7fe60304,0x7fec7fee,0x6660606c,0x6f606fe0,0x6fe66f62,0x6fe66fe7,0x6f646764,0x6fe46fe0,0x626c66e4,0xfff4260c,0xfff6fff6,0x0f060706,0x39c71f86,0x70f279e6,0x00006060},{0x0e380600,0x0e180e38,0x7ffc0e18,0x7fce7ffc,0x7fce0e0e,0xffce7fce,0xeecceecc,0x6ecc6ecc,0x7fcc7fcc,0x0e1c0e1c,0x0fec0edc,0x0f9c0fdc,0x0f0c0f9c,0x3f9c1f1c,0xf1fc7bdc,0x001c60dc},{0x7f980008,0x0c387f98,0x0c7c0c38,0x7f4c0c6c,0x61167f06,0x6d30611a,0x6d106d30,0x6d7e6d00,0x6d606d7e,0x6d6c6d60,0x6f3c6d3c,0x6f186f1c,0x0c300c38,0x36300c30,0x63807700,0x00004180},{0x18c00800,0x1ccc18ee,0x0ddc1dcc,0x0e000e08,0x7ffe7ffe,0x60067ffe,0x6fe66006,0x0ff00ff0,0x07000e00,0x03800380,0xffffffff,0x0180ffff,0x01800180,0x03800180,0x03e00380,0x00c001c0},{0x0c580408,0x7dfe0c5e,0x7e587ffe,0x37fc7618,0x3fbe3ffc,0xfdae3bbf,0x7ffc7ffc,0x038065bc,0xfffe7ffe,0x1ff80000,0x00001ff8,0x1ff81ff8,0x1ff80000,0x18181ff8,0x1ff81818,0x18181ff8}};if(x>=LPT_FONT_WIDTH)return false;if(y<0)return false;if(y>=LPT_FONT_HEIGHT)return false;int int_index;int_index=y*LPT_FONT_WIDTH+x;int bit_index;bit_index=int_index%(sizeof(int)*8);int_index/=(sizeof(int)*8);if(mask[character_index][int_index]&(1<<bit_index))return true;elsereturn false;}
void CChildView::OnPaint()
{CPaintDC dc(this);int y;for(y=0;y<LPT_FONT_HEIGHT;y++){int x;for(x=0;x<LPT_FONT_WIDTH;x++){if(LPRFontGet(36,x,y))dc.SetPixel(x,y,RGB(64,128,128));elsedc.SetPixel(x,y,RGB(200,200,200));}}
}

其中bool LPRFontGet(int character,int x,int y)的功能是取得字体。

character 的取值范围是0~36,分别代表:“京”“津”“冀”“晋”“蒙”“辽”“吉”“黑”“沪”“苏”“浙”“皖”“闽”“赣”“路”“豫”“鄂”“湘”“粤”“桂”“琼”“渝”“川”“贵”“云”“藏”“陕”“甘”“青”“宁”“新”“港”“澳”“使”“领”“学”和“警”。

x,y是字符上像素坐标取值范围:x[0~16],y[0~32]。

如果该点是字体上的点返回true否则返回false

void CChildView::OnPaint() 是应用LPRFontGet的一个例子。

向您推荐 —— 绿睿 车牌识别

车牌识别采购、研发纵览

第2节 字符特点

用编程语言逐一描述字符的特点,可以很好的提高在恶劣环境下的字符识别率,从而提高车牌识别的质量。但是这个算法编程任务繁重,所以只有在商业化运用时使用。另外这也是一种手工操作的“神经网络”识别,比自动化的“神经网络”效率高。

下面举个例子,例子来自于最新版的绿睿车牌识别的核心代码。

bool CLPR::LetterNumberRecognize5LeftDown()
{//判断是不是字符‘5’的左下角bool five_left_down;five_left_down=false;//扫描开始的地方int start_y;start_y=m_center_y+2;//m_center_y: 字符中间的y坐标//扫描结束的地方int end_y;end_y=m_max_y-2;//m_center_y: 字符最下面的y坐标//开始扫描int y;for(y=start_y;y<end_y;y++){int left;left=Left(y);//在y行,最左端像素离边界的距离if(left>=m_delta_x*0.5)//m_delta_x 字符的宽度{five_left_down=true;break;}}return five_left_down;
}

整个过程都是在走逻辑很繁琐。但是识别效率还可以,还可以有效抵抗字符旋转等干扰。

向您推荐 —— 绿睿 车牌识别

转载于:https://www.cnblogs.com/zhaoleicpp/archive/2009/04/20/1439458.html

车牌识别采购、研发纵览相关推荐

  1. 浅析AI边缘计算的车辆/车牌识别技术研发及场景应用

    车牌识别技术是计算机视频图像识别技术在车辆牌照识别中的一种应用,它融合了ORC识别.云计算等多种技术,可将运动中的汽车牌照从复杂的背景中提取并识别出来,通过车牌提取.图像预处理.特征提取.车牌字符识别 ...

  2. 车牌识别的研发,四种车牌识别软件

    互联网的繁荣发展随之而来互联网也强势发展,物联网顾名思义,物联网就是物物相连的互联网.这有两层意思:其一,物联网的核心和基础仍然是互联网,是在互联网基础上的延伸和扩展的网络:其二,其用户端延伸和扩展到 ...

  3. 车牌识别SDK,解决多行业全方位方案

    PC端车牌识别sdk 文通PC平台车牌识别sdk是北京文通科技有限公司自主研发的PC平台车牌识别sdk,在智能交通系统.出入口管理系统.公安图帧系统.移动警务系统等多种行业都已实现成功运用.文通PC平 ...

  4. 浅析AI智能分析网关的车辆/车牌识别技术的研发及应用场景

    车牌识别技术是计算机视频图像识别技术在车辆牌照识别中的一种应用,它融合了ORC识别.云计算等多种技术,可将运动中的汽车牌照从复杂的背景中提取并识别出来,通过车牌提取.图像预处理.特征提取.车牌字符识别 ...

  5. 移动端扫描车牌识别,新能源车牌OCR识别已研发

    移动端扫描车牌自动识别技术的技术核心:移动端车牌识别,手机端车牌识别,手持端车牌识别,Android端车牌识别,ios车牌识别,统统都是以OCR识别技术为基础,车牌定位凹凸字体处理二值化字符切割一系列 ...

  6. 车牌识别算法_PC端车牌识别SDK融入好算法

    PC端车牌识别SDK介绍 易泊PC端车牌识别SDK融合了车牌定位.车牌字符切分.车牌字符识别等算法,使该系统具有识别效率高.速度快.适应性强.使用方便等优势,技术处于国际先进水平.大力发展机器人.人工 ...

  7. 巡逻机器人用应用的pc端车牌识别

    PC端车牌识别产品形态 加密锁.车牌识别SDK开发包.开发文档 pc端车牌识别使用背景 人工智能的发展,京东送件也用上了送件机器人,某机器人公司如今研发出巡逻机器人,用于对可以车辆的抓拍与检查,在停车 ...

  8. c程序设计停车场收费管理系统_智能车牌识别停车收费管理系统

    关键词:停车收费系统.车牌识别.车牌识别相机.停车管理系统.智能停车管理 今天主要来讲一下当今社会应用比较多的智能停车收费管理系统的知识. 智能停车场收费系统简介 车牌识别停车场收费系统集车牌识别一体 ...

  9. 移动端车牌识别(前端识别、后端识别)的区别分析

    关键词:移动端车牌识别.ocr车牌识别技术.车牌识别技术.车牌识别sdk.移动端车牌识别sdk.手机端车牌识别.安卓车牌识别.安卓端车牌识别技术. 移动端车牌识别sdk(前端识别) 移动端前端车牌识别 ...

最新文章

  1. 怎么检测JDK环境变量是否配置正确
  2. nginx(一)安装与命令总结
  3. 3 float py 位小数 裁剪_对一个 float 精度问题的分析
  4. Airflow 中文文档:用upstart运行Airflow
  5. ROS学习笔记3(创建一个ROS Package)
  6. Oracle的去重函数 distinct
  7. 《嵌入式设备驱动开发精解》——1.1 本书内容的组织
  8. Vue2.0 Vue组件库
  9. JavaScript 05
  10. C盘清理——借助软件TreeSizeFree【网盘分享】(亲测有效)
  11. x86_64 gnu/linux,linux版本信息以及x86与x86_64的差别
  12. 房贷没放款前千万不要做的事
  13. 【原创】更相减损术 stein算法 欧几里得算法 拓展欧几里得算法 扩展欧几里得算法 逆元的计算与筛法 解模线性方程
  14. leetcode oj java Bulls and Cows
  15. 无法删除文件夹的“只读”属性
  16. 基于STM32F103的步进电机S型曲线加减速算法与实现
  17. HTML/CSS写的简单的注册页面
  18. Linux 下 lsof 命令的几个高效用法
  19. rayleighchan实现瑞利多径衰落信
  20. asp网站开发--实例(收藏)

热门文章

  1. 抗渗等级p6是什么意思_抗渗等级P6什么意思?
  2. java 获取指定日期的前几天或后几天
  3. 2019华北五省计算机应用大赛官网,软件学院学生在2019年华北五省(市、自治区)及港澳台大学生计算机应用大赛(河北赛区)中喜获佳绩...
  4. SAP 取标标准成本和实际成本
  5. scala学习之旅(十三):隐式转换和隐式参数
  6. 0xc0000225无法进系统_系统重装|电脑无法开机蓝屏错误代码0xc0000225故障问题
  7. 计算机原理(CPU+存储+OS+指令)
  8. Django 创建随机验证码
  9. html5页面上下翻页特效,h5实现垂直上下翻页效果
  10. 记一次在学院服务器装Ubuntu系统