车牌识别--倾斜矫正

在车牌识别系统中, 车牌字符能够正确分割的前提是车牌图像能够水平,以至于水平投影和垂直投影能够正常进行。如果车牌倾斜没有矫正,那么水平投影和垂直投影,甚至铆钉都无法正常处理。所以,当车辆信息中获取车牌的第一步,应该是检查倾斜角度,做倾斜矫正。

倾斜矫正,这里使用的算法:

1、倾斜角度检测: 霍夫变换

关于hough变换,可以参考前面图像处理博文:

http://blog.csdn.net/liujia2100/article/details/6989693   直线检测

http://blog.csdn.net/liujia2100/article/details/6989688   文本图像倾斜矫正

2、倾斜矫正: 图像旋转

下面详细说明倾斜矫正过程:

原车牌图像为(从车牌图像中,可以看到车牌有倾斜角度):

1、 获取车牌在车辆中的粗略位置(可以用多种方法,这里暂不分析)

2、提取车牌整体图片数据, 根据第一步结果,提取出,车牌在辆大体位置信息。

关于车牌定位,我使用两部,第一步粗略定位,然后做一些预处理,比如倾斜矫正,然后第二部才是精确定位,只提取车牌的位置信息图像

3、利用HSV颜色空间转换,获取车牌背景蓝色区域位置,获取车牌粗略信息图像后,由于车牌背景颜色与周围颜色有很明显的区别,这里采用HSV颜色过滤的方法,过滤绿色背景图像

4、水平膨胀, 水平膨胀的目的,是为了边缘检测,只要求检测边缘,尽量除去字符信息,也可以降低hough变换的运算量

5、水平差分运算,相当于 边缘检测,经过上面的处理后,才进行边缘检测

6、这个时候就可以利用hough变换检测直线了。

由于hough变换运算量十分大,所以,尽量减少图像中的白点,来降低计算量,因此前面才做了这么多步骤。

请看下图的红线,就是检测出来的角度,为177度(Hough代码在下面)。

7、利用旋转算法,旋转刚才粗略提取的车牌位置(旋转代码在下面),尽管旋转后的车牌有些锯齿,但是已经能够保证水平,就可以使用水平投影和垂直投影了

这是旋转后的车牌,有些锯齿出现,由于图像分辨率较低,就没有用差值运算。

8、精确提取车牌

9、正常分割字符

10、识别结果

由于正弦余弦运算,计算量比较大,这里进行一部分优化,就是正弦余弦计算用数组代替。

生成正弦,余弦数组的的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

int main(void)
{
    char buf[20];
    int i;
    float p;
    float k;
    FILE *fcos;
    FILE *fsin;

    fcos = fopen(".\\cos.txt", "wb");
    fsin = fopen(".\\sin.txt", "wb");

    if(fcos == NULL || fsin == NULL)
    {
        printf("open error\n");
        exit(-1);
    }

    i = 0;

    for(i = 0; i <= 180; i++)
    {
        k = 3.1415926 * i / 180.0;
        p = cos(k);

        if((i%16 == 0))
            fwrite("\n",strlen("\n"),1,fcos);

        sprintf(buf,"%f, ", p);
        fwrite(buf,strlen(buf),1,fcos);

    }

    for(i = 0; i <= 180; i++)
    {
        k = 3.1415926 * i / 180.0;
        p = sin(k);

        if((i%16 == 0))
            fwrite("\n",strlen("\n"),1,fsin);

        sprintf(buf,"%f, ", p);
        fwrite(buf,strlen(buf),1,fsin);

    }
    fclose(fcos);
    fclose(fsin);
    return 0;
}

生成数组为:

float carCos[] = {
1.000000, 0.999848, 0.999391, 0.998630, 0.997564, 0.996195, 0.994522, 0.992546, 0.990268, 0.987688, 0.984808, 0.981627, 0.978148, 0.974370, 0.970296, 0.965926,
0.961262, 0.956305, 0.951057, 0.945519, 0.939693, 0.933580, 0.927184, 0.920505, 0.913545, 0.906308, 0.898794, 0.891007, 0.882948, 0.874620, 0.866025, 0.857167,
0.848048, 0.838671, 0.829038, 0.819152, 0.809017, 0.798636, 0.788011, 0.777146, 0.766044, 0.754710, 0.743145, 0.731354, 0.719340, 0.707107, 0.694658, 0.681998,
0.669131, 0.656059, 0.642788, 0.629320, 0.615662, 0.601815, 0.587785, 0.573576, 0.559193, 0.544639, 0.529919, 0.515038, 0.500000, 0.484810, 0.469472, 0.453991,
0.438371, 0.422618, 0.406737, 0.390731, 0.374607, 0.358368, 0.342020, 0.325568, 0.309017, 0.292372, 0.275637, 0.258819, 0.241922, 0.224951, 0.207912, 0.190809,
0.173648, 0.156434, 0.139173, 0.121869, 0.104528, 0.087156, 0.069757, 0.052336, 0.034900, 0.017452, 0.000000, -0.017452, -0.034899, -0.052336, -0.069756, -0.087156,
-0.104528, -0.121869, -0.139173, -0.156434, -0.173648, -0.190809, -0.207912, -0.224951, -0.241922, -0.258819, -0.275637, -0.292372, -0.309017, -0.325568, -0.342020, -0.358368,
-0.374607, -0.390731, -0.406737, -0.422618, -0.438371, -0.453990, -0.469472, -0.484810, -0.500000, -0.515038, -0.529919, -0.544639, -0.559193, -0.573576, -0.587785, -0.601815,
-0.615661, -0.629320, -0.642788, -0.656059, -0.669131, -0.681998, -0.694658, -0.707107, -0.719340, -0.731354, -0.743145, -0.754710, -0.766044, -0.777146, -0.788011, -0.798635,
-0.809017, -0.819152, -0.829038, -0.838671, -0.848048, -0.857167, -0.866025, -0.874620, -0.882948, -0.891007, -0.898794, -0.906308, -0.913545, -0.920505, -0.927184, -0.933580,
-0.939693, -0.945519, -0.951056, -0.956305, -0.961262, -0.965926, -0.970296, -0.974370, -0.978148, -0.981627, -0.984808, -0.987688, -0.990268, -0.992546, -0.994522, -0.996195,
-0.997564, -0.998630, -0.999391, -0.999848, -1.000000
};

float carSin[] = {
0.000000, 0.017452, 0.034899, 0.052336, 0.069756, 0.087156, 0.104528, 0.121869, 0.139173, 0.156434, 0.173648, 0.190809, 0.207912, 0.224951, 0.241922, 0.258819,
0.275637, 0.292372, 0.309017, 0.325568, 0.342020, 0.358368, 0.374607, 0.390731, 0.406737, 0.422618, 0.438371, 0.453990, 0.469472, 0.484810, 0.500000, 0.515038,
0.529919, 0.544639, 0.559193, 0.573576, 0.587785, 0.601815, 0.615661, 0.629320, 0.642788, 0.656059, 0.669131, 0.681998, 0.694658, 0.707107, 0.719340, 0.731354,
0.743145, 0.754710, 0.766044, 0.777146, 0.788011, 0.798635, 0.809017, 0.819152, 0.829038, 0.838671, 0.848048, 0.857167, 0.866025, 0.874620, 0.882948, 0.891007,
0.898794, 0.906308, 0.913545, 0.920505, 0.927184, 0.933580, 0.939693, 0.945519, 0.951056, 0.956305, 0.961262, 0.965926, 0.970296, 0.974370, 0.978148, 0.981627,
0.984808, 0.987688, 0.990268, 0.992546, 0.994522, 0.996195, 0.997564, 0.998630, 0.999391, 0.999848, 1.000000, 0.999848, 0.999391, 0.998630, 0.997564, 0.996195,
0.994522, 0.992546, 0.990268, 0.987688, 0.984808, 0.981627, 0.978148, 0.974370, 0.970296, 0.965926, 0.961262, 0.956305, 0.951057, 0.945519, 0.939693, 0.933580,
0.927184, 0.920505, 0.913545, 0.906308, 0.898794, 0.891007, 0.882948, 0.874620, 0.866025, 0.857167, 0.848048, 0.838671, 0.829038, 0.819152, 0.809017, 0.798636,
0.788011, 0.777146, 0.766044, 0.754710, 0.743145, 0.731354, 0.719340, 0.707107, 0.694658, 0.681998, 0.669131, 0.656059, 0.642788, 0.629320, 0.615662, 0.601815,
0.587785, 0.573576, 0.559193, 0.544639, 0.529919, 0.515038, 0.500000, 0.484810, 0.469472, 0.453991, 0.438371, 0.422618, 0.406737, 0.390731, 0.374607, 0.358368,
0.342020, 0.325568, 0.309017, 0.292372, 0.275637, 0.258819, 0.241922, 0.224951, 0.207912, 0.190809, 0.173648, 0.156435, 0.139173, 0.121869, 0.104529, 0.087156,
0.069757, 0.052336, 0.034900, 0.017452, 0.000000
};

旋转RGB图像的主要函数:

image: 图像数据

iRotateAngle: 要旋转的角度

width, height:原始图像的宽度,高度

lwidth,lheight:旋转后图像的宽度,高度

unsigned char *RotateRGB(unsigned char *image, float iRotateAngle,int width,int height,int &lwidth,int &lheight)
{

    int i,j,k,m,n;
    long    lNewWidth;
    long    lNewHeight;
      float gray;
    long    i0;
    long    j0;
    float    fRotateAngle;
    float    fSina, fCosa;
    float    fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;
    float    fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;

    float    f1,f2;

    if(iRotateAngle >= 0)
    {
        fSina = (float)carSin[(int)iRotateAngle];
        fCosa = (float)carCos[(int)iRotateAngle];
    }
    else
    {
        fSina = 0 - (float)carSin[0 -(int)iRotateAngle];
        fCosa = (float)carCos[0 - (int)iRotateAngle];
    }

    fSrcX1 = (float) (- (width  - 1) / 2);
    fSrcY1 = (float) (  (height - 1) / 2);
    fSrcX2 = (float) (  (width  - 1) / 2);
    fSrcY2 = (float) (  (height - 1) / 2);
    fSrcX3 = (float) (- (width  - 1) / 2);
    fSrcY3 = (float) (- (height - 1) / 2);
    fSrcX4 = (float) (  (width  - 1) / 2);
    fSrcY4 = (float) (- (height - 1) / 2);

    fDstX1 =  fCosa * fSrcX1 + fSina * fSrcY1;
    fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1;
    fDstX2 =  fCosa * fSrcX2 + fSina * fSrcY2;
    fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2;
    fDstX3 =  fCosa * fSrcX3 + fSina * fSrcY3;
    fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3;
    fDstX4 =  fCosa * fSrcX4 + fSina * fSrcY4;
    fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4;

    lNewWidth  = (long) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5);

    lNewHeight = (long) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) )  + 0.5);
    unsigned char *temp=myMalloc(lNewHeight*lNewWidth*3,0,0);

    f1 = (float) (-0.5 * (lNewWidth - 1) * fCosa - 0.5 * (lNewHeight - 1) * fSina
        + 0.5 * (width  - 1));
    f2 = (float) ( 0.5 * (lNewWidth - 1) * fSina - 0.5 * (lNewHeight - 1) * fCosa
        + 0.5 * (height - 1));

    for(i = 0; i < lNewHeight; i++)
    {
        for(m=0,j = 0;j < lNewWidth,m<lNewWidth*3;m+=3,j++)
        {
            i0 = (long) (-((float) j) * fSina + ((float) i) * fCosa + f2 + 0.5);
            j0 = (long) ( ((float) j) * fCosa + ((float) i) * fSina + f1 + 0.5);

            if( (j0 >= 0) && (j0 < width) && (i0 >= 0) && (i0 < height))
            {
                 n=i0 * width * 3 + j0 * 3;
                 *(temp + lNewWidth * i * 3 + m + 1) = *(image + n + 1);
                 *(temp + lNewWidth * i * 3 + m + 2) = *(image + n + 2);
                 *(temp + lNewWidth * i * 3 + m) = *(image + n);
            }
            else
            {
                 *(temp + lNewWidth * i*3+ m+1)=0;
                 *(temp + lNewWidth * i*3+ m+2)=0;
                 *(temp + lNewWidth * i*3+ m)=0;
            }
        }
    }

      lwidth = lNewWidth;
    lheight = lNewHeight;

    return temp;

}

Hough变化的主要函数

返回值Kmax,就是检测到最长直线的角度,就是车牌的倾斜角度。

int hough(unsigned char *srcBmp,int width,int height)
{
    int kmax=0;
    int pmax=0;
    int yuzhi=0;
    int i,j,k,m,n,p;
    int mp = (int) (sqrt(width*width + height*height)+1);
    int ma = 180;//180
    int ap;
    int npp[180][1000];
    for(i=0;i<180;i++)
        for(j=0;j<1000;j++)
        npp[i][j]=0;

    for(i = 0;i < height;i++)
        for(j = 0; j < width;j++)
        {
            if(srcBmp[i * width + j]==255)
            {
                for(k = 0; k < ma; k++)
                {
                    p=(int)(i * carCos[k] + j * carSin[k]);
                    p=(int)(p/2 + mp/2);
                    npp[k][p]=npp[k][p]++;
                }
            }
        }
        kmax=0;
        pmax=0;
        n=0;
        for(i = 0; i < ma; i++)
            for(j = 0; j < mp; j++)
            {
                if(npp[i][j] > yuzhi)
                {
                    yuzhi=npp[i][j];
                    kmax=i;
                    pmax=j;
                }
            }
            for(i = 0; i < height;i++)
                for(j = 0; j < width;j++)
                {
                    if(srcBmp[i*width+j]==255)
                    {
                        p=(int)(i*carCos[kmax] + j *carSin[kmax]);
                        p=(int)(p/2+mp/2);
#if defined(DISPLAYDEBUG)
                        if(p==pmax)
                          putpixel(j,i,RGB(255,0,0));
#endif
                    }
                }
                return kmax;
}

原文地址

时间: 01-29

车牌识别--倾斜矫正的相关文章

车牌OCR识别的流程,手机车牌识别

车牌的OCR识别的流程如下: 手机车牌识别背景 随着人们生活水平的提高,汽车方面的业务量也日益暴涨,加上如今"互联网+"的提出,智能终端(智能手机及平板电脑)及移动通信(4G)发展迅速,人们用手机的频率比用电脑的多,加上手机小巧轻便,成为生活中必要的工作及社交工具,可以预见未来几年60%以上的业务将会逐渐转移到智能终端系统上来.伴随着移动端APP的火爆应用,易泊将原来应用在电脑端的车牌识别技术转移到了移动端,手机车牌识别更加灵活,方便,为人们的应用解决了很多实际困难. 手机车牌识别描述

车牌识别算法介绍与实践

汽车牌照自己主动识别整个处理过程分为预处理.边缘提取.车牌定位.字符切割.字符识别五大模块,当中字符识别过程主要由下面3个部分组成: ①正确地切割文字图像区域: ②正确的分离单个文字: ③正确识别单个字符. 用MATLAB软件编程来实现每个部分,最后识别出汽车牌照. 系统设计概述 因为车辆牌照是机动车唯一的管理标识符号,在交通管理中具有不可替代的作用,因此车辆牌照识别系统应具有非常高的识别正确率,对环境光照条件.拍摄位置和车辆行驶速度等因素的影响应有较大的容阈,而且要求满足实时性要求. 该系统是

不想手动输入车牌号?手机Android端车牌识别助你一臂之力!

关键词:手机车牌识别 Android端车牌识别 移动端车牌识别 车牌识别 随着车辆的暴涨,对车辆的管理也是日益严峻.需要更多灵活的有效的管理方式,伴随着移动端APP的火爆应用,北京易泊时代将原来应用在电脑端的车牌识别技术转移到了手机Android端,手机Android端车牌识别更加灵活,方便,为人们的应用解决了很多实际困难. 手机Android端车牌识别产品描述 手机Android端车牌识别系统是北京易泊时代开发的基于移动平台的证件识别应用程序,支持Android/IOS等多种主流移动操作系统.

安卓车牌识别与警务通PDA之间的联系

一.安卓车牌识别在PDA中的应用背景 PDA(Personal Digital Assistant),又称为掌上电脑,在使用上,它比手机更多功能,能打单,扫码,相比台式电脑操作简单.移动方便,功能实用. 现在我国警务通用PDA机使用越来越普及了,由于人口越来越多,车辆越来越多,对人与车的管理必须提高效率,如果在这些终端机上能够集成车牌识别.驾驶证识别,行驶证识别,证件识别等用OCR技术研发出的功能,必然省时省力,对于维护交通安全和城市治安,以及实现交通自动化管理亦有着很重要的现实意义. 据了解,

车牌识别系统,助力智慧城市

城市在发展进程中总会遇到各种各样的问题,如今看来,例如停车,停车难已经成为一线二线城市,城市化过程中一个畅聊的话题,停车位少.停车位不好找.停车收费慢等等,所以今天我们要讨论的话题就是车牌识别一体机对提高城市停车管理的重要性,车牌识别一体机不仅可以减轻停车场负担,收费难管理难的压力,还能为安防等行业,提供便利. 城市在设计的过程中,优化了停车场的布局,在建设停车场的时候更加的人性化.方便化,比如立体车库的不断涌现.当然,我们如何知道停车场内是否有空余车位.哪个位置有停车位.这就离不开车牌识别的作

车牌识别及验证码识别的一般思路

http://www.pin5i.com/showtopic-22246.html 描述一下思路及算法. 全文分两部分,第一部分讲车牌识别及普通验证码这一类识别的普通方法,第二部分讲对类似QQ验证码,Gmail验证码这一类变态验证码的识别方法和思路. 一.车牌/验证码识别的普通方法 车牌.验证码识别的普通方法为: (1)      将图片灰度化与二值化 (2)      去噪,然后切割成一个一个的字符 (3)      提取每一个字符的特征,生成特征矢量或特征矩阵 (4)      分类与学习.

论车牌识别与电子警察关系

智能交通系统是21世纪世界道路交通的发展趋势,也是我国建设智慧城市不可或缺的一环.公路交通基础建设的不断发展和车辆管理体制的不断完善,为以视觉监控为基础的智能交通系统的实际应用打下了良好基础.其中电子警察系统的应用是道路交通管理中体现"科技强警"的一项重要举措,缓解了多年来警力不足和交通事故不断攀升之间的矛盾,同时在一定程度上消除了道路交通管理在时间和空间上的"盲点",扩大了交通管理的监控时段和监控范围,减轻了一线交通民警的劳动强度,改善了工作环境,科学准确的信息给

服务器端车牌识别

                   服务器端车牌识别   服务器端车牌识别即服务器版车牌OCR识别软件,该软件可部署在客户私有服务器中(私有本地服务器或云服务器均可),APP和业务系统可通过web service接口调用该识别服务,设备端只负责拍摄图像后上传,上传到已部署服务器端车牌识别软件的服务器中进行识别,识别完成后再返回标准的XML数据.整个识别过程和我公司没有任何交互,均在企业自有的服务器上完成识别.服务器端车牌识别软件目前支持Windows.Linux等主流服务器操作系统. 服务器端

基于opencv的车牌识别系统

前言 学习了很长一段时间了,需要沉淀下,而最好的办法就是做一个东西来应用学习的东西,同时也是一个学习的过程. 概述     OpenCV的全称是:Open Source Computer Vision Library.OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows和Mac OS操作系统上.它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python.Ruby.MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算

车牌识别--铆钉的去除

车牌识别中,每一步的效果直接影响整体的识别率,对车牌识别产生干扰的,不仅是车牌的污渍,还有铆钉. 一 .举例说明,铆钉干扰使得车牌识别错误 1.车辆图片 2.通过颜色HSV确认车牌大致位置 3.截取车牌图像 4.二值化后,水平投影,从图片中可以很清楚看到铆钉     5.字符分割后的车牌 6.提取分割后的车牌字符 7.错误的识别结果 二.改善方法 这里针对车牌识别的干扰去除方法加以改善. 1.原先博文中车牌识别中去除铆钉的方法,只是用投影的方法.粗略计算铆钉在车牌的上方,白点信息较少,通过水平投