版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
车牌识别系统的设计与实现摘要随着人们生活水平的日益提高,对汽车的需求越来越大,而随之而来的问题就是交通控制压力的增大,为了有效缓解日益增大的交通管理,车牌识别系统的运用也越来越得到重视。车牌识别系统主要用于高速公路的收费处,可以帮助交警更好的管理高速公路上的收费问题,汽车通过高速公路时,车牌识别系统能很快的识别出汽车的车牌信息,并记录下来,加快了高速公路的通行速度,节省了人力,物力,提高了效率。车牌识别系统还可以用于停车场收费,当汽车驶入停车场时,由图像采集设备对车牌进行拍摄,将拍摄到的图像传输给系统,由系统识别出车牌,之后进行记录,收费,大大方便了停车场的管理。车牌识别系统可以分为:车牌定位模块、车牌矫正模块、车牌分割模块、车牌识别模块。其中,车牌定位模块为车牌识别系统中的重要步骤,直接影响后续识别的准确率。常用的车牌定位算法有:基于形状、基于文字特征、基于色调、基于纹理等特征方法。因为车牌的形状为比较规整的矩形,使用基于形状的算法要求将目标转换为寻找矩形特征。国内的车牌多为蓝底白字,因此可以采用图像的饱和度和色调等特征,生成二值图,进行车牌定位车牌识别系统的功能可以分为定位、车牌字符的分割,车牌字符的识别等模块。其中,车牌的定位是本系统中的中重点,也是本系统实现的难点,因为定位的准确率直接影响到后续识别的准确率,可以说,如果车牌定位的好坏可以直接决定这个系统的好坏。而常常使用到达车牌定位算法包括了基于形状,文字特征,色调和纹理等各种特征的定位方法。而且车牌的形状多为蓝色底,白色字,规规整整的矩形,可以使用边缘检测或者基于形状的方法来定位车牌。本文主要介绍了基于Python+OpenCV+Tensorflow相关技术所开发的有关数字图像的车牌识别系统。从一张包含了车牌信息的一张静态图像中识别出车牌字符串。识别车牌这个过程包含了车牌的定位,车牌字符的分割,车牌字符的识别这三大模块,也是该系统的核心模块。其中车牌的定位使用的是OpenCV计算机视觉库,对图像进行灰度化,二值化,形态学等等的运算,从图像中定位出车牌所在的位置,并且将字符一个一个的分割出来。车牌字符的识别使用的是神经网络来进行识别的,在识别车牌之前先构建神经网络模型,通过海量的车牌字符图片,训练所搭建出来的神经网络,让它能够准确地识别分割后的车牌字符,最后通过客户端显示出识别结果来。关键字:车牌识别、车牌定位、神经网络目录第1章绪论 51.1研究的目的 51.2研究的意义 61.3国内外研究现状 71.4车牌识别的难点 7第2章开发环境简介 82.1VSCode简介 82.2Python简介 82.3OpenCV简介 92.4Tensorflow简介 9第3章相关知识于技术 103.1图像平滑处理 103.1.1均值滤波 103.1.2高斯滤波 103.1.3中值滤波 113.2形态学处理 123.2.1膨胀腐蚀 133.2.2开运算闭运算 133.3边缘检测 143.3.1Sobel算子 143.3.2Canny算子 153.4神经网络 163.4.1梯度下降 163.4.2反向传播 173.4.3激活函数 173.4.4损失函数 18第4章车牌识别系统的设计于实现 194.1车牌识别模块 194.1.1图像预处理 194.1.2车牌定位 224.1.3字符分割 244.1.4字符识别 274.2客户端模块 314.2.1客户端用户交互界面 314.5.2网络数据传输 31第5章结论 355.1总结 355.2展望 35参考文献 37绪论1.1研究的目的随着人们生活水平的日益提高,对汽车的需求越来越大,伴随而来的问题就是交通控制压力的增大,城市交通状况越来越受到人们的重视。如何有效管理城市交通成为各国关注的焦点。建立智能交通系统就是解决这一困境的最好办法。智能交通系统是一个以信息通信为基础的,将先进的科学技术,人工智能和数据通信技术等技术综合有效的运用与交通运算的方方面面,从而减少人工干预的成本,提高交通控制的效率,节约人力物力,而在智能交通系统中,车牌的识别技术的是重中之重,不可忽视的存在。1.2研究的意义1、高速公路收费站
在高速公路收费战的出入口的位置安放车牌识别系统,可以提高高速公路收费站的通信速度,节省人力成本。当车辆进入到车牌识别系统的采集区域时,由采集设备复杂采集车牌信息,并将采集到的车牌图像上次到服务器上,由车牌识别系统的识别算法来对上传过来的图像进行有效的识别并且返回到终端,记录车辆的通信信息。如果由违法违章车辆在通过此区域时,通过车牌信息和公安部的信息进行比对,可以有效的避免和防止犯罪事故的发送。
2、小区出入口小区的出口入口在车辆出入时主要是用来记录车牌号码和车辆的出入时间。例如,当一辆汽车驶入小区或停车场时,通过车牌识别系统可以快速准确的判断该车辆是否属于小区,如果属于小区,则放行,如果不属于小区则进行接下来的操作,对外部车辆采取定时收费等制度。这样可以节省大量的人力,在小区安装车牌识别系统可以一劳永逸的解决这些问题。3、停车场出入口
现如今汽车越来越对,停车也是绝大多数人的需求。在停车场安装智能车牌识别系统可以实现停车场的自动管理,节省人力,提高效率。当汽车驶入停车场时,通过图像采集设备采集车牌信息并识别,记录下车牌以及出入时间,就可以完成自动收费的功能,统计停车场车位数量,提高了停车场的利用率。1.3国内外研究现状 车牌识别系统的研究国外起步比较早。早在二十世纪八十年代,就开始有了车牌识别技术的应用,但是,这个阶段还没有形成完整的车牌识别系统体系,一般采用的是一些比较简单的图像处理方法来进行车牌识别,而且通常最终结果还是需要人工进行干预,效率并不高。 进入二十世纪九十年代后,车牌识别技术研究开始起步。典型的像A.S.Johnson提出车牌识别系统分为图像分割、特征提取、模板构造、字符识别等几个部分,用这几个部分完成车牌识别。 由于我国车牌的格式和国外车牌格式有非常大的差异,所以针对我过的车牌进行车牌识别有不同于国外,不能直接套用国外的车牌识别技术,需要结合我国车牌的实际情况来设计能够适应我国车牌的车牌识别系统。 国内九十年代也开始了直接的车牌识别系统的研究,比较成熟的车牌识别系统产品有中科院自动化研究所设计的汉王眼,香港亚洲视觉科技设计的慧光车牌识别系统等等。 虽然这些车牌识别系统的识别准确率都非常高,但是这些车牌识别系统的识别检测结构都是在简单的环境下所取得的,在比较复杂的环境下,这些车牌识别系统的识别准确率就不高了。1.4车牌识别的难点车牌定位和字符分割是车牌识别系统中最重要,也是最难的部分。是指在已经拍摄好的图像中,确定车牌的位置,并且从中提取车车牌图像,然后分割出车牌中的字符。车牌定位的难点主要来源于图像的采集,车牌图像的采用有额很多影响因素,包括大雨天的环境、大雾天的环境、光线不足的问题,这些复杂的问题让车牌的定位成为一件非常困难的事情。高分辨率下车牌识别速度问题,高分辨率的图像意味着车牌图像处理的开销也大,一般来说图像分辨率越高,车牌图像处理的开销越大,车牌识别速度越慢。但高分辨率图像下,对车牌处理和车牌识别的准确率有所提高,如何在这两者之前权衡存为一件困难的事情。车牌图像角度问题,在车牌图像的采集过程中,往往车牌不是正对着采集摄像头,这就造成了采集出来的车牌图像,字符并不是正的,而是斜的,这给车牌定位带来了很大的挑战。第2章开发环境简介2.1VSCode简介 VSCode全称VisualStudioCode,是由微软触屏的一款轻量级的文本编辑器,vscode以它免费、开源、功能强大的特点风靡全球,它几乎支持所有主流的编程语言的代码智能补全,语法高亮等等,支持插件扩展,并且对网页发开和云开发左右优化。支持的平台包括Windows、MacOS、Linux。该编辑器支持多种语言和文件格式的编写,截止2019年9月,已经支持了如下37种语言或文件:C++、C#、Java、Python、VB、SQL、PHP、HTML、JSON、XML、Lua、CSS、JavaScript、等等。2.2Python简介 Python是1990年由荷兰数学和计算机研究协会GuidovanRossum设计的,Python提供了高效的数据结构,有效的面向对象编程,Python以他解释性、高效性的特点,成为大多数平台上的快速开发应用的编程语言Python是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言,设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其他语言更有特色语法结构。2.3OpenCV简介 OpenCV是基于BSD开源许可的跨平台的计算机视觉和机器学习库,可以运行在Windows、Linux、Android、MacOS操作系统上。它是由C语言和少量C++语言编程而成,提供了Python、MATLAB等编程语言接口,实现了计算机图像处理和计算机视觉的通用算法 OpenCV主要应用于人脸识别、物体识别、图像分割、运动追踪、动作识别、机器视觉、运动分析等领域2.4Tensorflow简介 Tensorflow是基于数据流编程的符号数学系统,主要应用于各种各样的机器学习。它拥有多层结构,可以部署在各类服务器上、PC端和网页,支持GPU和TPU。 Tensorflow提供Python语言下的4个不同的版本:CPU版、GPU版、tf-nightly、tfnightly-gpu。安装Python版的Tensorflow可以使用pip安装,或者使用anaconda安装第3章相关知识于技术3.1图像平滑处理3.1.1均值滤波均值滤波是一种线性滤波,它主要采用的方法是邻域平均值法,是在某个邻域内,计算该领域的平均值,然后代替图像中的像素值。计算的公式为g(x,y)=求和f(x,y)/mm但是均值滤波也存在一定的不足之处,均值滤波可以对图像进行很好的去噪,但是在图像去噪的同时也破坏了图像的细节信息,因此给图像带来了比较严重的模糊。经过均值滤波后的图像:3.1.2高斯滤波高斯滤波器是一种线性滤波器,可以有效地抑制噪声,平滑图像。其作用原理类似于均值滤波器,即以滤波器窗口内像素的均值作为输出。窗模板的系数不同于平均滤波器的系数。平均滤波器的模板系数相同为1。而高斯滤波器的模板系数随着离模板中心距离的增加而减小。因此,高斯滤波器比均值滤波器模糊程度更小。高斯滤波让临近的像素具有更高的重要度,对周伟像素计算加权平均值,较近的像素具有较大的权重值,较远的显示具有较小的权重值。经过高斯滤波后的图像:3.1.3中值滤波滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近真实值,从而消除孤立的噪声点。该方法是利用一个具有一定结构的二维滑动模板,根据像素值的大小对平板中的像素进行排序,生成单调上升(或下降)的二维数据序列。中值滤波的实现是从图像中的某个采样窗口取出奇数个数据进行排序,用排序后的中值来取代要处理的数据。经过中值滤波后的图像:3.2形态学处理简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将
结构元素
作用于输入图像来产生输出图像。图像形态学运算运用十分广泛,通常用来消除图像噪声、分割图像中独立的元素、连接图像中相邻的元素、寻找图像中明显的极大值或极小值区域3.2.1膨胀腐蚀计算机图形学中的膨胀,是指将一个图像A和一个任意形状的内核B进行卷积运算,进行膨胀运算时,将内核B划过图像A,覆盖的区域选择并提取最大值,用来代替内核B中的锚点上的像素值,但是这一操作会导致的一个问题就是,图像中明亮的区域会扩展,因此膨胀会让原本的图像亮的区域变大,将不连续的区域连城一个整体。腐蚀操作就是提取内核中划过区域下的最小亮度值来取代锚点中的像素值,这一操作会使原本亮的区域变得比原来更加细小,甚至会将小亮点给完全抹除。3.2.2开运算闭运算 对图像先进行腐蚀操作,这一操作会使亮的区域变得更加细长,小亮点被完全抹除,然后再对图像进行膨胀运算,亮的区域恢复到原来的大小,而完全抹除的小亮点却不能恢复,这就是开运算。开运算可以很好的去除图像中的小亮点,前提是合理的选择好卷积核。 如果对图像先进行膨胀运算,再对其进行腐蚀运算,这种操作就叫做图像的闭运算。在图像膨胀的时候,如果亮的区域中有一个小黑点,膨胀会使这个小黑点完全消失,之后的腐蚀操作并不会将原来的小黑点还原。所以说闭运算可以很好的排除图像中的小型黑点。上图是对图像进行开运算的结果,首先对图像进行腐蚀,可以将上图的毛刺去除,但是“j“的粗细改变了,变得更细了,为了还原图像,再进行膨胀操作。最后得到的”j”就是去除毛刺的图像了3.3边缘检测3.3.1Sobel算子Soble算子的功能集合了高斯平滑和微分求导,又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到的是图像在X方法与Y方向梯度图像。水平变化:将图像与一个奇数大小的卷积核进行卷积 垂直变化:将图像与一个奇数大小的卷积和进行卷积 最后将水平方向的梯度和垂直方向的梯度进行相加即可得到图像的边缘信息3.3.2Canny算子Canny算子使用的是高斯滤波器进行梯度计算,得到的结果也类似于Sobel,距离中心的越近,像素点的权重也就越大。滞后阈值,如果梯度值比最大值要大,则将该像素点处理为边界,如果梯度值比最小值还要小,则将该像素值抛弃,不将其作为边界值。如果像素值在最大值和最小值之间,则于边界相连的保留,与边界不相连的抛弃。3.4神经网络神经元是神经网络的基本单元。神经元的基本功能就是获得输入,然后执行某些数学运算后,在将计算的结果进行输出。在上述神经元中,一共进行了3步数学运算,首先将2个输入乘以权重,再把2个结果进行相加,最后经过激活函数处理后输出,激活函数的作用是将无限制的输入转换为可以预形式的输出。3.4.1梯度下降 机器学习的核心内容就是把海量的数据输入到人工设计的模型中,然后让模型从这海量的数据中自动学习,从而优化模型自身的各种参数,最终使得这个模型能够在下一组没见过的数据中准确预测它的规律。而这个学习的过程就是机器学习算法的关键,梯度下降就是实现学习的这一过程常用的方法,在反向传播过程中,就是对每层的权重不断使用梯度下降来进行优化,梯度下降就是经过不断的改进,调整w权重值,使得模型的损失函数达到最小值,也就是优化模型参数。具体来说,一开始,我们随机选择一个数w,然后一步一步改进,每一次变化一小步,每一步都尝试降低损失函数。3.4.2反向传播 这是一共典型的三层神经网络模型,其中从左到右分别为输入层、隐藏层、输出层。数据X{x1,x2,x3,…,xn}为输入数据,将数据输入到神经网络中,根据神经元的功能进行前向传播。其中输入数据i1=0.05,i2=0.10。输出数据o1=0.01,o2=0.99,初始权重w1=0.15,w2=0.20,w3=0.25,w4=0.30,w5=0.40,w6=0.45,w7=0.50,w8=0.55 前向传播:neth1=w1*i1+w2*i2+b1*1 outh1=1/(1+e^(-neth1)) neto1=w5*outh1+w6*outh2+b2*1通过前向传播将,可以得到一个输出,再用这个输出的值和预期值进行比较,它们之存在一定的误差,为了缩小这种误差,从最后一层开始逐层进行调整神经网络的参数,如果误差值为负,就提升权重,如果误差值为正,就降低权重,调整的权重受到一定的比率限制,这个比率也叫学习率。在一次次不断的输入和调整的过程中,神经网络就会不断的自我优化,达达预期的输出3.4.3激活函数激活函数是深度学习中尤为重要的部分,它的作用就是对神经元接接收到的输入信息进行非线性的变化,并且将变换后的信息输入到下一层神经元并由下一次神经元进行计算。如果不使用激活函数的化,神经网络只会根据各层的权重和偏置进行简单的线性变换,不管网络由多少次都是一个线性回归模型,对于复杂问题的处理能力十分有限。并且神经网络中的反向传播算法依赖于激活函数,激活函数让反向传播成为了可能,因为激活函数可以使其误差变为一个可微的非线性函数,从而实现神经网络中各个参数的权重的调整。sigmoid函数可以将任意的输入映射到0到1的范围捏,输入的值越大,那么它越接近1,输入的值越小,那么它越接近0relu函数是使用最广的函数,因为relu函数能够在x的值大于0的时候保持梯度,避免发生梯度消失的问题,而且还可以加快神经网络收敛的速度。sortmax函数的优势于,它处理多分类问题非常方便。该函数可以将所有的输入映射成0到1的值,通常也叫做概率。3.4.4损失函数损失函数是用来评价模型的预测值和真实值不一样的程度,一般来说损失函数越好,模型的性能也就越好。不同的模型用的损失函数一般也不一样。损失函数分为经验风险损失函数和结构风险损失函数。经验风险损失函数指预测结果和实际结果的差别,结构风险损失函数是指经验风险损失函数加上正则项。0-1损失函数,字节对分类判断错误个数,0-1损失函数是一个非凸函数,其中,感知机用的就是这种损失函数。绝对值损失函数,计算预测值与目标值差的绝对值平方损失函数,平方损失函数主要用于解决回归问题第4章车牌识别系统的设计于实现在车牌识别系统中,图像采集主要由硬件来完成,即提取车辆的前景图像,将摄像头的视频信号转换为数字图像信号发送到计算机进行处理。因为自然环境的影响和照明条件,有许多干扰的车牌图像,这让车牌的定位不准确,所以为了更好地提取车牌,需要进行预处理的车牌图像,以确保质量的车牌位置。车牌区域检测,是系统的核心,这部分的实现,影响整个系统的性能,主要使用模式识别,数字图像处理,信息理论和其他知识的车牌定位和提取车牌图像。字符分割与识别,当车牌提取成功后,需要对其中的字符进行分割,并利用先验知识进行识别,得到最终结果。车牌识别系统的流程图4.1车牌识别模块4.1.1图像预处理 图像在计算机中是以文件的形式存储的,常见的图像存储格式由jpg、png、bmp、gif、tif、pcx、tga、fpx、psd、pcd、dxf、cdr、ufo、ai、raw、eps、wmf、webp、avi等等 图片文件的结构包括头文件、像素数据、调色板数据。 其中,头文件主要用于存放图像的基本信息,包括图像的各种特征参数、调色板数据和像素数据在文件中的位置,文字注释等等。像素数据在计算机上是以位图的形式存放的,每个像素数据对应图像相应位置上的颜色值信息。其中,具体颜色值由调色板数据提供。调色板数据,指二值、十六色、二百五十六色的色彩图像的色调数据。现在绝大多数的图像都是RGB彩色图像,RGB分别代表着3种颜色:R代表红色,G代表绿色、B代表蓝色。每个通道的范围为2的8次方,一共有2的24次方,也就是1670万种颜色,足以表示自然界中的任何一种颜色。灰度图像是值图像上每个像素用一个值来表示,范围从0到255,全黑为0,全白为255.。图像灰度化是指将彩色三通道图像转换为单通道灰度图。图像灰度化的有3种常用的方法:分量化。将一幅彩色图像的R通道,G通道,B通道中,取其中一个通道作为图像的灰度值最大值法:将一副彩色图像的R通道,G通道,B通道中,取其中一个亮度值最大的通道作为图像的灰度值加权平均法:因为人眼对绿色的敏感度是最高的,而对蓝色的敏感度是最低的,将彩色的图像以R=29.9%G=58.7%B=11.4%的比例进行加权平均计算得到灰度图像图像灰度化算法能够有效加快计算机图像处理速度,省去一些不必要的技术,提高效率。#灰度化img
=
cv2.imread("car.jpg",cv2.IMREAD_GRAYSCALE)cv2.imshow("img_gray",img)cv2.waitKey()首先,从计算机中读取一张包含车牌的图像,使用OpenCV的imread函数读取图像,其中cv2.IMREAD_GRAYSCALE表示将读取到的图像转换为灰度图像,然后使用OpenCV的imsow函数将读取并转换为灰度的包含车牌信息的图像显示出来。 这样就完成了车牌识别系统中的第一部,读取车牌图像 由于彩色图像是使用3通道,相比于灰色图像使用单通道来说,所需要的空间也更大,而且图像处理的消耗也比较大。在车牌识别系统中,图像的彩色信息对于车牌的识别影响并不是很大,甚至可以说不需要彩色信息。单通道的灰度图像足够且完全能够获得图像中的车牌信息,为了节省计算机的开销,需要将彩色图像转换为灰度图像。#
均衡化img
=
cv2.imread("car.jpg",
cv2.IMREAD_GRAYSCALE)img
=
cv2.equalizeHist(img)cv2.imshow("img2",
img)cv2.waitKey() 使用OpenCV的imread函数读取图像并且转换为灰度图像,再将灰度图像经过equalizeHist函数进行均衡化,增强原图像的细节信息。 均衡化是一种非常简单而且有效的图像增强技术,它是根据图像的直方图来修改图像中像素的灰度级。可以增强图像的对比度,提高图像的细节信息。原始图像的灰度分布可能是集中在一个非常狭窄的范围,这导致图像很可能不清晰。使用直方图均衡化,可以将原始图像的直方图变换为均匀分布形式,从而增加像素间灰度值差的动态范围,从而达到增强图像整体对比度的效果。直方图均衡化,换句话说,其基本原理是图像中像素的灰度值的数量扩大,和一个小数量的像素的灰度值合并,从而增加对比度,使图像清晰,达到增强的目的。#
高斯滤波img
=
cv2.imread("car.jpg",
cv2.IMREAD_GRAYSCALE)img
=
cv2.equalizeHist(img)img
=
cv2.GaussianBlur(img,
(5,
5),
0)cv2.imshow("img",img)cv2.waitKey() 对均衡化的图像进行高斯滤波、或者均衡滤波,以达到去除图像中的噪声的目标,排除噪声对后续图像处理的干扰。#
边缘检测img
=
cv2.imread("car.jpg",
cv2.IMREAD_GRAYSCALE)img
=
cv2.equalizeHist(img)img
=
cv2.GaussianBlur(img,
(5,
5),
0)img
=
cv2.Canny(img,
127,
255)cv2.imshow("img",
img)cv2.waitKey() 在进行边缘检测之前需要对图像进行滤波,可以排除噪声对图像处理的干扰,如果不进行滤波而直接进行边缘检测,那么噪声会影响边缘检测的效果,甚至噪声将不是边缘的地方也检测为边缘,对后续车牌的定位有很大的影响。4.1.2车牌定位下表是中华人民共和国大陆地区的车牌号的划分,车牌号的划分是按照不同的行政区域来划分的,车牌号的第一个位置是省和直辖市的简称,第二个位置为字母,表示省管辖的各个市,区等信息,后面的位置为字母或数字。在使用基于边缘的方法对车牌区域进行提取时候,因为车牌号码、底色和车身的颜色差异较大,所以能够很容易的确定车牌区域的位置。但是如果采集图像的环境不理想,也可以通过图像增强的方法对图像进行预处理,然后再使用基于边缘的车牌定位方法进行定位。下面是车牌定位的部分源代码def
locate(img):
#
转换为灰度图
gray
=
cv2.cvtColor(img,
cv2.COLOR_BGR2GRAY)
#
均衡化
增强细节
gray
=
cv2.equalizeHist(gray)
#
高斯滤波
去噪
gray
=
cv2.GaussianBlur(gray,
(5,
5),
0)
#
边缘检测
gray
=
cv2.Canny(gray,
127,
255)
#
寻找轮廓(外轮廓)
contours
=
cv2.findContours(gray,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[0]
#
定位后的车牌
targets
=
[]
for
item
in
contours:
#
用最小的矩形将轮廓包围起来
rect
=
cv2.boundingRect(item)
#
当矩形满足某个比例条件时判断为车牌
if
rect[2]
>
rect[3]*2.5
and
rect[2]
<
rect[3]*3.5
and
rect[3]
>
20:
targets.append(cv2.resize(
img[rect[1]:rect[1]+rect[3],
rect[0]:rect[0]+rect[2]],
(190,
60)))
return
targets[0]4.1.3字符分割对分割出来的车牌图像转化为灰度图像,然后再进行边缘检测。但是这时候发现分割出来的车牌图像上还有许多不必要的信息,例如车牌的轮廓和车牌上方的铆钉,这些都会影响后续字符分割和车牌识别的准确率。为了解决上述问题,可以采用直方图的方法来去除铆钉和车牌轮廓。首先对图像进行膨胀,然后再对图像进行腐蚀,膨胀卷积核大小采用5*3,腐蚀卷积核采用3*3,这样可以将单个车牌字符中的间隙连接起来,又可以将每个车牌相互隔绝起来,每个字符独自形成一个整体。然后将像素转化为直方图的信息,分为水平方向和竖直方向。直方图的两个坐标轴分别代表像素的横坐标(纵坐标)和该方向上白色像素的数量。 通过直方图我们可以发现,有2个很明显的波谷,仔细分析发现,这就是车牌图像中车牌的上下边框部分,这时候通过获取这2个部分的坐标值,在原图像中去除这一部分,就完成了车牌铆钉的去除。 用同样的方法,在横轴方向上把坐标和像素统计出来,可以分割出车牌中各个独立的字符。下面是字符分割的部分源代码def
cut(img):
#
转换为灰度图
gray
=
cv2.cvtColor(img,
cv2.COLOR_BGR2GRAY)
#
边缘检测
gray
=
cv2.Canny(gray,
127,
255)
#
膨胀
gray
=
cv2.dilate(gray,
np.ones((5,
3),
np.uint8))
#
腐蚀
gray
=
cv2.erode(gray,
np.ones((3,
3),
np.uint8))
#
裁剪上下边界
y
=
np.sum(gray,
axis=1)
boundry
=
[0,
0]
bias
=
2.5
#
将车牌分成上下2个部分,分别找波谷
for
i
in
range(round(gray.shape[0]/2),
-1,
-1):
if
y[i]
<
average(y)/bias:
boundry[0]
=
i
break
for
i
in
range(round(gray.shape[0]/2),
gray.shape[0]):
if
y[i]
<
average(y)/bias:
boundry[1]
=
i
break
img
=
img[boundry[0]:boundry[1],
:]
return
imgdef
split(img):
#
颜色转换
gray
=
cv2.cvtColor(img,
cv2.COLOR_BGR2GRAY)
#
调整大小并转换为二值图像
img
=
toBin(cv2.resize(gray,
None,
fx=4,
fy=4))
#
边缘检测
gray
=
cv2.Canny(gray,
127,
255)
#
调整大小
gray
=
cv2.resize(gray,
None,
fx=4,
fy=4)
#
转换为二值图像
gray
=
toBin(gray)
#
膨胀
gray
=
cv2.dilate(gray,
np.ones((25,
3),
np.uint8))
#
腐蚀
gray
=
cv2.erode(gray,
np.ones((3,
3),
np.uint8))
#
寻找轮廓(外轮廓)
contours
=
cv2.findContours(
gray,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[0]
rects
=
[]
#
将满足条件的车牌轮廓提取出来
for
item
in
contours:
rect
=
cv2.boundingRect(item)
if
rect[2]
>
20:
rects.append([rect[0],
rect[1],
rect[2],
rect[3]])
#
对提取出来的车牌轮廓按x轴排序
rects
=
sorted(rects,
key=lambda
i:
i[0])
#
保存分割出来的字符
charts
=
[]
for
i
in
rects:
t
=
img[i[1]:i[1]+i[3],
i[0]:i[0]+i[2]]
#
等比调整图像高度为20
t
=
cv2.resize(t,
(round(20*t.shape[1]/t.shape[0]),
20))
#
将图像等比调整成20x20
t
=
adapt(t)
charts.append(t)
return
charts4.1.4字符识别使用神经网络进行车牌字符识别的时候,首先需要建立神经网络,并且用海量的车牌字符图片数据对神经网络进行训练,训练使用的车牌字符图片为20*20的二值图像,所以需要将分割好的车牌字符图像转换成20*20的二值图像,这样才能够输入到神经网络。下面是训练神经网络的部分源代码id
=
["0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"J",
"K",
"L",
"M",
"N",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z"]chinese
=
["川",
"鄂",
"赣",
"甘",
"贵",
"桂",
"黑",
"沪",
"冀",
"津",
"京",
"吉",
"辽",
"鲁",
"蒙",
"闽",
"宁",
"青",
"琼",
"陕",
"苏",
"晋",
"皖",
"湘",
"新",
"豫",
"渝",
"粤",
"云",
"藏",
"浙"]letter=["A",
"B",
"C",
"D",
"E",
"F",
"G","H",
"J",
"K",
"L",
"M",
"N",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z"]def
cnn_number_letter():
train_x
=
np.load("data/number_letter_train_x.npy")
train_y
=
np.load("data/number_letter_train_y.npy")
train_x=train_x.reshape(-1,20,20,1)/255.0
train_x
=
train_x/255.0
model=keras.Sequential()
#卷积层
model.add(keras.layers.Conv2D(32,kernel_size=(5,5),activation="relu",input_shape=(20,20,1)))
#池化层
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=(2,2)))
#卷积层
model.add(keras.layers.Conv2D(64,kernel_size=(3,3),activation="relu"))
#池化层
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=(2,2)))
#卷积层
model.add(keras.layers.Conv2D(128,kernel_size=(3,3),activation="relu"))
#全连接层
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(units=34,activation="softmax"))
pile(optimizer="adam",loss="categorical_crossentropy",metrics=["accuracy"])
model.fit(train_x,train_y,batch_size=5,epochs=50)
model.save("cnn_number_letter_model.h5")def
cnn_letter():
train_x
=
np.load("data/letter_train_x.npy")
train_y
=
np.load("data/letter_train_y.npy")
train_x=train_x.reshape(-1,20,20,1)/255.0
train_x
=
train_x/255.0
model=keras.Sequential()
#
卷积层
model.add(keras.layers.Conv2D(32,kernel_size=(3,3),strides=(1,1),activation="relu",input_shape=(20,20,1)))
#
池化层
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=(2,2)))
#
卷积层
model.add(keras.layers.Conv2D(64,kernel_size=(5,5),strides=(1,1),activation="relu"))
#
池化层
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=(2,2)))
#全连接层
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(units=128,activation="relu"))
model.add(keras.layers.Dense(units=24,activation="softmax"))
pile(optimizer="adam",loss="categorical_crossentropy",metrics=["accuracy"])
model.fit(train_x,train_y,batch_size=5,epochs=50)
model.save("cnn_letter_model.h5")def
cnn_chinese():
train_x
=
np.load("data/chinese_train_x.npy")
train_y
=
np.load("data/chinese_train_y.npy")
train_x=train_x.reshape(-1,20,20,1)/255.0
train_x
=
train_x/255.0
model=keras.Sequential()
#
卷积层
model.add(keras.layers.Conv2D(32,kernel_size=(3,3),strides=(1,1),activation="relu",input_shape=(20,20,1)))
#
池化层
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=(2,2)))
#
卷积层
model.add(keras.layers.Conv2D(64,kernel_size=(5,5),strides=(1,1),activation="relu"))
#
池化层
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=(2,2)))
#全连接层
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(units=128,activation="relu"))
model.add(keras.layers.Dense(units=31,activation="softmax"))
pile(optimizer="adam",loss="categorical_crossentropy",metrics=["accuracy"])
model.fit(train_x,train_y,batch_size=5,epochs=50)
model.save("cnn_chinese_model.h5")
img=cv2.imread("2.jpg",cv2.IMREAD_GRAYSCALE)
img=img/255.0
a=np.asarray(img)
a.resize((1,20,20,1))
print(chinese[np.argmax(model.predict(a))])由于车牌的第一个位置为汉字,第二个位置为字母,其余位置为汉字或者字母。所以将识别的任务分给三个神经网络来完成,三个神经网络分别识别汉字,字母,汉字和字母。将分割好的车牌字符数据按顺序输入到神经网络,第一个车牌字符输入到识别汉字的神经网络,第二个车牌字符输入到识别字母的神经网络,剩下的车牌字符输入到识别字母和数字的神经网络,由于识别过程互不干扰,所以我们可以使用多线程来在同一时间进行多个车牌字符的识别。下面是字符识别的部分源代码iden_result
=
[]class
node:
def
__init__(self,
index,
value):
self.index
=
index
self.value
=
value#
是线程安全的def
identhread(index,
img):
if
index
==
0:
#
识别汉字
#value
=
chinese[np.argmax(model2.predict([img.tolist()])[0])]
a=np.asarray(img)
a=a.reshape((1,20,20,1))
value=chinese[np.argmax(cnn_chinese.predict(a)[0])]
iden_result.append(node(index,
value))
elif
index
==
1:
#
识别字母
#value
=
letter[np.argmax(model3.predict([img.tolist()])[0])]
a=np.asarray(img)
a=a.reshape((1,20,20,1))
value=letter[np.argmax(cnn_letter.predict(a)[0])]
iden_result.append(node(index,
value))
else:
#
识别数字和字母
a
=
np.asarray(img)
a=a.reshape((1,
20,
20,
1))
value
=
id[np.argmax(cnn_number_letter.predict(a)[0])]
iden_result.append(node(index,
value))#
比较函数def
mycmp(n1,
n2):
if
n1.index
<
n2.index:
return
-1
else:
return
1def
identify(charts):
threads
=
[]
iden_result.clear()
result
=
""
for
i
in
range(len(charts)):
charts[i]
=
charts[i]/255.0
t
=
threading.Thread(target=identhread,
args=(i,
charts[i]))
t.start()
threads.append(t)
for
i
in
threads:
i.join()
result_sorted
=
sorted(iden_result,
key=functools.cmp_to_key(mycmp))
for
i
in
result_sorted:
result
=
result+i.valuereturn
result4.2客户端模块4.2.1客户端用户交互界面 客户端程序使用visualstudio开发,为用户提供导入本地图像文件,或导入本地文件夹,将导入的图像传输到服务端进行识别,并由服务端将识别的结果返回到客户端。用户需要输入服务端的IP地址,每次在传输图像时,将要传输的图像发送到目标服务器中。这种设计方法让车牌识别算法和客户端实现了分离,增强了客户端和服务端的可扩展性,减小了系统的耦合性。让服务端可以为不同客户端提供车牌识别的服务,让不同平台的客户端都可以使用车牌识别系统提供的识别服务。 4.5.2网络数据传输 由于车牌识别算法和客户端是2个完全独立的系统,由客户端接收到的图片数据在发送到车牌识别系统中需要经过网络传输,本系统使用Socket编程,将图像的各个像素信息保存到一个数组中,使用Socket将这个数组传送到服务端,服务端在接收到来自客户端发送来的数据,首先先将数组转换成python可以读取的图像数据,然后进行图像的预处理,车牌定位,字符分割,车牌识别等等一系列的计算操作后,将识别出来的结果由刚刚建立起来的连接发送回给客户端。 基于这种设计模式,车牌识别系统可以作为SDK提供给Android,IOS,Linux,等等所有可以发起网络请求的设备所使用。以下是网络传输部分代码publicclassMySocket{ privateSocketserver=null; privateSocketconn=null; publicstringGetData(){ try { byte[]len=newbyte[4]; conn.Receive(len);byte[]data=newbyte[System.BitConverter.ToInt32(len,0)]; conn.Receive(data); returnEncoding.UTF8.GetString(data); }catch(Exceptione){ Console.WriteLine(e.Message); returnnull; } } publicBitmapGetImg(){try{ byte[]len=newbyte[4]; conn.Receive(len); intwidth=System.BitConverter.ToInt32(len,0); conn.Receive(len); intheight=System.BitConverter.ToInt32(len,0); Bitmapimg=newBitmap(width,height); for(inti=0;i<height;i++){ byte[]data=newbyte[width]; conn.Receive(data); for(intj=0;j<width;j++){if(data[j]==0){ img.SetPixel(j,i,Color.Black);}else{ img.SetPixel(j,i,Color.White);}}} returnimg; } catch(Exceptione){ Console.WriteLine(e.Message); returnnull;}} publicvoidSendData(byte[]data){ try{ byte[]len=System.BitConverter.GetBytes(data.Length); conn.Send(len); conn.Send(data); }catch(Exceptione){ Console.WriteLine(e.Message); } } publicvoidSendData(stringdata){ try{ byte[]t=Encoding.UTF8.GetBytes(data);byte[]len=System.BitConverter.GetBytes(t.Length);conn.Send(len); conn.Send(t); }catch(Exceptione){ Console.WriteLine(e.Message); } } publicvoidSendByteData(byte[]data){try{ conn.Send(data);}catch(Exceptione){ Console.WriteLine(e.Messa
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 安徽工业职业技术学院单招职业技能考试题库及答案
- 2026年新疆省高职单招面试题库及答案
- 2026年山东省高职单招综合素质考试试题及答案
- 2026年江苏省高职单招面试考试试题及答案
- 2026年《预防医学》模拟试题及答案(三)
- Spark实时分析平台技术课程设计
- 初中数学的微课程设计
- 单片机温湿度传感器应用课程设计
- 城市拥堵预测算法研究课程设计
- 数控车床加工仿真系统入门应用课程设计
- 《肺叶手术的麻醉》课件
- 一元一次方程和分式方程复习教案 人教版
- 脚手架拆除方案报审
- 2024外贸佣金合同中英文版
- 钻孔灌注桩桩头质量缺陷处理方案样本
- 法院送达地址确认书(诉讼类范本)
- 电子束曝光技术专题培训课件
- TDTG5024斗式提升机机座及总体部分设计
- 3%水泥土试验段施工方案
- GB/T 36174-2018金属和合金的腐蚀固溶热处理铝合金的耐晶间腐蚀性的测定
- 第二章常用低压电器基本原理课件
评论
0/150
提交评论