图像处理车牌 填充_数字图像处理车牌识别 - CSDN
  • 基于图像处理的汽车牌照的识别作者:陈秋菊指导老师:李方洲 (温州师范学院 物理与电子信息学院 325027) 摘要:以一幅汽车牌照的识别为例,具体介绍了车牌自动识别的原理。整个处理过程分为预处理、边缘提取、车牌...

               

     

    基于图像处理的汽车牌照的识别

    作者:陈秋菊

    指导老师:李方洲

                 (温州师范学院 物理与电子信息学院  325027)

     

    摘要:以一幅汽车牌照的识别为例,具体介绍了车牌自动识别的原理。整个处理过程分为预处理、边缘提取、车牌定位、字符分割、字符识别五大模块,用MATLAB软件编程来实现每一个部分,最后识别出汽车牌照。在研究的同时对其中出现的问题进行了具体分析,处理。寻找出对于具体的汽车牌照识别过程的最好的方法。

     

    关键词汽车牌照 车牌提取 字符分割  字符识别

     

    The vehicle license recognition based on the image processing

             Author:Chen Qiuju

                Tutor:Li Fangzhou

    (School of Physics and Electronic Information   Wen Zhou Normal College  325027)

    Abstract With one vehicle license recognition, the principle of the automobile License recognition is introduced .This process was divided into pre-process, edge extraction, vehicle license location, character division and character recognition, which is implemented separated by using MATLAB. The license is recognized at last. At the same time, the problems are also analyzed

    And solved in the process. The best method of recognition to the very vehicle license is found.

     

    Keywords: vehicle license   vehicle license location   character segmentation

    Character  recognition

                 

     

     

     

     

     

     

     

     

    1. 引言

    1.1 选题意义

       汽车牌照自动识别系统是以汽车牌照为特定目标的专用计算机视觉系统,是计算机视觉和模式识别技术在智能交通领域应用的重要研究课题之一,是实现交通管理智能化的重要环节,它可广泛应用于交通流量检测,交通控制与诱导,机场、港口、小区的车辆管理,不停车自动收费,闯红灯等违章车辆监控以及车辆安全防盗等领域,具有广阔的应用前景。目前,发达国家LPR汽车牌照识别技术License Plate Recognition LPR,简称“车牌通”)系统在实际交通系统中已成功应用,而我国的开发应用进展缓慢,车牌识别系统基本上还停留在实验室阶段基于这种现状还有它广阔的应用前景,目前对汽车车牌的识别研究就有了深远的意义。

                课题组成

    汽车车牌的识别过程主要包括车牌定位、字符车牌分割和车牌字符识别三个关键环节。其识别流程如下:

    字符识别  

    字符分割 

    车牌定位  

    边缘提取  

    图像预处理  

    原始图像   

                                                                      

     


    原始图像  :由数码相机或其它扫描装置拍摄到的图像

    图像预处理:对动态采集到的图像进行滤波,边界增强等处理以克服图像干扰

    边缘提取  :通过微分运算,2值化处理,得到图像的边缘

    车牌定位  :计算边缘图像的投影面积,寻找峰谷点,大致确定车牌位置,再计算此连通域内的宽高比,剔除不在域值范围内的连通域。最后得到的便为车牌区域。

    字符分割  :利用投影检测的字符定位分割方法得到单个的字符

    字符识别  :利用模板匹配的方法与数据库中的字符进行匹配从而确认出字符,得到最后的汽车牌照,包括英文字母和数字。

    本文以一幅汽车图像为例,结合图像处理各方面的知识,利用MATLAB编程,实现了从

    车牌的预处理到字符识别的完整过程。各部分的处理情况如下:

     

     

     

     

     

     

     

     

     

     

     

     

    2.预处理及边缘提取

     

                              1 汽车原图

       图像在形成、传输或变换过程中,受多种因素的影响,如:光学系统失真、系统噪声、暴光不足或过量、相对运动等,往往会与原始景物之间或图像与原始图像之间产生了某种差异,这种差异称为降质或退化。这种降质或退化对我们的处理往往会造成影响。因此在图像处理之前必须进行预处理,包括去除噪音,边界增强,增加亮度等等。

    因为噪声主要是一些含高频的突变成分,因此可以通过一个低通滤波器来消除图像中包含的噪声,并使低频成分得到增强。滤波的方式有两种,一种是空间域滤波,一种是频率域滤波。在空间域,常见的滤波方式有两种方式,均值滤波和中值滤波。空间域滤波主要有巴特沃斯滤波器。在车牌边缘提取之前,两种滤波方式均采用了。并与未进行滤波的边缘进行比较。以下是经处理后的一些图片。

            2  经均值滤波后提取的边缘图像

           3 经巴特沃斯低通滤波后提取的边缘图像

              4 未滤波直接提取出的边缘信息

        

              5 经高通滤波器增强后得到的边缘图像

       对比以上几幅图片,图2的边缘太粗,而图3的边缘已经模糊掉了。图5中包含的噪声太多,图4未经滤波直接提取出的边缘图像最清晰,所包含的有用信息最多。分析这种情况产生的原因,归纳起来主要有以下方面:

      1、原始图像清晰度比较高,从而简化了预处理

      2、图像的平滑处理会使图像的边缘信息受到损失,图像变得模糊

      3、图像的锐化可以增强图像中物体的边缘轮廓,但同时也使一些噪声得到了增强

      综上所述,结合MATLAB实验过程,得出不是每一种图像处理之初都适合滤波和边界增强。本次汽车车牌的识别,为了保存更多的有用信息,经过多次比较,选择图4作为后期处理的依据。边缘的提取采用的是梯度算子,因为其实现过程比较简单,所以在此不多加赘述了。

      提取出的边缘含有多个灰度值,要进行二值化处理,选择一个合适的域值。经多次比较,选取域值T=70,对于灰度值大于T的赋值为255,小于T的赋值为0。经过处理后的图像如下所示:

     

                6 二值化后的边缘图像

    结合后期分割得到的车牌图7,二值化后的图像在后期的识别中并不会提高车牌的识别率,因此不采用二值化的图像来进行识别,因此后面的处理依然使用图4

    3.车牌提取

        经过边缘提取得到的图像,车牌区域在水平方向灰度面积值具有明显频繁的跳变,在垂直方向上的面积投影则出现峰--峰的特性。根据这种峰谷特点,自动检测车牌位置峰点检测的车牌区域定位方法并对初步定位后的车牌进一步使用微定位技术该方法包括三部分: (1) 车牌的横向定位 (2)车牌的纵向定位 (3) 车牌的微定位。

       汽车本身具有一定的特点一般情况下牌照都挂在缓冲器上或附近处于车牌照图像的下半部分本次分割的主要意图是缩小牌照搜索范围大致确定出牌照的位置。对如图4所示的汽车边缘图像f ( x y) 我们首先进行水平方向一阶差分运算

    g ( i j) = | f ( i j) - f ( i j + 1) |

    其中i = 1 2 3 xw - 1 j = 0 1 2 3 yw - 1 ,其中xwyw分别为图像的行数和列数。然后对水平差分图像的像素沿水平方向累加产生一个投影表T( i) 如图7所示。

                   7 汽车边缘图像的水平面积投影图

    一般对应于车牌位置的投影值T( i) 较大而在车牌上下行附近的投影值较小均有谷点存在。只要能找到这两个谷点就能大致确定出车牌照的位置缩小车牌搜索范围。由图4可以看出,车牌下方的横栏处的T(i)值应该是最大的,而车牌位置就在其附近。根据这些特定,可定出车牌位置大概在320~350行之间。

      类似的方法得出汽车边缘图像的垂直面积投影图

                  8 汽车边缘图像的垂直面积投影图

       同上可初步得到汽车牌照的列位置在120~210之间。大致确定的牌照位置如下图。

                     

                      9 粗略定位出的汽车牌照

    对初步确定出来的牌照进行微定位,所谓微定位法就是对基本定位后的车牌图像进

    行局部分析以进一步确定字符范围缩减车牌的左、右和上、下边界这有利于后续的牌照字符处理。具体实现如下: (1) 由于车牌近似为一个矩形上下边缘近似为一条直线通过简单的灰度变化分析就可以再次定位车牌图像的上下边界这种情况适合于倾斜度较小的车牌对于倾斜程度较大的牌照来说在其横向定位之前就应该利用相关的技术进行车牌的矫正(例如Hough 变换技术) (2)确定左边界: 从左向右扫描 ,当遇到灰度值大于设定值60之后,停止扫描。上边界也是利用这种方式得到。这样就得到首字符的起始位置。再利用牌照的大小,宽高比一般都是固定的这些先验知识,就可以确定出牌照的具体位置。本设计中采用的车牌,其宽高比为1:3。从而确定出汽车牌照的具体位置。最后提取出的汽车牌照如下图:

    10 二值化的汽车牌照

                     

    11 未进行二值化的汽车牌照

    4.字符分割

    在汽车牌照自动识别过程中,字符分割有承前启后的作用。它在前期牌照定位的基础

    上进行字符的分割,然后再利用分割的结果进行字符识别。字符识别的算法很多,常采用垂直面积投影法来实现。面积投影法的公式如下:

                

    由于字符块在竖直方向上的投影必然在字符间或字符内的间隙处取得局部最小值,并且这个位置应满足车牌的字符书写格式、字符尺寸和其他一些条件的限制。下图是图10在垂直方向上的面积投影图。从图形中我们很直观的看出投影值中出现了8条间隙, 6个字母中间的间隙只有5个,还有三个间隙是字符间的。有字符的列其灰度值比较高,无字符的则相对比较低。依据这一点,再结合图10的特征,很容易得到每个字符的起始终止位置。第一个字符:1-10 第二个字符:10-18 第三个字符:28-41 第四个字符:42-48第五个字符:60-68 第六个字符:68-78

      

                         12 车牌垂直方向上的面积投影图

      将图10按照上面的分析行数不变,列数分为六组,分别影射到六个不同的数组中。又因为在字符的模式识别中,其模板大小统一,因此得到的六个数组必须变换其大小,均统一成26×14的形式。分割出来的六个字符如下所示,分别命名为M1.jpgM2.jpgM3.jpgM4.jpgM5.jpgM6jpg并用imwrite函数写入图像文件夹中,以便在后期处理中可以直接进行调用。

                                    

                           12 分割出来的六个字符图像

    一般分割出来的字符要进行进一步的处理,以满足下一步字符识别的需要。因为图像中含有许多燥声,这在预处理的图像中已经看出来了。因此必须进行滤波,然后归一化,二值处理。使其最后得到的图像与标准模板一样。只含有两种灰度值,黑与白。但是对于车牌的识别,并不需要这么多的处理就已经可以达到正确识别的目的。在此简化了处理过程,未经滤波归一化,直接进行后期处理。

    5.字符识别

    字符的识别目前用于车牌字符识别(OCR)中的算法主要有基于模板匹配的OCR算法以及基于人工神经网络的OCR算法。基于模板匹配的OCR的基本过程是:首先对待识别字符进行二值化并将其尺寸大小缩放为字符数据库中模板的大小,然后与所有的模板进行匹配,最后选最佳匹配作为结果。用人工神经网络进行字符识别主要有两种方法:一种方法是先对待识别字符进行特征提取,然后用所获得的特征来训练神经网络分类器。识别效果与字符特征的提取有关,而字符特征提取往往比较耗时。因此,字符特征的提取就成为研究的关键。另一种方法则充分利用神经网络的特点,直接把待处理图像输入网络,由网络自动实现特征提取直至识别。模板匹配的主要特点是实现简单,当字符较规整时对字符图像的缺损、污迹干扰适应力强且识别率相当高。综合模板匹配的这些优点我们将其用为车牌字符识别的主要方法。

     

    字符识别的算法如下:

                       

    读入字符图像

       

     

     


    与模板库中的字母逐一进行相关运算

                

     

     

    寻找相关度最大值所对应的模板

     

     


                     

     

    输出此模板所对应的值

     

     

     

     


      因此在字符识别之前必须把模板库设置好。汽车拍照的字符一般有七个,大部分车牌第一位是汉字,通常代表车辆所属省份,或是军种、警别等有特定含义的字符简称;紧接其后的为字母与数字。车牌字符识别与一般文字识别在于它的字符数有限,汉字共约50多个,大写英文字母26个,数字10个。所以建立字符模板库也极为方便。本次设计所识别的车牌只有字母与数字。为了实验方便,结合本次设计所选汽车牌照的特点,只建立了3个字母与3个数字的模板。其他模板设计的方法与此相同。

    5.1模板设计

    分析字符分割得到的图像以及其他车牌图像中字符的特点,将模板大小定为26×14

    背景为黑色,代表灰度值 0,字符边缘为白色。代表灰度值255

    设计过程如下:

    1.  用画图工具先画出PFM103等几个字符的图像。并分别保存为m11.jpgm12.jpg

    M1.jpgm14.jpgm15.jpgm16.jpg。根据画图的经验其大小应略大于26×14,以利于后面的处理。所得到的字符均为黑字白底。字体为方正姚体,大小16号。

    所画出的图形如下:

    2.     1中获得的粗略图像用MATLAB进行处理。处理的方面包括a.去除边框,利用二维数组的映射关系实现,去掉开始行()与结束行()即所有外围像素点b.提取模板的边缘。其实现方法与前面的汽车边缘提取的方法相同,也是利用梯度算子。C.尺寸大小变换,切割为标准的26×14格式。

    3.     整个处理过程结束后,再用imwrite 函数写入图像库中,作为标准模板使用。

    经过处理后的标准模板形式如下:

                                 

    模板的设计过程,共进行了两次。作为一幅jpg或者bmp形式的图片,其中包含了许许

    多多的像素点,各象素点的值也不一样,到底如何来确定这些像素点的值呢?模板设置无疑成为一个难点。于是便投机取巧,将本身分割得到的字符保存起来直接作为模板使用。这种方法明显不具有科学性。图像识别中模板匹配法是将未知的东西与已知的东西来进行比较。因此模板库中的字符应该是已知的,是预先设置好的是不可更改的,而不是在实验过程中来得到。第二次便是用以上的画图工具来一步一步逼近实现模板设置。实验结果显示,这种方法简单易行。

    5.2识别过程

      字符识别中模板匹配方法是实现离散输入模式分类的有效途径之一,其实质是度量输入与样本之间的某种相似性,取相似性最大者为输入模式所属类别,它根据字符的直观形象抽取特征,用相关匹配原理进行识别,即是将输入字符与标准字符在一个分类器中进行匹配。车牌字符相关匹配算法如下:

       输入字符用输入函数X表示,标准模板用函数T表示,它们的大小均为26×14。将未知的模式逐个与模板匹配,求出其相似度。

      

              

          

      其中,M=26N=14Ti  指第i个模板。X×Ti 是指矩阵对应元素相乘。如果把XT都归一化为1”0”,则上式表示标准模板与待识图像上对应点均为1”的数目与标准模板上1”点的数目之比。

      如果 maxSi>λ 则判定XTi,否则拒识,这里λ为拒识域值。本次实验中直接取相关最大值为判定域值。

      MATLAB来实现字符的识别。其中有两个很重要的函数可以直接调用:corr2 函数和max函数。

      Corr2 函数直接用来计算图像拒阵AB的相关系数rAB的大小及数据类型必须相同,得到的结果r是双精度标量。其调用方法如下:

                    r=corr2(AB)

      因此本设计中的字符识别只需调用此函数,即将分割出来的字符与设置好的模板一一进行相关运算,然后寻找出它们中的最大相关值。max函数就是用来选择几个数值的大小值。其调用方式如下:

                    [bc]=max(a(:))

      其中b返回的是比较后得到的最大值,c是最大值所对应的元素位置。

    同时还自编了一个识别函数result.m用来返回识别结果。程序代码如下:

      function c=result(H)

    M1=imread('M1.jpg')

    M2=imread('M2.jpg')

    M3=imread('M3.jpg')

    M4=imread('M4.jpg')

    M5=imread('M5.jpg')

    M6=imread('M6.jpg')

    M1=double(M1)

    M2=double(M2)

    M3=double(M3)

    M4=double(M4)

    M5=double(M5)

    M6=double(M6)

    d=zeros(6)

    d(1)=corr2(HM1)

    d(2)=corr2(HM2)

    d(3)=corr2(HM3)

    d(4)=corr2(HM4)

    d(5)=corr2(HM5)

    d(6)=corr2(HM6)

    [De]=max(d(:))

    switch e

        case 1

            c='P'

        case 2

            c='F'

        case 3

            c='M'

        case 4

            c=1

        case 5

            c=0

        case 6

            c=3

        otherwise

    end

       M1 M2 M3 M4 M5 M6为标准模板对应的二维数组。函数在开始运行时,从主函数里得到待识别的字符,此字符与模板进行相关运算,同时找出相关运算后的最大值及对应的函数位置。然后对最大位置进行判别,返回所对应的字符给主程序。并在MATLAB运行窗口显示出来。

      编写result.m函数大大简化了计算量,每个字符在识别的时候直接调用此函数,避免了重新编程浪费的时间及空间。这是本次车牌识别中的一大亮点

      运行结果,MATLAB的运行窗口显示出的车牌号码为:PFM103。完成了准确识别车牌的目的。

    6.总结:

      6.1 设计过程说明

      在汽车车牌识别的整个过程中,查找了很多资料,综合了各方面的信息。车牌实现的每一步都有许多的方法,各种方法都有其优劣,但是对于具体的图像处理,并不是每一种理论在实践中都可以实现,即使实现了也很难说哪一种方法最合适,还得在具体的实验中比较选择。以车牌预处理为例,经过滤波和边界增强处理后提取出的车牌效果明显没有未处理的效果理想。第二点在程序调试的过程中要耐心的检查每一个错误。测试结果表明,本设计有以下几条优点:

    1.     充分利用MATLAB中已有的函数库。整个程序设计简单易行

    2.     识别准确率高

    62设计工具说明:

      车牌识别程序设计能够得以顺利完成。在很大程度上得利于MATLAB这套软件, MATLAB功能强大,它包括数值计算和符号计算,并且计算结果和编程可视化。这为编程调试创造了一个便利的环境。作为图像处理最适用的工具之一,其突出的特点是它包含一个图像处理工具包,这个工具包由一系列支持图像处理操作的函数组成。所支持的图像处理操作有:图像的几何操作、邻域和区域操作、图像变换、图像恢复与增强、线性滤波和滤波器设计、变换(DCT 变换等) 、图像分析和统计、二值图像操作等。在图像的显示方面,MATLAB 提供了图像文件读入函数imread ( ) 用来读取如: bmp tif jpgpcxtiff jpeghdf xwd 等格式图像文件图像写出函数imwrite () 还有图像显示函数image ( ) imshow() 等等。这些,都使编程效率大为提高。

    7.讨论

       本设计已成功达到了车牌识别的目的,而且准确率也很高。但是在整个设计过程中,发现了几个值得参考的算法,也试图用这种算法来实现车牌识别,但种种原因,而未采用。现在次简单讨论一下:

      6.1.8个方向的模板的边缘提取算法

    本设计在边缘提取之时,使用的是梯度算子。这种算法的优点是简单易行,但是因为它不包含边缘的方向,因此对噪声不够敏感。目前,在图像处理方面使用得最多的是一种可抗噪声的Sobel算法。它定义了8个方向的模板。

                   

    通常物体的边缘是连续且光滑的,而噪声是随机的。 在任一边缘点附近沿边缘的走向总能找到另一边缘点,且这两边缘点之间的灰度差及方向差都不可能很大。但是噪声则不同,一般情况下,沿任一噪声点的方向(通过上述模板运算得到)不太可能找到与其灰度差及方向差都很小的噪声点。正是利用这一基本思想,本算法能将实际的边缘点与噪声点区分开来。

    加权领域平均算法来进行滤波处理

     62 加权领域平均算法来进行滤波处理

     由实验我们可以看出,一般的滤波器在对图像进行噪声滤除的同时对图像中的细节部分有不同程度的破坏,都不能达到理想的效果。但是采用加权的邻域平均算法对图像进行噪声滤除不仅能够有效地平滑噪声还能够锐化模糊图像的边缘。 加权的邻域平均算法的基本思想是: 在一个邻域内除了可以利用灰度均值外灰度的上偏差和下偏差也能够提供某些局部信息。算法的计算公式描述如下f (x y ) 表示原始图像g (x y ) 为平滑后点(x y ) 的灰度值V x y 表示以点(x y ) 为中心的邻域该邻域包含N 个象素m (x y ) 表示邻域V x y 内的灰度均值。NI表示邻域内大于平均值的像素个数,Ng表示小于平均值的像素个数,而N0表示等于平均值的像素个数。则修正的邻域平均法由下式给出:

     

    m - Aı m lN l > max{N g N 0}

    g(xy)=   m + Aı m gN g > max{N l N 0}            (1)

    m    else

     

     (1)(1) A为修正系数取值范围为01其大小反映V x y 中的边缘状况。 以上是我认为在图像处理中比较有价值的两点,有兴趣的可以上网查阅相关的资料。

    【参考文献】

    [1] 霍宏涛.数字图像处理.机械工业出版社,2003.5

    [2] 陈桂明、张明照、戚红雨.应用MATLAB语言处理数字信号与数字图像。科学出版社,2000

    [3] 郎锐.数字图象处理学Visual C++实现.北京希望电子出版社,2002.12

    [4] 刘露、强.汽车牌照自动识别技术初探,中国公路网,2003-09-26

    [5] 周妮娜、王敏、黄心汉、吕雪峰、万国红.车牌字符识别的预处理算法.计算机工程与应用,2003(15)

    [6] 佘新平、朱 立.一种具有抗噪声干扰的图像边缘提取算法的研究2001-6-4

    [7] 苑玮琦、伞晓钟. 一种汽车牌照多层次分割定位方法,2004 Vol.9 No.4 P.239-243

    [8] 许志影李晋平.MATLAB极其在图像处理中的应用.计算机与现代化,2004(4)

    [9] 董慧颖、曹仁帅.汽车牌照自动识别系统中字符分割算法研究.沈阳工业学院学报2003(12)Vol.22 No.4

    [10] 崔 江王友仁.车牌自动识别方法中的关键技术研究.计算机测量与控制,2003.11(4)

    [11] 王年、李婕、任彬、汪炳权.多层次汽车车牌照定位分割方法. 安徽大学学报,1999(6)Vol.23.No.2

    [12] 马俊莉莫玉龙王明祥.一种基于改进模板匹配的车牌字符识别方法.小型微型计算机系统Vol.23.No.2

      

     

     

     

     

     

     

     

     
    展开全文
  • 本次《数字图像处理》课程作业要求使用数字图像处理技术自动定位,分割和识别车牌。其中数据需要使用老师提供的数据(50张车牌图片),尽量使用课程中老师讲授的传统的数字图像处理领域的知识,不使用深度学习(除非...

    自动定位、分割、识别汽车车牌

    1 实验内容与目的

    本次《数字图像处理》课程作业要求使用数字图像处理技术自动定位,分割和识别车牌。其中数据需要使用老师提供的数据(50张车牌图片),尽量使用课程中老师讲授的传统的数字图像处理领域的知识,不使用深度学习(除非仅仅使用老师提供的数据集)。

    2 方法概述

    整个算法的流程见下表:

    序号 步骤
    1 图像的预处理
    2 车牌粗定位
    3 车牌精定位
    4 车牌区域切割
    5 字符切割
    6 字符识别

    2.1 图像的预处理

    由于老师所给的数据集中每一种车牌的背景颜色不同,有白色的车牌、黄色的车牌以及最常见的蓝色的车牌,所以这里对于不同背景颜色的车牌进行分开讨论。我们在这里使用背景为蓝色的车牌举例说明图像预处理的部分。
    首先考虑到待识别的图片的背景比较复杂,并且有较多的噪声,所以这里将RGB像素值比较低的彩(蓝)色噪声去掉,防止噪声对于后续操作的干扰。
    然后接着将蓝色的区域进行提取,并在灰度图中尽量显示出来,这里提取的方法主要使用的是蓝色的RBG值为(0,0,255)。然后再对于蓝色提取后的区域进行归一化,并使用二值化的函数进行二值化的操作,从而的到原图像对应的灰度(二值化)图像。
    接着对于以上的二值化的图像(二维的二值化图像)进行连通区域的标记,这里是为了找到“蓝色”区域中面积最大的区域,并将其初步认为其是车牌所在的区域,并使用函数对于连通区域的属性进行度量,来判断具体哪一个区域为蓝色所标记的区域。再对于这些区域的面积进行排序,将面积比较大的区域进行初步的标记。
    选择得到初步的车牌位置后需要对于图像进行闭运算,使用因为使用闭运算可以使得轮廓线更为光滑,而且可以消弥狭窄的间断和长细的鸿沟,消除小的空洞,并填补轮廓线中的断裂,这样就可以将车牌中的字体(通常在一个图片中面积比较小)也纳入到上面所标记的所谓的车牌的区域中。
    进行完成图像聚类(图像的闭运算,填充图像后),我们再一次对于连通的区域进行标记,与上一次操作不同的是,这里我们仅仅选择面积最大的区域作为我们所认定的暂时的车牌区域,并将此二值化的图片(矩阵)送入下一个“车牌的粗定位”步骤中进行进一步的操作。
    其实这一步的图像预处理等价于使用了形态学滤波的方法进行了图像的预处理工作。

    2.2 车牌粗定位

    这里的粗定位的方法其实可以与上一步联系在一起,因为其实在图像的预处理中已经找到了车牌的位置,这里的车牌粗定位的工作是确定行的起始位置和终止位置,以及列的起始位置和终止位置,并将其原来的彩色图像恢复,用于下一步真正的细定位的工作。
    具体的做法是,首先为了不改变图像的分辨率,将其变更为double类型的图片。
    接着,首先确定行的起始位置和终止位置,这里将图像预处理工作得到的结果在横向上进行了加和,由于是二值化的图像,所以只有0和1两个数值,所以可以很明显的在通过统计的曲线看出黑白区域的边界部分,从而可以比较好的确定具体的行的起始位置和终止位置。
    然后确定列的起始位置和终止位置,这里将图像预处理工作得到的结果在纵向上进行了加和,由于是二值化的图像,所以只有0和1两个数值,所以可以很明显的在通过统计的曲线看出黑白区域的边界部分,从而可以比较好的确定具体的列的起始位置和终止位置。
    最终,通过行列的统计结果,即标记的行列的终止和起始的位置,从原彩色图片中切割出粗定位后的图片,并予以显示。

    2.3 车牌精定位

    接下来是图片精定位的工作,由于上一步骤中图像的粗定位中仍然存在一下的问题:首先是角度不一定是水平的,这是因为数据本身的拍摄角度不同,有很多的照片使用前面的粗定位和图像预处理后,整个的车牌的角度并不是水平,这就会对于以后的字符切割工作造成麻烦,所以进行角度的旋转是很必要的;另外一方面,我们还需要对于水平的图像进行裁剪。期间每进行完一次的操作后,都是用直方图对于操作后的结果进行分析。
    首先进行角度变换之前,要进行如下的操作,由于取得的是车牌粗处理的图片,首先进行resize将不同大小的区域都resize为同样大小的区域;接着进行二值化和形态学的开操作,一个开操作是一个腐蚀操作再接着一个膨胀操作使用相同的结构元素。这样可以求得图片的主要的特征,并且将噪声进一步的去除。然后再找出图像的主要目标以及其对应的最大的连通区域。
    接下来我们可以根据以上操作的结果来进行角度的变化,这里的角度变换的前提是车牌粗定位的时候,边界的区域比较精确而且完全近似于矩形,这里我们直接使用MATLAB自带的函数计算矩形的长边长与水平方向的夹角,从而得到需要的旋转角度,再使用MATLAB自带的图像旋转工具进行图像的旋转。
    由于经过旋转后的图像的分辨率会下降很多,所以这里我继续对于旋转后的图片进行了基于形态学的开运算。
    最后将最终的图像进行切割,得到最终的车牌精定位的结果,并把结果转换为二值化的图像,方便以后的字符识别。在过程中,我每操作一步都会使用直方图检验分割的效果。

    2.4 车牌区域切割

    上步骤中的车牌精定位的效果达到了预期的目标,但是在图像的周围还是存在“黑边”这对于后续的字符的识别会产生严重的干扰,所以我们还是需要“真正”体现车牌信息的区域进行切割。
    这里考虑的方法就是,在横向最左和最右端分别以一个像素的步长向中心移动,直到遇到“白色”的像素值,这里为了防止“白色”噪声的干扰,通过设置阈值或者说是形态学直方图的阈值对于条件进行判断,从而增加模型的鲁棒性能。在纵向也相同,最上端和最下端分别以一个像素的步长向中心移动,直到遇到“白色”的像素值,这里为了防止“白色”噪声的干扰,通过设置阈值或者说是形态学直方图的阈值对于条件进行判断,从而增加模型的鲁棒性能。
    经过“车牌区域切割”的操作后,我们得到的就是完整并且不带任何“边界”的纯车牌信息了。

    2.5 字符切割

    经过上面的四步骤,我们得到了完整并且不带任何“边界”的纯车牌图片,所以接下来进行字符的切割操作。
    这里的字符切割完全考虑到的是单行的车牌的识别,对于数据集中出现的两行的车牌暂时没有考虑这种情况。
    算法中首先需要计算得到区域中有多少个文字出现,这里考虑的是使用计算连通区域的方法,与图像预处理的想法基本一致,计算有多少个面积大于一定阈值的连通区域就确定为多少个文字(英文字母)出现,另外一点,一般的车牌的文字+字母+数字的个数不会超过8个,所以这里我将连通区域的数目规定为小于8个。
    然后我们使用MATLAB自带的函数对于连通区域进行判断与定位,并将其初步使用bbox进行定位。接着对于所有的bbox分别计算他们在水平和竖直方向上的长度,并将这个平均长度视为每一个文字区域的长度,在竖直方向也一样,将平均的宽度视为每一个文字区域的宽度。但是对于水平方向还需要如下的进一步细分,还是判断在每一个文字区域内的连通区域,一般来说如果分类正确应该在每一个文字区域中只有一个连通区域(这里的中文由于进行了开运算,也是可以看作为一个连通区域,即使文字出现了偏旁部首)。如果发现了多个(一般为两个或者三个)连通区域,那么就将切割范围在水平方向上进行细微的调动,直到完成每一个文字中有且只有一个连通区域的目标。
    这样我们就可以定位到每一个文字区域的边界点(定位点),从而进行切割操作。这里为了方便,我们将切割的目标区域的数量定位7个。因为一般的车牌号码是:省的简称+一个字母(两个字母)+五个数字(四个数字)组成的。这样我们将最终切割得到了7个文字区域交给下一个字符识别来进行。

    2.6 字符识别

    由于不能使用现成的OCR以及深度神经网络进行这里的字符识别,严格来说是字符的匹配。其中匹配的模板是自己切割的数字0-9是个数字以及a-z这26个字母,其中这里的字母I和O因为在车牌中和数字1和0基本完全相同,所以这里没有识别字母I和字母O的,这里一切都是直接使用数字1和数字0来代替。
    我们这里将识别汉字和识别数字、字母分开来看,首先来看数字和字母的识别。
    我们如果默认车牌是由7个字符组成的,即省的简称+一个字母(两个字母)+五个数字(四个数字)组成的话,那么后六个应该就是数字以及字母的位置。这里考虑首先对于切割出来的每一个字符区域与数字+字母的模板(切割的数字0-9是个数字以及a-z这26个字母),进行点乘,其目的在于进一步匹配两者的近似程度,还有一个细节是,我自己制作的模板与前一步分割出来的字符正好的相反的,即模板的“黑色”区域是切割出来字符的“白色”区域,所以在进行点乘之前需要先将区域进行二值化的反转操作,使用阈值为0.5的反转函数就可以轻易的实现。进行点乘完后,我们对于点乘后的图片(矩阵),再进行连通区域的标定,并且计算出其最大的面积,使用这个最大的面积与模板在进行MSE的计算,对于一个字符区域与每一个模板进行上述的操作,从中找到一个MSE最小的标定块,并认为其就是与字符相同的模板。这也就达到了识别的效果。不过这一切识别正确的前提是,之前的图像预处理、车牌的细分割以及最后的字符的分割做的准确无误。
    接下来是汉字的识别。我们如果默认车牌是由7个字符组成的,即省的简称+一个字母(两个字母)+五个数字(四个数字)组成的话,那么第一个区域应该就是数字以及字母的位置。其中一个细节是,我自己制作的模板与前一步分割出来的字符正好的相反的,即模板的“黑色”区域是切割出来字符的“白色”区域,所以在进行操作之前需要先将区域进行二值化的反转操作,使用阈值为0.5的反转函数就可以轻易的实现。在这里我首先对于字符进行较为微弱的腐蚀运算接着使用这个字符区域与每一个中文字符模板进行MSE的计算操作,最终MSE最小的模板就直接认为其是正确的模板,并认为其就是与字符相同的模板。这也就达到了识别的效果。不过这一切识别正确的前提是,之前的图像预处理、车牌的细分割以及最后的字符的分割做的准确无误。
    所以模型最后的字符识别成功,关键在于前面定位以及分割算法的精细程度以及准确率。

    3 源代码的解释与说明

    3.1 图像预处理源代码说明

    图像预处理算法的源代码在rgb2filtered.m文件中。
    首先考虑到待识别的图片的背景比较复杂,并且有较多的噪声,所以这里将RGB像素值比较低的彩(蓝)色噪声去掉,防止噪声对于后续操作的干扰。然后接着将蓝色的区域进行提取,并在灰度图中尽量显示出来,这里提取的方法主要使用的是蓝色的RBG值为(0,0,255)。主要的实现代码如下:
    在这里插入图片描述
    然后再对于蓝色提取后的区域进行归一化,并使用二值化的函数进行二值化的操作,从而的到原图像对应的灰度(二值化)图像。
    在这里插入图片描述
    接着对于以上的二值化的图像(二维的二值化图像)进行连通区域的标记,这里是为了找到“蓝色”区域中面积最大的区域,并将其初步认为其是车牌所在的区域,并使用函数对于连通区域的属性进行度量,来判断具体哪一个区域为蓝色所标记的区域。再对于这些区域的面积进行排序,将面积比较大的区域进行初步的标记。
    在这里插入图片描述
    选择得到初步的车牌位置后需要对于图像进行闭运算,使用因为使用闭运算可以使得轮廓线更为光滑,而且可以消弥狭窄的间断和长细的鸿沟,消除小的空洞,并填补轮廓线中的断裂,这样就可以将车牌中的字体(通常在一个图片中面积比较小)也纳入到上面所标记的所谓的车牌的区域中。
    在这里插入图片描述
    进行完成图像聚类(图像的闭运算,填充图像后),我们再一次对于连通的区域进行标记,与上一次操作不同的是,这里我们仅仅选择面积最大的区域作为我们所认定的暂时的车牌区域,并将此二值化的图片(矩阵)送入下一个“车牌的粗定位”步骤中进行进一步的操作。
    在这里插入图片描述
    同样的方法如果是黄色背景或者其他颜色的背景,可以直接将提取的颜色设置为需要的RGB颜色即可,另一方面,为了鲁棒性的优势,这里可以将RGB的提取范围扩大,从而将更多的区域归入其中,从而提高识别的效率和准确性等程度。

    3.2 车牌粗定位源代码说明

    车牌粗定位的源代码在rough_locate.m文件中。
    这里的粗定位的方法其实可以与上一步联系在一起,因为其实在图像的预处理中已经找到了车牌的位置,这里的车牌粗定位的工作是确定行的起始位置和终止位置,以及列的起始位置和终止位置,并将其原来的彩色图像恢复,用于下一步真正的细定位的工作。
    首先是确定行的起始位置和终止位置,这里将图像预处理工作得到的结果在横向上进行了加和,由于是二值化的图像,所以只有0和1两个数值,所以可以很明显的在通过统计的曲线看出黑白区域的边界部分,从而可以比较好的确定具体的行的起始位置和终止位置。
    在这里插入图片描述
    然后确定列的起始位置和终止位置,这里将图像预处理工作得到的结果在纵向上进行了加和,由于是二值化的图像,所以只有0和1两个数值,所以可以很明显的在通过统计的曲线看出黑白区域的边界部分,从而可以比较好的确定具体的列的起始位置和终止位置。
    在这里插入图片描述
    最终,通过行列的统计结果,即标记的行列的终止和起始的位置,从原彩色图片中切割出粗定位后的图片,并予以显示。
    在这里插入图片描述

    3.3 车牌精定位源代码说明

    车牌精定位的源代码在precise_locate.m文件中。
    首先是二值化和形态学的开操作,一个开操作是一个腐蚀操作再接着一个膨胀操作使用相同的结构元素。这样可以求得图片的主要的特征,并且将噪声进一步的去除。然后再找出图像的主要目标以及其对应的最大的连通区域。
    在这里插入图片描述
    接下来我们可以根据以上操作的结果来进行角度的变化,这里的角度变换的前提是车牌粗定位的时候,边界的区域比较精确而且完全近似于矩形,这里我们直接使用MATLAB自带的函数计算矩形的长边长与水平方向的夹角,从而得到需要的旋转角度,再使用MATLAB自带的图像旋转工具进行图像的旋转。
    在这里插入图片描述
    最后将最终的图像进行切割,得到最终的车牌精定位的结果,并把结果转换为二值化的图像,方便以后的字符识别。
    在这里插入图片描述
    在过程中,我每操作一步都会使用直方图检验分割的效果,基本的代码为:
    在这里插入图片描述

    3.4 车牌区域切割源代码说明

    车牌区域切割源代码在final_crop.m文件中。
    对于去除黑边,这里考虑的方法就是,在横向最左和最右端分别以一个像素的步长向中心移动,直到遇到“白色”的像素值,这里为了防止“白色”噪声的干扰,通过设置阈值或者说是形态学直方图的阈值对于条件进行判断,从而增加模型的鲁棒性能。在纵向也相同,最上端和最下端分别以一个像素的步长向中心移动,直到遇到“白色”的像素值,这里为了防止“白色”噪声的干扰,通过设置阈值或者说是形态学直方图的阈值对于条件进行判断,从而增加模型的鲁棒性能。
    在这里插入图片描述
    接着再使用切割得到车牌的矩形区域。
    在这里插入图片描述

    3.5 字符切割源代码说明

    字符切割源代码在seperate_characters.m文件和get_character.m文件中。
    算法中首先需要计算得到区域中有多少个文字出现,这里考虑的是使用计算连通区域的方法,与图像预处理的想法基本一致,计算有多少个面积大于一定阈值的连通区域就确定为多少个文字(英文字母)出现,另外一点,一般的车牌的文字+字母+数字的个数不会超过8个,所以这里我将连通区域的数目规定为小于8个。
    在这里插入图片描述
    然后我们使用MATLAB自带的函数对于连通区域进行判断与定位,并将其初步使用bbox进行定位。接着对于所有的bbox分别计算他们在水平和竖直方向上的长度,并将这个平均长度视为每一个文字区域的长度,在竖直方向也一样,将平均的宽度视为每一个文字区域的宽度。但是对于水平方向还需要如下的进一步细分,还是判断在每一个文字区域内的连通区域,一般来说如果分类正确应该在每一个文字区域中只有一个连通区域(这里的中文由于进行了开运算,也是可以看作为一个连通区域,即使文字出现了偏旁部首)。如果发现了多个(一般为两个或者三个)连通区域,那么就将切割范围在水平方向上进行细微的调动,直到完成每一个文字中有且只有一个连通区域的目标。

    在这里插入图片描述
    在这里插入图片描述
    这样我们就可以定位到每一个文字区域的边界点(定位点),从而进行切割操作。
    在这里插入图片描述

    3.6 字符识别源代码说明

    字符识别的源代码在characters_recognition.m文件中。
    由于不能使用现成的OCR以及深度神经网络进行这里的字符识别,严格来说是字符的匹配。其中匹配的模板是自己切割的数字0-9是个数字以及a-z这26个字母,其中这里的字母I和O因为在车牌中和数字1和0基本完全相同,所以这里没有识别字母I和字母O的,这里一切都是直接使用数字1和数字0来代替。
    首先是我们如果默认车牌是由7个字符组成的,即省的简称+一个字母(两个字母)+五个数字(四个数字)组成的话,那么后六个应该就是数字以及字母的位置。这里考虑首先对于切割出来的每一个字符区域与数字+字母的模板(切割的数字0-9是个数字以及a-z这26个字母),进行点乘,其目的在于进一步匹配两者的近似程度,还有一个细节是,我自己制作的模板与前一步分割出来的字符正好的相反的,即模板的“黑色”区域是切割出来字符的“白色”区域,所以在进行点乘之前需要先将区域进行二值化的反转操作,使用阈值为0.5的反转函数就可以轻易的实现。
    在这里插入图片描述
    进行点乘完后,我们对于点乘后的图片(矩阵),再进行连通区域的标定,并且计算出其最大的面积,使用这个最大的面积与模板在进行MSE的计算,对于一个字符区域与每一个模板进行上述的操作,从中找到一个MSE最小的标定块,并认为其就是与字符相同的模板。这也就达到了识别的效果。
    在这里插入图片描述

    3.7 主函数的源代码说明

    这里主函数的功能就是将以上的六个步骤总结在一起,并从选取待识别图片开始进行,一步一步进行图像预处理、车牌粗定位、车牌细定位、车牌切割、字符切割以及最终的字符识别的工作。具体的实现方式如下:
    在这里插入图片描述

    4 识别结果展示

    我们这里使用两个图片的结果说明:23.jpg和test0101.jpg。
    首先23.jpg的图像预处理的结果(左侧为原图,右侧为处理后的图片,这个图片仅仅是对于选定颜色的提取结果以及二值化后的结果):
    在这里插入图片描述
    在这里插入图片描述
    然后是经过连通区域以及闭运算后的结果,期间也使用了形态学滤波的方法进行了分析,过程也在下面进行显示,分别显示横向和纵向的统计结果:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    接着根据以上的结果,进行车牌的粗定位,并在原图中进行截取,截取的粗定位的车牌如下图:
    在这里插入图片描述
    接下来首先对于上面的车牌粗定位的图像进行开运算并进行二值化的操作,并在水平和竖直方向分别统计,结果如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    然后对于上面的二值化图像进行旋转,使得其水平。并在水平和竖直方向分别统计,结果如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    接着对于车牌进行细微的再分割,目的是与最终的匹配的模板一致,将上下左右侧的黑边去除,算法运行后的切割的结果如下:
    在这里插入图片描述
    然后对于上面的图像进行字符级别的切割,结果如下(这是7个单独的图片):
    在这里插入图片描述
    接着是使用模板匹配的方法进行字符识别,其中自己制作的模板如下图:
    在这里插入图片描述
    在这里插入图片描述
    然后分别对于每一个分割后的字符进行模板的匹配,这里分别在横向和纵向对于图像进行分析匹配,匹配结果和横向的统计结果如下图(这里以英文和数字为例说明结果):
    在这里插入图片描述
    最后将匹配的结果通过命令行输出:
    在这里插入图片描述
    下面来看另外一个图片的例子:test0101.jpg。
    首先test0101.jpg的图像预处理的结果(左侧为原图,右侧为处理后的图片,这个图片仅仅是对于选定颜色的提取结果以及二值化后的结果):
    在这里插入图片描述
    在这里插入图片描述
    然后是经过连通区域以及闭运算后的结果,期间也使用了形态学滤波的方法进行了分析,过程也在下面进行显示,分别显示横向和纵向的统计结果:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    接着根据以上的结果,进行车牌的粗定位,并在原图中进行截取,截取的粗定位的车牌如下图:
    在这里插入图片描述
    接下来首先对于上面的车牌粗定位的图像进行开运算并进行二值化的操作,并在水平和竖直方向分别统计,结果如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    然后对于上面的二值化图像进行旋转,使得其水平。并在水平和竖直方向分别统计,结果如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    接着对于车牌进行细微的再分割,目的是与最终的匹配的模板一致,将上下左右侧的黑边去除,算法运行后的切割的结果如下:
    在这里插入图片描述
    在这里插入图片描述
    然后对于上面的图像进行字符级别的切割,结果如下(这是7个单独的图片):
    在这里插入图片描述
    然后分别对于每一个分割后的字符进行模板的匹配,这里分别在横向和纵向对于图像进行分析匹配,匹配结果和横向的统计结果如下图(这里以英文和数字为例说明结果):
    在这里插入图片描述
    最后将匹配的结果通过命令行输出:
    在这里插入图片描述

    5 其他方法的尝试

    5.1 基于卷积的特征提取和矩形度约束的方法

    这个方法的效率比较低,其基于卷积运算首先对于特征进行提取,在由此进行的车牌的识别工作。这里使用的卷积核的形式如下:
    在这里插入图片描述

    由此来检测水平方向和竖直方向的变化情况(并突出边缘的部分,使得车牌的部分更加清晰),对于(2)WJ03-警0037.jpg这个图片进行完如下的卷积操作以后的图形如下所示:
    在这里插入图片描述
    在这里插入图片描述
    然后对于车牌进行二值化的操作,并计算出连通区域内的面积,通过设置阈值将面积小于一定数值的区域删除,留下来大的区域,同时这里还进行了连通区域的长宽比以及近似矩形度的计算,因为我们最后确定的区域应该是一个矩形域而且它的长宽比一定是确定范围内的数字,经过查阅查阅资料,一般的车牌的长宽比大约为4:1与5:1之间,所以可以根据这种条件来对于车牌的具体区域进行区分与寻找。这里的主要实现代码如下:
    在这里插入图片描述
    通过这套算法,最终得到的车牌的区域为:
    在这里插入图片描述
    对于上图进行canny算子进行边缘检测的结果为:
    在这里插入图片描述

    5.2 基于canny算子边缘检测的方法

    5.2.1 图像的预处理

    这里首先将输入的图片转化为灰度的图像,然后对其进行基于Canny算子的边缘检测。其结果如下图:这里使用test00000120050921201034561.jpg这幅图片举例:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    这里使用Canny进行边缘检测是因为,车牌的背景与其周围的物体(车身)的颜色有明显区别,在颜色中使用梯度计算的话,这种差距更为明显,所以使用Canny算子进行边缘提取,可以比较好的找到车牌对应的位置,但是同时也会存在很多别的边缘,例如车身边缘与道路边缘等等,所以还需要后面继续处理。
    这里的方法是首先使用线性的结构元素对于Canny算子计算得到的边缘图像进行腐蚀,其目的在于找到线性的边界位置,然后再使用矩形结构的元素遂于图像进行聚类与填充。腐蚀后的结果以及填充后的图像如下图所示:
    在这里插入图片描述
    在这里插入图片描述
    可以从上面的结果看出,图像中还有许多的“噪声区域”,车牌的位置相比于这些“噪声区域”来说面积均比较大,所以这里从对象种移除面积小于2000的小对象,即进行形态学的滤波。其结果如下:
    在这里插入图片描述

    5.2.2 车牌的定位

    进行车牌的定位的话,首先应该进行车牌的粗定位从而确定车牌的行列的起始位置和终止位置。这里直接对于上一步经过填充后的图进行白色像素点的统计,使用行方向像素点值的累计和和列方向像素点值的累计和来选择概率最大的车牌的位置。经过粗定位后的车牌的图像如下图所示,其行列方向的像素点值的累计和的图像见下图:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    下面对于图像进行精定位。其主要工作之一就是去除车牌两侧的边框干扰,这里选择的方法是从四个边界向中心“推进”,以1为步长。遇到白色的区域即截止,遇到黑色值的点截止,并标记。从而最终得到精确定位的车牌的二值图像。最终的图像如下,这里我也在列方向对于像素点的灰度值进行了形态学的累计和。
    在这里插入图片描述
    在这里插入图片描述

    5.2.3 字符的分割

    这里采用的是倒序分割。其原因在于第一个字符一般为汉字,对于汉字的识别比较差,因为汉字本身比较复杂,而且本身数据集中图像分辨率就比较差,而且对于有偏旁部首的汉字,很容易就会将其分割为多个汉字。但是对于数字和字母来说其结构一般比较简单,所以这里采用倒序的分割方法。
    具体的分割方法是,使用MATLAB自带的函数对于连通区域进行判断与定位,并将其初步使用bbox进行定位。接着对于所有的bbox分别计算他们在水平和竖直方向上的长度,并将这个平均长度视为每一个文字区域的长度,在竖直方向也一样,将平均的宽度视为每一个文字区域的宽度。但是对于水平方向还需要如下的进一步细分,还是判断在每一个文字区域内的连通区域,一般来说如果分类正确应该在每一个文字区域中只有一个连通区域(这里的中文由于进行了开运算,也是可以看作为一个连通区域,即使文字出现了偏旁部首)。如果发现了多个(一般为两个或者三个)连通区域,那么就将切割范围在水平方向上进行细微的调动,直到完成每一个文字中有且只有一个连通区域的目标。
    最终的字符切割的结果如下:
    在这里插入图片描述

    5.2.4 字符的车牌识别

    这里使用的与上面所描述的车牌识别方法完全相同,就是使用字符的匹配法。具体来说,使用分割所得的字符图片与模板点乘完后,我们对于点乘后的图片(矩阵),再进行连通区域的标定,并且计算出其最大的面积,使用这个最大的面积与模板在进行MSE的计算,对于一个字符区域与每一个模板进行上述的操作,从中找到一个MSE最小的标定块,并认为其就是与字符相同的模板。这也就达到了识别的效果。最终的上面的识别结果为:
    进行点乘完后,我们对于点乘后的图片(矩阵),再进行连通区域的标定,并且计算出其最大的面积,使用这个最大的面积与模板在进行MSE的计算,对于一个字符区域与每一个模板进行上述的操作,从中找到一个MSE最小的标定块,并认为其就是与字符相同的模板。这也就达到了识别的效果:
    在这里插入图片描述

    5.3 基于图像增强的方法

    这里的图像增强是主要考虑到图像的分辨率比较差,而且有部分的车牌数据是在黑暗的环境下的图像,且有部分的车牌比较“陈旧”亮度与新车牌不同,肉眼所见都比较模糊,所以这里在进行图像预处理的时候首先进行了图像的增强。
    这里采用的图像增强的方式是使用了原始图像与背景图像做减法,从而突出待识别区域的“亮度”。再使用上述的方法就可以提高识别效果,这里的图像增强的结果如下图(依次为原始的黑白图像、背景图像以及增强后的图像):
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    这里我还考虑到使用《数字图像处理》课程中介绍的Top-hat(顶帽)或者是Black-hat(黑帽)等形态学滤波方法进行图像的增强,结果发现效果并不好,故不再使用这种方法。使用Top-hat的具体结果如下多图(分别为原图和算法处理后的图)。
    在这里插入图片描述
    在这里插入图片描述

    6 实验结论与所思所想

    本次实验我将自动定位、分割和识别汽车车牌这个任务分成了六个子任务来做,分别是图像的预处理、车牌的粗定位、车牌的精定位、车牌区域切割、字符切割以及字符识别。其中我的实验重点在图像的预处理这一部分,因为这一部分与课上所讲授的知识最贴合,而且对于最终的识别结果影响最大。
    在图像的与处理中我分别使用了连通区域、开闭运算、图像聚类(图像填充)、基于形态学滤波、基于卷积的特征提取与矩形度的约束、图像增强(Top-hat以及Black-hat等方法)以及Canny等边缘检测等方法进行图像的预处理。从而得到了非规则的车牌可能出现的区域。
    在车牌的粗定位处理中,我主要使用了基于统计学的方法对于图像进行水平方向和竖直方向的二值化图像的像素点值的累计和进行分析并初步确定车牌的矩形区域并删去面积小于一定阈值的区域。
    在车牌的精定位处理和车牌区域切割中,首先进行二值化以及形态学的开操作(去除噪音),并使用角度变化使得车牌变水平,方便后面的车牌和字符切割操作。再对于周围的黑色边框进行去除,这个车牌的最终的区域。
    在字符切割方面,通过连通区域和基于统计学的方法对于图像进行水平方向和竖直方向的二值化图像的像素点值的累计和对于每个字符的位置进行判断,从而得到最终的每一个字符的位置。
    最终的字符识别方面,通过事先已经准备好的模板与我们的切割后的单个字符进行匹配,选择MSE最小的模板对应的文字(数字或字母)作为最终的字符识别的结果。
    最终的结果,我的算法以及后面实现的一些单独步骤的算法可以在某些车牌数据中取得100%的识别结果(蓝色底色的),但是对于大部分的数据识别效果还是比较差。原因如下,首先车牌的数据相比于成熟算法所以用的数据集分辨率较差而且车辆(车牌)的尺寸明显较小,需要比较精细的定位。而且,图像中存在夜间以及不同环境下的图像,车牌的背景颜色不同,甚至有的车牌不是单行的,这导致对于算法的泛化性能要求就变高了。最后,可能自己的理论知识、实践能力以及代码能力比较差。
    这个大作业可以从以下的几点进行改进:首先我算法中使用的前提是蓝色的背景的车牌,对于白色和黄色为背景颜色的车牌识别效果很差,所以这里可以使用边缘检测的方法对于车牌的位置进行寻找。这样可以进一步增加车牌识别的鲁棒性能。然后车牌的切割时,应该考虑到每一个字符的位置基本是确定的(国家应该有标准),所以可以以此作为一个约束进行车牌中字符位置的判断。另外,在图像的预处理方便,可以对于在黑夜中的信息进行图像的增强,对于分辨率很低的图像进行超像素等工作,来进一步提高字符切割以及字符识别的准确度。

    7 实验心得与收获

    本次实验通过传统的数字图像处理的算法进行车牌的自动定位、分割、识别,我个人觉得最大的收获在于,我们没有使用现在比较火热的深度学习的方法进行以上的工作,而完全使用传统的数字图像处理的方法进行识别。使用深度学习的我们或许根本就不会对于整个问题进行深入的分析,直接将其作为一个目标识别问题使用YOLO或者Faster RNN等网络进行定位车牌,再使用基于深度学习的OCR进行字符的识别,例如CRNN深度学习网络。这根本达不到我们分析问题解决问题的能力。

    参考文献
    [1] Yang F, Yang F. Detecting license plate based on top-hat transform and wavelet transform[C]//2008 International Conference on Audio, Language and Image Processing. IEEE, 2008: 998-1003.
    [2] Anagnostopoulos C N E, Anagnostopoulos I E, Psoroulas I D, et al. License plate recognition from still images and video sequences: A survey[J]. IEEE Transactions on intelligent transportation systems, 2008, 9(3): 377-391.

    展开全文
  • 该小工程是我为了学习支持向量机算法作为练习的,但继SVM的理论后,更多的困难体在数字图像处理上,比如车牌检测,字符分割,不过在坚持下都已被解决,希望大家能加入一起体验机器学习与数字图像处理 车牌识别的流程...

    车牌识别

    介绍

    opencv数字图像处理,pca+svm车牌识别

    说明

    该小工程是我为了学习支持向量机算法作为练习的,但继SVM的理论后,更多的困难体在数字图像处理上,比如车牌检测,字符分割,不过在坚持下都已被解决,希望大家能加入一起体验机器学习与数字图像处理
    车牌识别的流程:
    1检测到车牌
    2将车牌的字符分割出来
    3字符逐个使用SVM模型识别
    具体的原理(包括SVM超平面推导公式)位于文件夹“theory”,格式为word

    安装教程

    python3
    安装需要的库即可:
    numpy
    pandas
    opencv
    scikit-learn

    eg:pip install scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple

    使用说明

    首先可以直接运行demo.py,直接查看车牌识别的结果
    作为学习,大家可以一步一步参与:
    1.SVM:pixeltocsv将训练图片写入csv
    svmtrain训练svm模型,其中用pca进行降维,模型保存为.m格式
    loadsvm作为使用模型的接口
    2.locate,车牌定位:高斯滤波,中值滤波;
    Sobel算子边缘检测,二值化;
    膨胀一次,腐蚀一次;
    根据车牌长高比范围查找轮廓,将轮廓裁剪出来
    3.spli,字符分割:反复滤波获得不含杂质(垂直投影不连续)的二值图像,
    根据字符像素的脉冲信号起止分割字符
    4.字符逐个使用SVM识别

    注意如果是opencv版本差异带来的问题:
    image_process,contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    改为
    contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)即可
    由于训练集只有数字和英文,所以不能识别车牌的中文字符

    demo结果

    输入图片
    输入图片
    字符分割后

    字符分割
    输出结果,数据集只有英文与数字,所以不识别中文

    结果,不包括中文

    SVM原理:
    首先,识别的方法是很多的,比如对于提取出来的一个个数字,用一个softmax网络就可以达到目的,CNN的正确率会更高,这个小小project选择svm进行分类主要是为了体验一下深度学习之前的最受好评的机器学习算法。
    以下直接贴我写的文档内容,打字太累了:
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述做这个小项目的初衷是为了体验在深度学习出现前最流行的SVM,但是数字图像处理真的让我够头疼的,目前车牌字符分割上还存在一定问题,后续版本有待改进

    车牌定位:

    import cv2
    import numpy as np
    
    def preprocess(gray):
        # # 直方图均衡化
        # equ = cv2.equalizeHist(gray)
        # 高斯平滑
        gaussian = cv2.GaussianBlur(gray, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
        # 中值滤波
        median = cv2.medianBlur(gaussian, 5)
        #cv2.imshow('gaussian&media', median)
        #cv2.waitKey(0)
        # Sobel算子,X方向求梯度
        sobel = cv2.Sobel(median, cv2.CV_8U, 1, 0, ksize=3)
        # 二值化
        ret, binary = cv2.threshold(sobel, 170, 255, cv2.THRESH_BINARY)
        #print("阈值:",ret)
        #cv2.imshow('binary', binary)
        #cv2.waitKey(0)
        # 膨胀和腐蚀操作的核函数
        element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
        element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 7))
        # 膨胀一次,让轮廓突出
        dilation = cv2.dilate(binary, element2, iterations=1)
        # 腐蚀一次,去掉细节
        erosion = cv2.erode(dilation, element1, iterations=1)
        #cv2.imshow('erosion', erosion)
        #cv2.waitKey(0)
        # 再次膨胀,让轮廓明显一些
        dilation2 = cv2.dilate(erosion, element2, iterations=3)
        #cv2.imshow('dilation2', dilation2)
        #cv2.waitKey(0)
        return dilation2
    
    def findPlateNumberRegion(img,ImageArea):
        region = []
        # 查找轮廓,contours记录了每一个闭合的轮廓索引
        #image_process,contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        #print("轮廓数:",len(contours))
        #print("原图面积",ImageArea)
        edge=ImageArea*0.016
        #print("阈值:",edge)
        # 筛选面积小的
        for i in range(len(contours)):
            cnt = contours[i]
            # 计算该轮廓的面积
            area = cv2.contourArea(cnt)
            #print("面积:",area)
            # 面积小的都筛选掉
            if (area < edge):
                continue
            # 轮廓近似,作用很小
            epsilon = 0.001 * cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, epsilon, True)
            # 找到最小的矩形包围轮廓,该矩形可能有方向
            #返回矩形的中心点坐标,长宽,旋转角度[-90,0)
            rect = cv2.minAreaRect(cnt)
            #print("rect is: ",rect)
            # box是四个点的坐标
            box = cv2.boxPoints(rect)
            #取整
            box = np.int0(box)
            # 计算高和长
            height = abs(box[0][1] - box[2][1])
            width = abs(box[0][0] - box[2][0])
            # 车牌正常情况下长高比在2.7-5之间
            ratio = float(width) / float(height)
            #print("ratio: ",ratio)
            if (ratio > 5 or ratio < 2):
                continue
            region.append(box)
        print("车牌区域:",region)
        print("车牌个数:",len(region))
        return region
    
    def detect(img):
        """截取车牌"""
        # 转化成灰度图
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        #输入图像面积
        height, width = img.shape[:2]
        ImageArea=height*width
        # 形态学变换的预处理
        dilation = preprocess(gray)
        # 查找车牌区域
        region = findPlateNumberRegion(dilation,ImageArea)
        # 用绿线画出这些找到的轮廓
        for boxf in region:
            cv2.drawContours(img, [boxf], 0, (0, 0, 0), 2)
        ys = [boxf[0, 1], boxf[1, 1], boxf[2, 1], boxf[3, 1]]
        xs = [boxf[0, 0], boxf[1, 0], boxf[2, 0], boxf[3, 0]]
        ys_sorted_index = np.argsort(ys)
        xs_sorted_index = np.argsort(xs)
        x1 = boxf[xs_sorted_index[0], 0]
        x2 = boxf[xs_sorted_index[3], 0]
        y1 = boxf[ys_sorted_index[0], 1]
        y2 = boxf[ys_sorted_index[3], 1]
        img_org2 = img.copy()
        img_plate = img_org2[y1:y2, x1:x2]
        #cv2.imshow('number plate', img_plate)
        #cv2.imwrite("./plate.png",img_plate)
        #cv2.waitKey(0)
        #cv2.destroyAllWindows()
        return img_plate
    
    if __name__ == '__main__':
        imagePath = './car1.png'
        img = cv2.imread(imagePath)
        cv2.imshow('img', img)
        plate=detect(img)

    字符分割:

    import numpy as np
    import cv2
    
    def preprocess(img):
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 高斯平滑
        gaussian = cv2.GaussianBlur(gray, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
        # 中值滤波
        median = cv2.medianBlur(gaussian, 5)
        #cv2.imshow('gaussian&media', median)
        #cv2.waitKey(0)
        # 二值化
        ret, binary = cv2.threshold(gaussian, 225, 255, cv2.THRESH_BINARY)
        #ret, binary = cv2.threshold(sobel, 90, 255, cv2.THRESH_BINARY)
        #print("阈值:",ret)
        #cv2.imshow('binary', binary)
        #cv2.waitKey(0)
        # 膨胀和腐蚀操作的核函数
        element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
        element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 7))
        # 膨胀一次,让轮廓突出
        dilation = cv2.dilate(binary, element2, iterations=1)
        # 腐蚀一次,去掉细节
        erosion = cv2.erode(dilation, element1, iterations=1)
        #cv2.imshow('erosion', erosion)
        #cv2.waitKey(0)
        dilation2 = cv2.dilate(erosion, element2, iterations=1)
        #cv2.imshow('dilation2', dilation2)
        #cv2.waitKey(0)
        return binary,dilation2
    
    def pickpoint(img):
        height, width = img.shape[:2]
        ImageArea=height*width
        # 查找轮廓,contours记录了每一个闭合的轮廓索引
        #image_process,contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        #print("轮廓数:",len(contours))
        #print("原图面积",ImageArea)
        edgemax=ImageArea*0.0036
        #print("阈值:",edgemax)
        # 筛选面积小的
        for i in range(len(contours)):
            cnt = contours[i]
            # 计算该轮廓的面积
            area = cv2.contourArea(cnt)
            #print("面积:",area)
            # 面积小的都筛选掉
            if (area < edgemax):
                rect = cv2.minAreaRect(cnt)
                #print("rect is: ", rect)
                # box是四个点的坐标
                box = cv2.boxPoints(rect)
                box = np.int0(box)
                #print("box",box)
                img=cv2.drawContours(img, [box], -1, (0, 0, 255), thickness=-1)
                #cv2.imshow("pick",img)
                #cv2.waitKey(0)
        #腐蚀一次
        element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
        img = cv2.erode(img, element1, iterations=1)
        #cv2.imshow("erimg", img)
        #cv2.waitKey(0)
        return img
    
    
    def find_end(start,arg,black,white,width,black_max,white_max):
        """找到每个脉冲的终止"""
        end=start+1
        for m in range(start+1,width-1):
            if (black[m] if arg else white[m])>(0.95*black_max if arg else 0.95*white_max):
                end=m
                break
        return end
    
    def cut(thresh,binary):
        char=[]
        white=[]
        black=[]
        height=thresh.shape[0]
        width=thresh.shape[1]
        print('height',height)
        print('width',width)
        white_max=0
        black_max=0
        #计算每一列的黑白像素总和
        for i in range(width):
            line_white=0
            line_black=0
            for j in range(height):
                if thresh[j][i]==255:
                    line_white+=1
                if thresh[j][i]==0:
                    line_black+=1
            white_max=max(white_max,line_white)
            black_max=max(black_max,line_black)
            white.append(line_white)
            black.append(line_black)
            #print('white',white)
            #print('black',black)
        #arg为true表示黑底白字,False为白底黑字
        arg=True
        if black_max<white_max:
            arg=False
        n=1
        while n<width-2:
            n+=1
            #判断是白底黑字还是黑底白字  0.05参数对应上面的0.95 可作调整
            if(white[n] if arg else black[n])>(0.05*white_max if arg else 0.05*black_max):
                start=n
                end=find_end(start,arg,black,white,width,black_max,white_max)
                n=end
                if end-start>5:
                    cj=binary[1:height,start:end]
                    #左右填充
                    cjwidth = cj.shape[1]
                    cjheight=cj.shape[0]
                    cj=cv2.copyMakeBorder(cj,0,0,int(cjwidth*0.2),int(cjwidth*0.2),cv2.BORDER_CONSTANT, value=0)
                    #上下裁剪,因为要适应到数据集
                    cjwidth = cj.shape[1]
                    length=int(cjheight*0.25)
                    cj=cj[length:cjheight-length,0:cjwidth]
                    #平滑
                    cj = cv2.GaussianBlur(cj, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
                    # 均值平滑
                    cj = cv2.blur(cj, (3, 5))
                    #直方图均衡化
                    cj=cv2.equalizeHist(cj)
                    #二值化扩大亮度
                    ret, cj = cv2.threshold(cj, 60, 255, cv2.THRESH_BINARY)
                    cj = cv2.GaussianBlur(cj, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
                    cj = cv2.blur(cj, (3, 5))
                    char.append(cj)
                    #print("result/%s.jpg" % (n))
                    #cv2.imshow('cutlicense',cj)
                    #cv2.waitKey(0)
        return char
    
    if __name__ == '__main__':
        imagePath = './plate.png'
        img = cv2.imread(imagePath)
        cv2.imshow('img', img)
        binary,dilation2=preprocess(img)
        thresh=pickpoint(dilation2)
        charlist=cut(thresh,binary)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

    SVM训练:

    import pandas as pd
    from sklearn.decomposition import PCA
    from sklearn import svm
    from sklearn.externals import joblib
    import time
    from sklearn.utils import shuffle
    
    if __name__ =="__main__":
        data = pd.read_csv('./train.csv')
        data = shuffle(data)
        train_num = 5000
        test_num = 7000
        train_data = data.values[0:train_num,1:]
        train_label = data.values[0:train_num,0]
        test_data = data.values[train_num:test_num,1:]
        test_label = data.values[train_num:test_num,0]
        t = time.time()
    
        #PCA降维
        pca = PCA(n_components=0.8, whiten=True)
        print('start pca...')
        train_x = pca.fit_transform(train_data)
        test_x = pca.transform(test_data)
        print(train_x.shape)
    
        # svm训练
        print('start svc...')
        svc = svm.SVC(kernel = 'rbf', C = 10)
        svc.fit(train_x,train_label)
        pre = svc.predict(test_x)
    
        #保存模型
        joblib.dump(svc, 'model.m')
        joblib.dump(pca, 'pca.m')
    
        # 计算准确率
        score = svc.score(test_x, test_label)
        """
        start pca...
        (5000, 21)
        start svc...
        准确率:0.980500,花费时间:1.99s
        """
        print(u'准确率:%f,花费时间:%.2fs' % (score, time.time() - t))

    Demo:

    import locate.locateplate as locateplate
    import split.splitarea as splitarea
    import svm.loadsvc as loadsvc
    import cv2
    
    class Demo():
        def __init__(self,img_path,svc_path,pca_path):
            self.img_path=img_path
            self.svc_path=svc_path
            self.pca_path=pca_path
        def run(self):
            #车牌定位
            img = cv2.imread(self.img_path)
            cv2.imshow("car",img)
            plate=locateplate.detect(img)
            #字符分割
            binary,dilation=splitarea.preprocess(plate)
            thresh = splitarea.pickpoint(dilation)
            charlist = splitarea.cut(thresh,binary)
            #加载svm模型
            svc, pca = loadsvc.load_model(self.svc_path,self.pca_path)
            string=[]
            #每个字符进行识别
            for i in range(len(charlist)):
                name="result{}".format(str(i))
                cv2.imshow(name,charlist[i])
                #没有中文数据集,所以不进行识别中文
                if(i==0):
                    continue
                char=cv2.resize(charlist[i], (20, 20), interpolation=cv2.INTER_CUBIC)
                test=char.reshape(1,400)
                test_x = pca.transform(test)
                pre = svc.predict(test_x)
                string.append(loadsvc.nameindex(pre))
            print("车牌非中文字符:",string)
            cv2.waitKey(0)
    
    if __name__ == '__main__':
        img_path="./valimg/car.jpg"
        svc_path="./svm/model.m"
        pca_path="./svm/pca.m"
        platedemo=Demo(img_path,svc_path,pca_path)
        platedemo.run()

    能和大家一起学习很开心,Bye~

    展开全文
  • 车牌识别的过程可分为四步:1)车牌图像切割;2)车牌图像分类;3)车牌字符切割;4)车牌字符分类;1)车牌图像切割: a.将原图转化为灰度图,可去除多通道产生的外界噪声;b. sobel滤波 ,车牌分割的一个重要...

    本文和下文用于开源项目OpenCV的车牌识别的学习!!!

    车牌识别的过程可分为四步:1)车牌图像切割;2)车牌图像分类;3)车牌字符切割;4)车牌字符分类;

    1)车牌图像切割: 

    a.将原图转化为灰度图,可去除多通道产生的外界噪声;

    b. sobel滤波 ,车牌分割的一个重要特征是车牌中的垂直边缘比较多,为了提取垂直边缘,采用sobel一阶垂直方向导数;

    c. 阈值化处理,应用一个OSTU法自动获取阈值滤波器来获得一个二值图像;

    d. 闭运算形态学 ,连接含有边缘数量很多的所有区域,删除边缘之间的空白区域,将车牌区域连接起来;

    e. 漫水填充, 所有的车牌都有统一的背景颜色。使用漫水填充算法来获取旋转矩阵的精确修剪。漫水填充函数用颜色把连通区域填充到掩码图像,填充从种子开始。填充的像素点都是与种子点进行比较,如果像素值为x,seed-low<=x<=seed+up,则该位置将被填充。一旦得到了用来剪切的掩码图像,进而可得到掩码图像点的最小外接矩形,再次检查矩形大小。对于每一个掩码,白色像素获得位置用minAreaRect函数重新得到最相近的修剪区域;

    f. 仿射变换,用来去掉检测矩形区域的旋转;

    g. 提取矩形;

    h. 调整为统一大小,直方图均衡化,提取的矩形图像不能很好的在训练和分类中使用,因为他们没有相同的大小。并且,每个图像包含不同的光照条件,增加了他们之间的差别。

    /* imageSlicer.cpp */
    
    #include <iostream>
    #include <opencv2/opencv.hpp>
    #include <time.h>
    
    using namespace std;
    using namespace cv;
    
    //筛选旋转矩形的面积和宽高比
    bool areaDetection(RotatedRect rectArea)
    {
    	float error = 0.4;//允许错误率
    	const float width_height = 4.7272;//获得西班牙车牌的宽高比 57200
    
    	int min_area = 25 * 25 * width_height;//获得允许矩形的最大最小面积
    	int max_area = 100 * 100 * width_height;
    
    	float min_value = width_height*(1 - error);//获得允许矩形的最大最小宽高比 1.890-6.6180
    	float max_value = width_height*(1 + error);
    
    	int rect_area = rectArea.size.width*rectArea.size.height;//计算可旋转矩形的包围面积和宽高比
    	float rect_value = rectArea.size.width / rectArea.size.height;
    
    	rect_value = rect_value<1 ? 1 / rect_value : rect_value;
    
    	return rect_area>min_area && rect_area<max_area && rect_value>min_value && rect_value<max_value;
    }
    
    void imgProcess(Mat carImg)
    {
    	//1.获得灰度图
    	Mat grayImg, blurImg, sobelImg, threshImg, mopImg;
    	cvtColor(carImg, grayImg, COLOR_BGR2GRAY);
    	//imshow("灰度图", grayImg);
    
    	//2.均值滤波
    	/*void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1),
    	int borderType=BORDER_DEFAULT )*/
    	blur(grayImg, blurImg, Size(5, 5));//均值滤波
    	//imshow("均值滤波", blurImg);
    
    	//3.sobel边缘检测
    	/*void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize=3, double scale=1,
    	double delta=0, int borderType=BORDER_DEFAULT )*/
    	Sobel(blurImg, sobelImg, CV_8U, 1, 0);//sobel算子边缘检测 只对x方向求一阶导
    	//imshow("sobel边缘检测", sobelImg);
    
    	//4.二值化,OTSU算法自动获取阈值获得二值化图像
    	/*double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)*/
    	threshold(sobelImg, threshImg, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
    	//imshow("图像二值化", threshImg);
    
    	//5.闭运算,删除边缘之间的空白区域,将车牌区域连接起来
    	/*Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1))*/
    	Mat element = getStructuringElement(MORPH_RECT, Size(17, 3));//定义结构元素
    	/*void morphologyEx(InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor=Point(-1,-1),
    	int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )*/
    	morphologyEx(threshImg, mopImg, CV_MOP_CLOSE, element);
    	//imshow("闭运算", mopImg);
    
    	//6.寻找所有轮廓,然后用面积和宽高比筛选
    	vector<vector<Point>> contours;//定义轮廓,每个轮廓是一个点集
    	/*void findContours(InputOutputArray Img, OutputArrayOfArrays contours, OutputArray hierarchy,
    	int mode, int method, Point offset=Point())*/
    	findContours(mopImg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);//检测最外层轮廓
    	map<int, RotatedRect> mapCounter;//定义map容器,存储筛选后的矩形轮廓
    	for (int i = 0; i < contours.size(); ++i)
    	{
    		/*void drawContours(InputOutputArray Img, InputArrayOfArrays contours, int contourIdx, const Scalar& color,
    		int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )*/
    		drawContours(mopImg, contours, i, Scalar(255), 1);//绘制图像轮廓
    
    		/*RotatedRect minAreaRect(InputArray points)*/
    		RotatedRect contourRect = minAreaRect(contours[i]);//给定2D点集,寻找最小面积点集的包围矩形
    		Point2f vertices[4];//定义矩形的四个顶点
    		contourRect.points(vertices);
    		for (int j = 0; j < 4; ++j)
    		{
    			line(mopImg, vertices[j], vertices[(j + 1) % 4], Scalar(255), 2);//绘制包围轮廓的矩形
    		}
    		if (areaDetection(contourRect))
    			mapCounter[i] = contourRect;
    	}
    
    	//imshow("矩形包围所有轮廓", mopImg);
    	cout << "轮廓总数: " << contours.size() << endl;
    	cout << "筛选后的轮廓数量:" << mapCounter.size() << endl;
    
    	//获得map存储筛选后矩形轮廓的起始地址用于遍历,继续筛选
    	map<int, RotatedRect>::iterator it = mapCounter.begin();
    	while (it != mapCounter.end())
    	{
    		//7.绘制通过面积和宽高比筛选的矩形
    		//RotatedRect contourRect = it->second;//获得键对应的值
    		//Point2f vertices[4];//定义四个顶点
    		//contourRect.points(vertices);
    		//for (int j = 0; j < 4; ++j)
    		//{
    		//	line(mopImg, vertices[j], vertices[(j + 1) % 4], Scalar(255), 5);
    		//}
    		//++it;
    
    		//8.漫水填充矩形轮廓
    		RotatedRect contourRect = it->second;//获得键对应的值
    		/*void circle(Mat& img, Point center, int radius, const Scalar& color,
    		int thickness=1, int lineType=8, int shift=0)*/
    		circle(mopImg, contourRect.center, 3, Scalar(255), -1);//绘制矩形中心
    
    		float minSize = (contourRect.size.width < contourRect.size.height) ? contourRect.size.width : contourRect.size.height;
    		minSize = minSize*0.5;//设置随机种子的范围
    
    		srand(time(NULL));
    		int seedNum = 10;//设置每个掩码图像的随机种子数
    		Mat mask;//绘制新的掩码图像
    		mask.create(carImg.rows + 2, carImg.cols + 2, CV_8UC1);
    		mask = Scalar::all(0);
    		Scalar newVal = Scalar::all(255);//填充颜色
    		Rect ccomp;//重绘最小矩形区域
    		Scalar loDiff(30, 30, 30);//亮度或颜色负差的最大值
    		Scalar upDiff(30, 30, 30);//亮度或颜色正差的最大值
    		//只考虑当前像素水平和垂直方向的像素+白色填充值为255(忽略newVal)+考虑当前像素与种子像素的差+填充掩码图像
    		int flags = 4 + (255 << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
    		for (int j = 0; j < seedNum; ++j)
    		{
    			/*int floodFill(InputOutputArray Img, InputOutputArray mask, Point seedPoint, Scalar newVal,
    			Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 )*/
    			Point point;
    			point.x = contourRect.center.x + rand() % (int)minSize - (int)(minSize / 2);//获得矩形区域中心附近的点作为种子(黄色)
    			point.y = contourRect.center.y + rand() % (int)minSize - (int)(minSize / 2);
    			circle(mopImg, point, 1, Scalar(255), -1);//绘制种子
    			int area = floodFill(carImg, mask, point, newVal, &ccomp, loDiff, upDiff, flags);
    		}
    		//imshow("漫水填充图像", mopImg);
    		//imshow("掩码图像", mask);
    
    		//9.通过每个图像掩码获得最小面积的包围矩形
    		vector<Point> pointInterest;
    		Mat_<uchar>::iterator itMask = mask.begin<uchar>();//Mat的轻量级数据类型Mat_,需指定类型
    		for (; itMask != mask.end<uchar>(); ++itMask)
    		{
    			if (*itMask == 255)
    				pointInterest.push_back(itMask.pos());//保存白点的坐标
    		}
    		RotatedRect minRect = minAreaRect(pointInterest);//给定2D点集,寻找最小面积的包围矩形
    
    		if (areaDetection(minRect))
    		{
    			//10.绘制通过继续筛选的矩形
    			Point2f minRectPoints[4];
    			minRect.points(minRectPoints);
    			for (int k = 0; k < 4; k++)
    				line(mopImg, minRectPoints[k], minRectPoints[(k + 1) % 4], Scalar(255));
    
    			//11.对原图仿射变换
    			float width_height = (float)minRect.size.width / (float)minRect.size.height;
    			float angle = minRect.angle;
    			if (width_height < 1)//处理图像中旋转角度大于90度的车牌
    				angle = angle + 90;
    			Mat rotMat = getRotationMatrix2D(minRect.center, angle, 1);//获得矩形的旋转矩阵
    			Mat warpImg;
    			/*void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize,
    			int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())*/
    			warpAffine(carImg, warpImg, rotMat, carImg.size(), INTER_CUBIC);
    			//imshow("原图仿射变换", warpImg);
    
    			//12.图像切割
    			Size minRectSize = minRect.size;
    			if (width_height < 1)
    				swap(minRectSize.width, minRectSize.height);
    			Mat plateImg;
    			/*void getRectSubPix(InputArray Img, Size patchSize, Point2f center,
    			OutputArray patch, int patchType=-1 )*/
    			getRectSubPix(warpImg, minRectSize, minRect.center, plateImg);
    			//imshow("原图车牌", plateImg);
    
    			//13.调整车牌图像大小为标准33*144
    			Mat resizeImg;
    			resizeImg.create(33, 144, CV_8UC3);
    			/*void resize(InputArray src, OutputArray dst, Size dsize, double fx=0,
    			double fy=0, int interpolation=INTER_LINEAR )*/
    			resize(plateImg, resizeImg, resizeImg.size(), 0, 0, INTER_CUBIC);
    			imshow("33*144车牌", resizeImg);
    			imwrite("plateOri.jpg", resizeImg);
    
    			//14.直方图均衡化
    			Mat histImg;
    			cvtColor(resizeImg, histImg, COLOR_BGR2GRAY);
    			blur(histImg, histImg, Size(3, 3));
    			equalizeHist(histImg, histImg);
    			imshow("直方图均衡化车牌", histImg);
    			imwrite("plate.jpg", histImg);
    		}
    		++it;
    	}
    }

    2)车牌图像分类

    a. SVM

    /* imageClassification.cpp */
    #include <iostream>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    using namespace ml;
    
    void SVMClassifier(Mat srcImg)
    {
    	Mat plateImg;
    	srcImg.convertTo(plateImg, CV_32FC1);
    	plateImg = plateImg.reshape(1, 1);//将图像转换为1行m列特征,自动计算列数
    
    	FileStorage fs;
    	fs.open("SVM.xml", FileStorage::READ);//打开xml文件
    
    	//1.获得训练数据
    	Mat trainMat, classesMat;
    	fs["TrainingData"] >> trainMat;//读取训练数据集和类标签
    	fs["classes"] >> classesMat;
    	Ptr<TrainData> trainData = TrainData::create(trainMat,ROW_SAMPLE,classesMat);
    
    	//2.创建分类器,设置参数
    	SVM::ParamTypes param;//设置SVM参数
    	SVM::KernelTypes kernel = SVM::LINEAR;
    	Ptr<SVM> svm = SVM::create();
    	svm->setKernel(kernel);
    
    	//3.训练分类器
    	svm->trainAuto(trainData);
    
    	//4.预测
    	int result = svm->predict(plateImg);
    	cout << "预测结果: " << result << endl;
    }


    展开全文
  • 一种新的车牌图像字符分割与识别算法 pdf文档
  • 本书详细介绍了利用Delphi进行图像处理的技术,常用的图像格式,以及Delphi图像处理的常用方法Scanline。本书共8章,内容包括图像的基本概念、图像的点运算、图像的几何变换、图像的颜色系统、图像的增强、图像代数...

    《Delphi数字图像处理及高级应用》

    Delphi 教程 系列书籍 (077) Delphi数字图像处理及高级应用》 网友(邦)整理 EMail: shuaihj@163.com

    下载地址:

    Pdf

    Delphi数字图像处理及高级应用

    • 作者: 刘骏
    • 出版社:科学出版社
    • ISBN:7030121635
    • 上架时间:2003-11-5
    • 出版日期:2003 年9月
    • 开本:16开
    • 页码:350
    • 版次:1-1

    内容简介

    本书详细介绍了利用Delphi进行图像处理的技术,常用的图像格式,以及Delphi图像处理的常用方法Scanline。本书共8章,内容包括图像的基本概念、图像的点运算、图像的几何变换、图像的颜色系统、图像的增强、图像代数与分隔、图像的特效、图像处理综合实例,前面7章比较详细地介绍了图像处理的内容,同时提供了非常详细的程序代码,第8章是编者自己创作或者平时收集的一些经典的例子。本书提供了丰富的源代码,并提供了详细的注释,为读者的学习提供方便。本书可以作为高等院校有关老师的教学参考书或高年级学生及研究生的自学用书,也可作为软件开发人员的参考书。

    前言

    图像处理是一门理论与实践紧密结合的学科,一直以来受到人们的重视。Visual C++(以下简称VC)作为图像处理的常用工具,虽然功能强大,但由于其落后的MFC架构,使得很多初级程序员望而却步;Delphi作为Windows环境下面向对象快速开发工具 (RAD),以其高速的开发效率深得程序员的喜爱,它的编译器的编译速度是VC的几倍,并且具有良好的封装性。 Delphi除了在数据库方面有很强的优势以外,在图像处理上也有着非常强大的功能,Delphi进行图像处理的速度并不亚于VC,同时大大提高了开发效率,只需要少量代码就能实现很多复杂的功能。但是目前专门介绍Delphi数字图像处理的书还很少,以前的Delphi书籍在讲到图像这一节基本上都是一笔带过,没有做系统介绍,本书的写作正是基于这一点,编者把平时工作中遇到的和平时收集的一系列图像处理方面的问题做了一个系统的整理,而成此书。随着图像、多媒体技术的发展以及人们对开发效率的追求,使用Delphi来进行图像处理无疑是最好的选择。 同其他数字图像处理图书相比,本书具有如下显著特点: 1)详细介绍了各种常用、经典图像处理理论。 2)详细介绍小波压缩算法以及实现原理,同时介绍了JPEG2000图像处理技术。 3)完善的代码支持,本书光盘提供了各实例的源代码:为了节省篇幅,书中只给出了核心的代码和详细的注释。 4)本书介绍了近30个各种图像应用实例,包括实际工程应用的具体实例及其源代码,读者可以直接引用。 5)语言简洁易懂,读者很容易明白。 本书包括8章,分别为: 第1章为图像的基本概念,详细介绍了最新的JPEG2000图像格式以及各种其他常用的文件格式,同时介绍各种基础理论。第2章为图像的点运算,对图像的灰度、对比度、灰度直方图、着色、反色等效果做了详细的介绍,并对图像的反走样做了全面的说明,对图像的Gamma校正和特大位图的创建方法也有深入说明。 第3章是图像的几何变换,除了介绍常见的几何变换以外还增加了图像的扭曲,波浪和远视图效果。第4章为图像的颜色系统,不仅介绍了颜色空间的基本概念,还给出了比较重要的颜色空间的转换原理和代码,如RGB空间到CMYK空间的相互转换,RGB空间和HSL空间之间的相互转换等。 第5章是图像的增强,介绍了灰度直方图的拉伸、图像的伪彩色增强等常见处理的原理。第6章是图像的代数与分割,主要介绍了数学形态学在图像处理中的应用,以及经典的边缘检测方法。 第7章为图像特效,图像的特效包括了一些经典的动态效果和静态效果。 第8章是应用篇,给出一些非常好的实用的例子。本书从理论到实践(程序实现)介绍的都非常详细,相信Delphi的初中级程序员很快就会掌握。本书提供了丰富的源代码,并提供了详细的解释,为读者的学习提供方便。 本书可以作为高等院校有关老师的教学参考书或高年级学生或者研究生的自学用书,也可作为软件开发人员的参考书。本书由刘骏主编,参与写作的人员有王华、汪洁、刘海英、白露、王占全、庞演、顾强、李平、孙阳、宁海洋、吴阳、张曙等。同时还要感谢一些网友,如活跃在大富翁论坛上的huazai网友、卷起千堆雪tyn网友,以及其他的一些不知名的热心的网友的帮助。由于时间仓促和作者的水平有限,书中错误和不妥之处在所难免,敬请读者批评指正。如果有任何问题,可以登录www.2wintech.net询问,作者会在一周之内做出答复。 作 者 2003年6月

    目录

    第1章 图像的基础知识

    1.1 图像的基本概念

    1.1.1 图像的应用

    1.1.2 位映像图像和向量图像

    1.1.3 图像处理中的分辨率

    1.2 三基色原理和图像的输入

    1.2.1 可见光谱与光度学参量

    1.2.2 三基色原理

    1.2.3 视觉生理和心理规律

    1.3 图像的几种常见的格式

    1.3.1 BMP格式

    1.3.2 GIF格式

    1.3.3 JPEG格式

    1.3.4 PCX格式

    1.3.5 TIF格式

    1.3.6 JPEG2000格式

    1.4 图像格式转换器实例

    1.4.1 程序功能

    1.4.2 程序实现

    1.5 图像浏览器实例

    1.5.1 程序功能

    1.5.2 程序实现

    1.6 Delphi图像处理中Scanline的用法

    1.6.1 pf8bit的位图

    1.6.2 pf24bit的位图

    1.6.3 pf32bit的位图

    1.6.4 pf8bit向pf24bit转换

    小结

    第2章 图像的点运算

    2.1 图像灰度处理

    2.1.1 实现原理

    2.1.2 程序实现

    2.2 图像的灰度直方图

    2.2.1 实现原理

    2.2.2 程序实现

    2.3 图像的二值化

    2.3.1 实现原理

    2.3.2 程序实现

    2.4 图像亮度处理

    2.4.1 实现原理

    2.4.2 程序实现

    2.5 图像对比度处理

    2.5.1 实现原理

    2.5.2 程序实现

    2.6 饱和度调节

    2.6.1 实现原理

    2.6.2 程序实现

    2.7 图像着色

    2.7.1 实现原理

    2.7.2 程序实现

    2.8 图像反色

    2.8.1 实现原理

    2.8.2 程序实现

    2.9 图像曝光

    2.9.1 实现原理

    2.9.2 程序实现

    2.10 Gamma校正

    2.10.1 实现原理

    2.10.2 程序实现

    2.11 迷人的万花筒

    2.11.1 实现原理

    2.11.2 程序实现

    2.12 位图的反走样

    2.12.1 实现原理

    2.12.2 程序实现

    2.13 位图的与、或操作

    2.13.1 实现原理

    2.13.2 程序实现

    2.14 创建大型位图以及统计位图颜色

    2.14.1 实现原理

    2.14.2 程序实现

    2.15 位图的噪声调节

    2.15.1 实现原理

    2.15.2 程序实现

    小结

    第3章 图像的几何变换

    3.1 图像的平移

    3.1.1 实现原理

    3.1.2 程序实现

    3.2 图像的缩放

    3.2.1 实现原理

    3.2.2 程序实现

    3.3 图像的旋转

    3.3.1 90度旋转

    3.3.2 任意角旋转

    3.4 图像的镜像

    3.4.1 实现原理

    3.4.2 程序实现

    3.5 图像扭曲

    3.5.1 实现原理

    3.5.2 程序实现

    3.6 图像的波浪效果

    3.6.1 实现原理

    3.6.2 程序实现

    3.7 远视图

    3.7.1 实现原理

    3.7.2 程序实现

    3.8 裁剪和合并

    3.8.1 实现原理

    3.8.2 程序实现

    小结

    第4章 图像的颜色系统

    4.1 颜色的基本概念

    4.2 颜色空间简介

    4.2.1 RGB颜色空间

    4.2.2 YIQ颜色空间

    4.2.3 YUV颜色模型

    4.2.4 HSV颜色模型

    4.2.5 CMYK模型

    4.2.6 CIE-XYZ颜色空间

    4.2.7 Lab颜色空间

    4.3 颜色空间的转换

    4.3.1 RGB颜色空间和HSL颜色空间相互转换

    4.3.2 RGB颜色空间和CMYK颜色空间的相互转换

    4.3.3 RGB和HSV颜色空间互换

    4.4 亮度/饱和度调整

    4.4.1 实现原理

    4.4.2 程序实现

    4.5 通道与模式

    4.5.1 实现原理

    4.5.2 程序实现

    4.6 RGB颜色调整

    4.6.1 实现原理

    4.6.2 程序实现

    4.7 特殊色彩的实现

    4.7.1 实现原理

    4.7.2 程序实现

    4.8 颜色量化与减色

    4.8.1 实现原理

    4.8.2 程序实现

    4.9 颜色混合

    4.9.1 实现原理

    4.9.2 程序实现

    小结

    第5章 图像的增强

    5.1 图像增强概述

    5.2 灰度线性变换

    5.2.1 实现原理

    5.2.2 程序实现

    5.3 灰度非线性变换

    5.3.1 实现原理

    5.3.2 程序实现

    5.4 灰度直方图拉伸

    5.4.1 实现原理

    5.4.2 程序实现

    5.5 图像锐化与图像平滑

    5.5.1 图像的锐化

    5.5.2 图像平滑

    5.6 伪彩色增强

    5.6.1 实现原理

    5.6.2 程序实现

    5.7 中值滤波

    5.7.1 实现原理

    5.7.2 程序实现

    小结

    第6章 图像代数与图像分割

    6.1 图像的腐蚀

    6.1.1 实现原理

    6.1.2 程序实现

    6.2 图像的膨胀

    6.2.1 实现原理

    6.2.2 程序实现

    6.3 图像的结构开和结构闭

    6.3.1 实现原理

    6.3.2 程序实现

    6.4 图像的细化

    6.4.1 实现原理

    6.4.2 程序实现

    6.5 图像的边缘检测

    6.5.1 实现原理

    6.5.2 程序实现

    6.6 图像的Hough变换

    6.6.1 实现原理

    6.6.2 程序实现

    6.7 图像的轮廓提取

    6.7.1 实现原理

    6.7.2 程序实现

    6.8 图像的识别和模板匹配

    6.8.1 投影法

    6.8.2 差影法

    6.8.3 模板匹配

    小结

    第7章 图像的特效处理

    7.1 图像的滑入和卷帘显示效果

    7.1.1 图像的卷帘显示效果

    7.1.2 图像的滑入效果

    7.2 图像的淡入淡出效果

    7.3 扩散效果

    7.3.1 实现原理

    7.3.2 程序实现

    7.4 百叶窗效果和马赛克效果

    7.4.1 百叶窗效果

    7.4.2 马赛克效果

    7.5 交错效果

    7.5.1 垂直交错效果

    7.5.2 水平交错效果

    7.6 浮雕效果

    7.6.1 灰色浮雕

    7.6.2 彩色浮雕

    7.7 图像的中心渐出和渐入效果

    7. 7.1 图像的中心渐出效果

    7.7.2 图像的中心渐入效果

    7.8 图像的雨滴效果和积木效果

    7.8.1 图像的雨滴效果

    7.8.2 图像的积木效果

    小结

    第8章 综合实例

    8.1 利用Delphi实现桌面更换

    8.1.1 实现原理

    8.1.2 程序实现

    8.2 图片文件的加密解密

    8.2.1 位图文件的加密解密

    8.2.2 JPG文件加密解密

    8.3 自定义光标的实现

    8.4 基于Delphi的图像漫游

    8.4.1 实现原理

    8.4.2 程序实现

    8.5 用Delphi实现屏幕图像捕捉

    8.6 图片存取到流以及从流中复原

    8.6.1 实现原理

    8.6.2 程序实现

    8.7 Delphi图像处理在纺织检测中的应用

    8.7.1 Hough变换进行边缘检测

    8.7.2 纱线参数测量

    8.7.3 织物表面粗糙度比较

    8.7.4 织物疵点检测

    8.8 Photoshop中流动蚂蚁线的实现

    8.8.1 矩形流动蚂蚁线

    8.8.2 椭圆流动蚂蚁线

    8.8.3 任意位置流动蚂蚁线

    8.9 用Delphi读取JPEG文件的缩览图

    8.9.1 实现原理

    8.9.2 程序实现

    8.10 Delphi数据压缩/解压缩处理

    8.10.1 实现原理

    8.10.2 程序实现

    8.11 特大位图的快速显示

    8.11.1 实现原理

    8.11.2 程序实现

    8.12 Photoshop中的喷枪实现

    8.12.1 实现原理

    8.12.2 程序实现

    8.13 颜色填充

    8.13.1 种子填充

    8.13.2 路径填充

    8.14 位图与组件

    8.14.1 Combobox中添加位图

    8.14.2 ListBox中显示位图

    8.14.3 RichEdit中内容显示为位图

    8.15 颜色拾取器

    8.15.1 实现原理

    8.15.2 程序实现

    8.16 位图的打印

    8.16.1 实现原理

    8.16.2 程序实现

    8.17 Delphi图像处理在交通中的应用——车牌识别

    8.18 位图文件信息写到文本文件以及恢复

    8.19 放大镜

    8.19.1 实现原理

    8.19.2 程序实现

    8.20 调色板创建及应用

    8.20.1 创建调色板

    8.20.2 调色板应用

    8.21 图像的局域网传输

    8.21.1 实现原理

    8.21.2 程序实现

    8.22 图像纵横比率最佳调节

    8.22.1 实现原理

    8.22.2 程序实现

    8.23 JPEG格式图片错误信息显示

    8.24 JPG图片存取到数据库

    8.24.1 实现原理

    8.24.2 程序实现

    8.25 基于小波变换的JPEG2000压缩实现

    8.25.1 实现原理

    8.25.2 程序实现

    8.26 傅里叶变换

    8.26.1 实现原理

    8.26.2 程序实现

    参考文献

    展开全文
  • 可以用传统的机器学习方式,确定图片中车牌的位置,之后对车牌进行相应的处理图像分割,尺寸调整,平滑图像等,再事先利用神经网络,搭建网络模型、训练模型、保存模型参数,最后把前面分割好的图像转换成能适应这...
  • Outline 1、滤波及边缘检测 1)空间滤波、频率滤波 2)边缘检测 canny,sobel,laplace
  • 数字图像处理[M]. 电子工业出版社, 2014.第一章 绪论1 数字图像处理的主要内容(基本步骤)是什么?主要内容:图像获取、图像增强、图像复原、彩色图像处理、(小波变换)、形态学处理、分 割、识别、压缩编码。 ...
  • 如题,我们这一篇博文的目的是为了将车牌提取出来的预处理,我将之总结为车牌特征提取。 (1)首先我们来看车牌部分与其他部分的区别,及车牌的特征,整体的车牌定位及提取方案即时基于此(基于灰度图像中考虑): ...
  • 第一层 》》第二层 》第三层 》》第四层 图像领域 理论 数学,信号处理,图像,计算机视觉 图像处理 模糊 ...图像处理 去燥 ...图像处理 颜色转换 ...图像处理 压缩编码 ...图像处理 增强 ...图像处理 抠图
  • 最近在做一个车牌识别的小项目,之前也没这方面的经验,我大概也就是按照一般步骤:1). 车牌检测;2).车牌校正;3).车牌文字识别这么个三步走的策略来弄。在现实场景中,检测出来的车牌通常都不是那么正规正矩,带有...
  • 图像预处理 车牌定位 车牌过滤 字符分割 字符识别 操作步骤 总结 个人感悟 一直以来对图像识别很感兴趣,再加上这段时间系统地自学了下机器学习的相关知识,所以想自己找实践项目做一下。至于为什么选择...
  • 本案例的车牌图像来源于互联网,如有侵权请尽快联系我,立删。 文章目录一、概述二、车牌图像分析三、车牌定位1. 基本处理2. 图像降噪3....其实现是将图像处理技术与计算机软件技术相连接在一起,以准确...
  • 车牌识别项目总结

    2020-05-16 16:26:45
    写在开头:许久之前的项目了,也是人工智能和图像处理的入门吧,想了想还是整理出来比较好 为什么使用python进行车牌识别? 准确率是多少? 如何提高准确率? 车牌图像处理原理 一、是读取图像,对图像进行...
  • 漫水填充算法

    2017-06-04 22:55:00
    所谓漫水填充算法,是给定一个联通域内的一个点,以此为起点找到这个联通域的其余所有点并将其填充为指定颜色的一种算法。  之所以称之为漫水填充,是因为这种算法就是模拟了涨水的过程,从一点开始,水流慢慢加大...
  • 图像处理专业英语

    2018-02-08 10:41:15
    本文整合自:(1)wyx100 http://blog.csdn.net/wyx100/article/details/74635853(2)刘关张 http://blog.csdn.net/liu_guanzhang/article/details/20708115非常感谢二位!!!AAAN (Active Appearance Model)...
  • 图像是人类获取和交换信息的主要来源,因此,图像处理的应用领域必然涉及到人类生活和工作的方方面面。随着人类活动范围的不断扩大,图像处理的应用领域也将随之不断扩大。(1)航天和航空技术方面的应用 数字...
  • 1.透视变换原理:可以看大牛的博客图像几何变换之透视变换点击打开链接warpPerspective函数点击打开链接2.OpenCV实现车牌图像校正在车牌识别之前,一般都需要对车牌图像进行校正,校正的图像便于后续字符分割。...
  • 连通区域(Connected Component)一般是指图像中具有相同像素值且位置相邻的前景像素点组成的图像区域(Region,Blob)。...连通区域分析是一种在CVPR和图像分析处理的众多应用领域中较为常用和基本的方法。例如:...
1 2 3 4 5 ... 20
收藏数 500
精华内容 200
关键字:

图像处理车牌 填充