⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dipview.cpp

📁 使用OpenCV和C++实现的车牌识别系统
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/// CDipView::OnLocate()的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:完成车牌定位的整个过程
/// 程序流程:1.产生副本
///           2.水平差分提取边缘,寻找横向的车牌带状区域
///           3.垂直差分提取边缘,寻找纵向的车牌带状区域
///           4.利用先验知识标识车牌区域,进行车牌带状区域的选择,(横纵向)
///           5.构造出车牌矩形域;
///           6.再次利用利用跳变数选择车牌矩形区域,进行车牌区域的最终选择;
///           7.精确定位车牌,即削弱车牌横向宽度;
///           8.更新图象;
/// </summary> 
void CDipView::OnLocate()
{
	// TODO: 在此添加命令处理程序代码
	CDipDoc *pDoc=GetDocument();

	int width,height;
	width=pDoc->ImgWidth;
	height=pDoc->ImgHeight;

	BYTE *g=new BYTE[width*height];

	CopyImg(pDoc,g,width,height);
	//Banlance(g,width,height);
	HSub(g,width,height);
    Search(g,width,height);

	CopyImg(pDoc,g,width,height);
	VSub(g,width,height);
	VSearch(g,width,height);	

	Mark(pDoc,width,height);
    VMark(pDoc,width,height);
	DrawRect(pDoc,width,height);
	Choose(pDoc,width,height);
	FurtherLocate(pDoc,width,height);

	free(g);
	IsNewBitmap=true;
	IsNewFile=true;
	pDoc->UpdateAllViews(NULL);    
}

// 均衡化图象
void CDipView::Banlance(BYTE* DisposeImg,int Width,int Height)
{
    float num=0;	
	int row,col;
	int count[256];
	float s0[256];
	int s[256];                        //256个灰度等级
	int x=0;
	int temp=0;

	for( x=0;x<256;x++)
	{
		count[x]=0;
		s0[x]=0.0;
		s[x]=0;
	}

	for(row=0;row<Height;row++)                          //每个灰度等级象素个数
	{
		for(col=0;col<Width;col++)
		{	
			temp=DisposeImg[row*Width+col];
			count[temp]++;			
		}
	}	

	for(x=0;x<256;x++)                                       //对应灰度等级概率
	{
		num=(float)Width*Height;
		s0[x]=(float)(count[x]/num);
	}

	for( x=1;x<256;x++)                                      //概率累计,合并灰度等级    
	{	
		s0[x]+=s0[x-1];	 
	}	

    for( x=0;x<256;x++)                                      //映射
	{	
		 s[x]=(int)(s0[x]*255+0.5);
	}

	for(row=0;row<Height;row++)                          //每个灰度等级象素个数
	{
		for(col=0;col<Width;col++)
		{	
			int reflect=0;
			temp=DisposeImg[row*Width+col];
			reflect=s[temp];
			DisposeImg[row*Width+col]=reflect;
		}
	}	
}


// 图象复制
void CDipView::CopyImg(CDipDoc * SourceImg, BYTE* DestImg, int Width, int Height)
{
	for(int row=0;row<Height;row++)
	{
		for(int col=0;col<Width;col++)
		{	
			DestImg[row*Width+col]=SourceImg->ImgData[row*Width+col];			
		}
	}	
}

// 图象复制
void CDipView::CopyImg(BYTE* SourceImg, BYTE* DestImg, int Width , int Height)
{
    for(int row=0;row<Height;row++)
	{
		for(int col=0;col<Width;col++)
		{	
			DestImg[row*Width+col]=SourceImg[row*Width+col];			
		}
	}	
}

/// <summary>
/// CDipView::HSub(BYTE* DisposeImg, int Width , int Height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:水平差分提取图象边缘。
/// 程序流程:1.逐行扫描,sub=|f(x,y)-f(x,y+1)|;
///           2.若差值小于20,则g(x,y)=0;
///             若差值大于30,则增强原图象,令g(x,y)=g(x,y)+30;
///           3.另最后一列全部为0,即黑色;
/// </summary> 
// 水平差分
void CDipView::HSub(BYTE* DisposeImg, int Width , int Height)
{
	int row,col,sub;

	for(row=0;row<Height;row++)
	{
		for(col=0;col<Width-1;col++)
		{			
			sub=abs((DisposeImg[row*Width+col])-(DisposeImg[row*Width+col+1]));
			if(sub<20)
			{
				DisposeImg[row*Width+col]=0;
			}
			else
			{
				if(sub>30)
				{					
                	DisposeImg[row*Width+col]=sub+30;
				}
				else
				DisposeImg[row*Width+col]=sub;
			}
		}
	}

	for(row=0;row<Height;row++)
	{
		DisposeImg[row*Width+Width-1]=0;				
	}	 
}

// 纵向差分
void CDipView::VSub(BYTE* DisposeImg, int Width , int Height)
{	
	int row,col,sub;

	for(row=0;row<Height-1;row++)
	{
		for(col=0;col<Width;col++)
		{			
			sub=abs((DisposeImg[row*Width+col])-(DisposeImg[(row+1)*Width+col]));		
		/*	if(sub<5)
			{
				DisposeImg[row*Width+col]=0;
			}
			else
			{
				if(sub>10)
				{					
                	DisposeImg[row*Width+col]=sub+30;
				}
				else
				DisposeImg[row*Width+col]=sub;
			}*/
			DisposeImg[row*Width+col]=sub;				
		}
	}

	for(col=0;col<Width-1;col++)
	{			
		DisposeImg[(Height-1)*Width+col]=0;
	}
}

/// <summary>
/// CDipView::Search(BYTE* DisposeImg, int width , int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:完成图象车牌区域的初步定位。即寻找出差分扫描后水平跳变数最大的前10个区域。
/// 程序流程:1.利用间行扫描的方式找出跳变数最大的前10行;
///           2.对 Top 10 行进行区域细粒度增长选择;
///             其相似度的选取为:0.7~1.3 倍的该行跳变总数;
///           3.二值化,threshold=255;
///           4.任意选择一列,最好不要边缘列,可能有干扰(本程序选择为第十列),搜索出各个带状候选域,存入标志;
/// </summary> 
void CDipView::Search(BYTE* DisposeImg, int width , int height)
{
	BYTE*TempImg=new BYTE[width*height];

    int *Count= new int[height];
	int *TempCount=new int[height];
	int *maxChanges=new int[10];
	int *Rows=new int[10]; 
	
	CopyImg(DisposeImg,TempImg,width,height);

	for(int c=0;c<height;c++)
	{
		Count[c]=0;
		TempCount[c]=0;
	}

	for(c=0;c<10;c++)
	{
        maxChanges[c]=0;
	    Rows[c]=0; 
		Height[c]=0;
		TopRow[c]=-1;
	}
	
    for(int row=0;row<height;row++)
	{
		for(int col=0;col<width-1;col++)
		{	
			if(DisposeImg[row*width+col]!=DisposeImg[row*width+col+1])
				Count[row]++;		
		}
		TempCount[row]=Count[row];
	}

	/////////////////////////////////////Top 10 chage row
	for(int top=0;top<10;top++)
	{
		int Max=0;
		for(row=0;row<height;)
		{
			if(Max<TempCount[row])
			{
				Max=TempCount[row];
			}	
			row=row+10	;
		}
		maxChanges[top]=Max;

		int R=0;
    	for(row=0;row<height;)
		{
	    	if(Max!=TempCount[row])
			{
	    		row=row+10;				
			}	
			else
			{
				R=row;
				break;	
			}
		}
		Rows[top]=R;
		TempCount[R]=0;	
	}

	for(top=0;top<10;top++)
	{
		for(int range=-10;range<10;range++)
		{
			if((0.7*Count[Rows[top]]<=Count[Rows[top]+range])&&(Count[Rows[top]+range]<=1.3*Count[Rows[top]]))		
			{
				 for(int col=0;col<width;col++)
				 {	
		        	DisposeImg[(Rows[top]+range)*width+col]=255;						
				 }
			}
		}
	}

	 for(row=0;row<height;row++)
	 {
		for(int col=0;col<width;col++)
		{	
		    if(DisposeImg[row*width+col]<255)
			{
               DisposeImg[row*width+col]=0;
			}
		}
	 }	

	int Area=0;                   //标识区域的地点
	if(DisposeImg[0*width+10]==255)
	{
		Area++;		
		Height[Area]++;
	    TopRow[Area]=0;	
	}
	for(row=1;row<height;row++)
	{	
		if((DisposeImg[row*width+10]==255) && (DisposeImg[(row-1)*width+10]==0))
		{
			Area++;		
	        Height[Area]++;
	    	TopRow[Area]=row;				
		}
		else 
		{
			if(DisposeImg[row*width+10]==255&&DisposeImg[(row-1)*width+10]==255)
		    {
		    	Height[Area]++;
		    }		    
		}
	}	

//	Mark(TempImg,width,height);

//	CopyImg(TempImg,DisposeImg,width,height);

	free(TempImg);
    free(Count);
	free(TempCount);
	free(maxChanges);
	free(Rows); 
}

/// <summary>
/// CDipView::Mark(CDipDoc * DisposeImg, int width , int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:利用先验知识标识车牌区域,进行车牌区域的选择,(横向)
/// 函数说明:特定应用条件,拍摄所得车牌的区域高度、宽度均有一定的范围,其大小可以分析图象后可得
///           根据统计得到:车牌的顶部极少出现在高度小于100个像素的区域;
///                         车牌高度也一般大于20个像素。
///           程序的最终结果为满足条件的经过扩展了的带状区域
/// 程序流程:1.舍弃区域顶部小于100的待选域
///           2.选择区域高度大于20的待选域
///           3.区域扩展,上下各增大5个像素。若顶部小于5,则顶部坐标不变,高度加5;
///                                          若底部大于图象的底部,则底部坐标不变,高度加5;
/// </summary> 
void CDipView::Mark(CDipDoc * DisposeImg, int width , int height)
{
	for(int x=0;x<20;x++)
	{
		int h=Height[x];
		if(TopRow[x]<=5)
		{
			Height[x]=0;
			TopRow[x]=-1;
		}
	}
	 for(x=0;x<20;x++)
	{
		int h=Height[x];
		if(h>20)                                
		{                                       
		    int r=0;
			int r0=0;
			r=TopRow[x]-5;
			r0=TopRow[x]+h+5;
		
			if((r>0)&&(r0<height))
			{
//				for(int col=0;col<width;col++)
//			    {					
//					DisposeImg->ImgData[r*width+col]=255;			
//					DisposeImg->ImgData[r0*width+col]=255;						
//				}		

				TopRow[x]=r+5;
				Height[x]=h;		
			}
			else
			{
				if(r<=0)
				{		
					r=r+5;

					//for(int col=0;col<width;col++)
			  //      {
					//	DisposeImg->ImgData[r*width+col]=255;			
					//	DisposeImg->ImgData[r0*width+col]=255;							
					//}	
					TopRow[x]=r;
					Height[x]=h;
				}
				else
				{
					if(r0>=height)
					{
						r0=r0-5;					
						//for(int col=0;col<width;col++)
						//{
						//	DisposeImg->ImgData[r*width+col]=255;			
						//	DisposeImg->ImgData[r0*width+col]=255;	
						//}	
						Height[x]=Height[x]-5;
					}
				}
			}
		}
	}

	for(x=0;x<20;x++)
	{
		int h=Height[x];
		if(h<20||TopRow[x]<=100)
		{
			Height[x]=0;
			TopRow[x]=-1;
		}
	}	
}

/// <summary>
/// CDipView::VSearch(BYTE* DisposeImg, int width , int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:水平查找后,纵向查找。完成图象车牌区域的初步定位。即寻找出差分扫描后垂直跳变数最大的前30个区域。
/// 程序流程:1.利用间行扫描的方式找出跳变数最大的前30行;
///           2.对 Top 30 行进行区域增长;
///             其相似度的选取为:0.8~1.2 倍的该行跳变总数;
///           3.二值化,threshold=255;
///           4.任意选择一列,(本程序选择为第十行),搜索出各个带状候选域,存入标志;
/// </summary> 
//
void CDipView::VSearch(BYTE* DisposeImg, int width, int height)
{	
	BYTE *g=new BYTE[width*height];

    int *Count= new int[width];
	int *TempCount=new int[width];
	int *maxChanges=new int[30];
	int *Cols=new int[30];                  //maxChanges' col  

	CopyImg(DisposeImg,g,width,height);		
	 
	for(int c=0;c<width;c++)
	{
		Count[c]=0;
		TempCount[c]=0;
	}

	for(c=0;c<30;c++)
	{
        maxChanges[c]=0;
	    Cols[c]=0; 
		Widths[c]=0;
		Left[c]=-1;
	}

    for(int col=0;col<width;col++)
	{
		for(int row=0;row<height-1;row++)
		{	
			if(DisposeImg[row*width+col]!=DisposeImg[(row+1)*width+col])
				Count[col]++;		
		}
		TempCount[col]=Count[col];
	}

	/////////////////////////////////////Top 30 change col
	for(int top=0;top<30;top++)
	{
		int Max=0;
		for(int col=0;col<width;)
		{
			if(Max<TempCount[col])
			{
				Max=TempCount[col];
			}	
			col=col+10	;
		}
		maxChanges[top]=Max;

		int C=0;
    	for(col=0;col<width;)
		{
	    	if(Max!=TempCount[col])
			{
	    		col=col+10;				
			}	
			else
			{
				C=col;
				break;	
			}
		}
		Cols[top]=C;
		TempCount[C]=0;	
	}	
	
	for(top=0;top<30;top++)
	{
		for(int range=-20;range<20;range++)
		{
			if((Cols[top]+range)>=0&&(Cols[top]+range)<width)
			{
				if((0.8*Count[Cols[top]]<=Count[Cols[top]+range])&&(Count[Cols[top]+range]<=1.2*Count[Cols[top]]))		
				{
					for(int row=0;row<height;row++)
					{	
		        		DisposeImg[row*width+(Cols[top]+range)]=255;						
					}
				}
			}
			else
			{		
					continue;				
			}

		}
	}

	 for(int row=0;row<height;row++)
	 {
		for(int col=0;col<width;col++)
		{	
		    if(DisposeImg[row*width+col]<255)
			{
               DisposeImg[row*width+col]=0;
			}
		}
	 }	
	
	int Area=-1;                   //标识区域的地点
	if(DisposeImg[10*width+0]==255)
	{
		Area++;		
		Widths[Area]++;
	    Left[Area]=0;	
	}
	for(col=1;col<width;col++)
	{	
		if(DisposeImg[10*width+col]==255 && DisposeImg[10*width+(col-1)]==0)
		{
			Area++;		
			Widths[Area]++;
	    	Left[Area]=col;				
		}
		else 
		{
			if((DisposeImg[10*width+col]==255)&&(DisposeImg[10*width+col-1]==255))
			{
		    	Widths[Area]++;
			}		    
		}		
	 }
}

// 纵向定位
void CDipView::VMark(CDipDoc* DisposeImg, int width, int height)
{
	for(int x=0;x<30;x++)
	{
		int w=Widths[x];
		if(w>100)
		{
		    int c=0;
			int c0=0;
			c=Left[x];
			c0=Left[x]+w-10;

			if(c!=0&&c0>0)
			{
				//for(int row=0;row<height;row++)
				//{
				//	DisposeImg->ImgData[row*width+c]=255;			
				//	DisposeImg->ImgData[row*width+c0]=255;	
				//}	
				Widths[x]=Widths[x]-10;
			}
			else
			{
				if(c<=0)
				{
					c=5;				
					//for(int row=0;row<height;row++)
					//{
					//	DisposeImg->ImgData[row*width+c]=255;			
					//	DisposeImg->ImgData[row*width+c0]=255;	
					//}	
					Left[x]=c;
				}
				else
				{
					if(c0<=0)
					{
						c0=c0+10;
						//for(int row=0;row<height;row++)
					 //   {
						//	DisposeImg->ImgData[row*width+c]=255;			
						//	DisposeImg->ImgData[row*width+c0]=255;	
						//}	
						//Widths[x]=Widths[x]-5;
					}
				}
			}
		}
	}	

	for(x=0;x<30;x++)
	{
		int w=Widths[x];
		if(w<100)
		{
			Widths[x]=0;
			Left[x]=-1;
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -