zoukankan      html  css  js  c++  java
  • 车牌识别--倾斜矫正

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

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

    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
    ");
    		exit(-1);
    	}
    
    
    	i = 0;
    
    	for(i = 0; i <= 180; i++)
    	{
    		k = 3.1415926 * i / 180.0;
    		p = cos(k);
    		
    				
    		if((i%16 == 0))
    			fwrite("
    ",strlen("
    "),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("
    ",strlen("
    "),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;
    }


    图像处理交流QQ群:

     105060236
     

  • 相关阅读:
    亿级 Web 系统的容错性建设实践
    Spring 4支持的Java 8新特性一览
    Java多线程干货系列—(一)Java多线程基础
    Sublime Text 2 实用快捷键(Mac OS X)
    spring-事务管理
    100 个 Linux 常用命令大全
    这些年MAC下我常用的那些快捷键
    Java 容器源码分析之HashMap多线程并发问题分析
    MySQL索引结构--由 B-/B+树看
    Java 容器之 Connection栈队列及一些常用
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6767286.html
Copyright © 2011-2022 走看看