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

📄 dipview.cpp

📁 使用OpenCV和C++实现的车牌识别系统
💻 CPP
📖 第 1 页 / 共 5 页
字号:

/// <summary>
/// CDipView::DrawRect(CDipDoc* DisposeImg, int width, int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:利用先验知识标识车牌区域,进行车牌区域的选择,(横纵向)
/// 函数说明:国家标准:车牌的宽高比近似为3:1;
/// 程序流程:1.初始化存储数组
///           2.选择区域高宽比大于3的待选域
/// </summary> 
void CDipView::DrawRect(CDipDoc* DisposeImg, int width, int height)
{
	for(int x=0;x<50;x++)
	{
		Rect_X[x]=-1;
		Rect_Y[x]=-1;
		Rect_W[x]=0;
		Rect_H[x]=0;
	}
	
	Rect_Areas=0;

	for(int m=0;m<20;m++)
	{
		for(int n=0;n<30;n++)
		{
			if((Widths[n]>3*Height[m])&&(Widths[n]*Height[m]!=0))
			{
				Rect_Areas++;
				Rect_X[Rect_Areas-1]=Left[n];
				Rect_Y[Rect_Areas-1]=TopRow[m];
				Rect_W[Rect_Areas-1]=Widths[n];
				Rect_H[Rect_Areas-1]=Height[m];
			}
		}
	}

	//for( x=0;x<Rect_Areas;x++)
	//{
	//	for(int row=Rect_Y[x];row<(Rect_Y[x]+Rect_H[x]);row++)
	//	{
	//		DisposeImg->ImgData[row*width+Rect_X[x]]=255;
	//		DisposeImg->ImgData[row*width+Rect_X[x]+Rect_W[x]]=255;			
	//	}
	//}

	//for( x=0;x<Rect_Areas;x++)
	//{
	//	for(int col=Rect_X[x];col<(Rect_X[x]+Rect_W[x]);col++)
	//	{
	//		DisposeImg->ImgData[Rect_Y[x]*width+col]=255;
	//		DisposeImg->ImgData[(Rect_Y[x]+Rect_H[x])*width+col]=255;
	//	}
	//}
}


void CDipView::OnChoose() 
{
	// TODO: Add your command handler code here
}

/// <summary>
/// CDipView::Choose(CDipDoc *DisposeImg, int width, int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:再次利用利用跳变数选择车牌区域,进行车牌区域的最终选择,(横纵向)
/// 程序流程:1.初始化存储数组
///           2.计算每个伪车牌区域的跳变数
///           3.选择具有最大跳变数的区域为车牌区
/// </summary> 
void CDipView::Choose(CDipDoc *DisposeImg, int width, int height)
{
	int row=0;
	int col=0;

	int temp=0;

	int *JumpNums=new int[Rect_Areas];
	for(int area=0;area<Rect_Areas;area++)
	{
		JumpNums[area]=0;	
	}

	for(area=0;area<Rect_Areas;area++)    //计算每个伪车牌区域的行跳变数
	{
		BYTE* TempImg=new BYTE[Rect_W[area]*Rect_H[area]];

		for(row=0;row<Rect_H[area];row++)
		{
			for(col=0;col<Rect_W[area];col++)
			{
				TempImg[row*Rect_W[area]+col]=DisposeImg->ImgData[(Rect_Y[area]+row)*width+(Rect_X[area]+col)];
			}
		}

		JumpNums[area]=JumpNum(TempImg,Rect_W[area],Rect_H[area]);

		free(TempImg);
	}
	
	temp=MaxJump(JumpNums,Rect_Areas);

	// 区域刻画
/*	for(row=Rect_Y[temp];row<(Rect_Y[temp]+Rect_H[temp]);row++)
	{
		DisposeImg->ImgData[row*width+Rect_X[temp]]=255;
		DisposeImg->ImgData[row*width+(Rect_X[temp]+Rect_W[temp])]=255;	
	}
	
    for(col=Rect_X[temp];col<(Rect_X[temp]+Rect_W[temp]);col++)
	{
		DisposeImg->ImgData[Rect_Y[temp]*width+col]=255;
    	DisposeImg->ImgData[(Rect_Y[temp]+Rect_H[temp])*width+col]=255;
	}	*/

	//剔除伪车牌区
	for(area=0;area<Rect_Areas;area++)    
	{
		if(area!=temp)
		{
			Rect_X[area]=-1;
			Rect_Y[area]=-1;
			Rect_W[area]=0;
			Rect_H[area]=0;
		}		
	}

	//移至第一位
	Rect_X[0]=Rect_X[temp];
	Rect_Y[0]=Rect_Y[temp];
	Rect_W[0]=Rect_W[temp];
	Rect_H[0]=Rect_H[temp];

	//清空
	if(temp!=0)
	{
		Rect_X[temp]=-1;
		Rect_Y[temp]=-1;
		Rect_W[temp]=0;
		Rect_H[temp]=0;
	}

	Rect_Areas=1;
}

/// <summary>
/// CDipView::JumpNum(BYTE *DisposeImg,int width,int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:计算伪车牌区的跳变平均数
/// 程序流程:1.初始化;
///           2.水平差分,边缘提取;
///           3.选择车牌的中间1/3行来计算每个伪车牌区域的跳变平均数;
/// </summary>
/// <return>各个区域的平均跳变数</return>
int CDipView::JumpNum(BYTE *DisposeImg,int width,int height)
{
	int startRow=0;
	int endRow=0;
	long JumpNum=0;
	int averJump=0;
	int r=0;

	BYTE* g=new BYTE[width*height];
    CopyImg(DisposeImg,g,width,height);
	
	HSub(g,width,height);	

	startRow=(int)(0+height/3);
	endRow=(int)(0+2*height/3);	

	for(int row=startRow;row<endRow;row++)
	{
		for(int col=0;col<width-1;col++)
		{
			if(g[row*width+col]!=g[row*width+col+1])			
				JumpNum++;			
		}
	}

	r=endRow-startRow;
	averJump=(int)(JumpNum/r);

	free(g);

	return averJump;
}

/// <summary>
/// CDipView::MaxJump(int *JumpNums,int num)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:找出所有伪车牌区域中具有最大跳变平均数的区域号
/// 程序说明:选择排序
/// </summary>
/// <return>最大跳变平均数的区域号</return>
int CDipView::MaxJump(int *JumpNums,int num)
{	
	int area=0;
	int temp=0;
	int val=0;

	val=JumpNums[0];
	for(area=0;area<num;area++)
	{
		if(JumpNums[area]>val)
		{
			temp=area;
			val=JumpNums[area];
		}
	}

	return temp;
}

/// <summary>
/// CDipView::FurtherLocate(CDipDoc *DisposeImg,int width,int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:精确定位车牌
/// 程序流程:
/// 程序说明:由于水平分割出的伪车牌区域已经比较准确,故仅作垂直方向的进一步定位(缩小宽度)
/// </summary>
void CDipView::FurtherLocate(CDipDoc *DisposeImg,int width,int height)
{
	int row=0;
	int col=0;

	//copy 到一个暂存数组,以便处理操作且不破坏原图象
	BYTE* TempImg=new BYTE[Rect_W[0]*Rect_H[0]];
	for(row=0;row<Rect_H[0];row++)
	{
		for(col=0;col<Rect_W[0];col++)
		{
			TempImg[row*Rect_W[0]+col]=DisposeImg->ImgData[(Rect_Y[0]+row)*width+(Rect_X[0]+col)];
		}
	}
	
	VFurthLocate(TempImg,Rect_W[0],Rect_H[0]);

/*	int temp=0;
	// 区域刻画
	for(row=Rect_Y[temp];row<(Rect_Y[temp]+Rect_H[temp]);row++)
	{
		DisposeImg->ImgData[row*width+Rect_X[temp]]=255;
		DisposeImg->ImgData[row*width+(Rect_X[temp]+Rect_W[temp])]=255;	
	}
	
    for(col=Rect_X[temp];col<(Rect_X[temp]+Rect_W[temp]);col++)
	{
		DisposeImg->ImgData[Rect_Y[temp]*width+col]=255;
    	DisposeImg->ImgData[(Rect_Y[temp]+Rect_H[temp])*width+col]=255;
	}	*/

	free(TempImg);
}

/// <summary>
/// CDipView::VFurthLocate(BYTE *DisposeImg, int width, int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:找出车牌的左右边缘
/// 程序流程:1.水平差分,二值化;
///           2.垂直方向投影,统计各列的投影值;
///           3.去除噪声点;
///           4.找出左右边缘
///           5.计算车牌宽度
///           6.车牌精确定位赋值
/// </summary>
void CDipView::VFurthLocate(BYTE *DisposeImg, int width, int height)
{
	int row=0;
	int col=0;
	int num=0;

	int leftCol=0;
	int rightCol=width-1;

	HSub(DisposeImg,width,height); 
	ForHandle(DisposeImg,width,height);                           //二值化

    //note the value of hProjection
	int*HProj=new int[width];                        
	for(col=0;col<width;col++)
	{
		HProj[col]=0;
	}    
	for(col=0;col<width;col++)
	{
		for(row=0;row<height;row++)
		{	
			if(DisposeImg[row*width+col]==255)
				HProj[col]++;		
		}	
	}
	HProj[0]=0;
	for(col=0;col<width;col++)                    //去除噪声点
	{
		if(HProj[col]<3)
		{
			HProj[col]=0;
		}
	}    

	///////////////////////////////////////////找出左边缘
	int nextCol=0;
	int w=0;
	for(col=0;col<width;col++)
	{
		num=0;
		if(HProj[col]==0&&HProj[col+1]!=0)
		{
			num++;		
			nextCol=FindNextCol_LR(HProj,width,col);
			w=nextCol-col;
			leftCol=col;
		}
		if(w<3)
		{
			num=num-1;
		}
		if(num==1)
		{
			break;
		}
	}	

	//////////////////////////////////////////找出右边缘
	nextCol=0;
	w=0;
	for(col=width;col>=0;col--)
	{
		num=0;
		if(HProj[col]==0&&HProj[col-1]!=0)
		{
			num++;		
			nextCol=FindNextCol_RL(HProj,width,col);
			w=col-nextCol;
			rightCol=col;
		}
		if(w<3)
		{
			num=num-1;
		}
		if(num==1)
		{
			break;
		}
	}	
	
	int blantCols=0;
	blantCols=leftCol+(width-rightCol);

	Rect_X[0]+=leftCol;
	Rect_W[0]=width-blantCols;

	free(HProj);
}

/// <summary>
/// CDipView::ForHandle(BYTE *DisposeImg, int width, int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:二值化图象
/// 程序说明:threshold=average+delt;
/// 程序流程:1.计算图象均值;
///           2.计算图象方差;
///           3.二值化
/// </summary>
void CDipView::ForHandle(BYTE *DisposeImg, int width, int height)
{	
	 BYTE *temp=new BYTE[height*width];
	 int x,y;	

	 CopyImg(DisposeImg,temp,width,height);
	
	 long double total=0;
	 float aver=0;
	 for(x=0;x<height;x++)
	 {
		 for(y=0;y<width;y++)
		 {	
			 total+=DisposeImg[x*width+y];			
		 }
	 }
	 aver=(BYTE)(total/(float)(height*width));

	 float delt; 
	 float sub=0; 
	 for(x=0;x<height;x++)
	 {
		 for(y=0;y<width;y++)
		 {			
			 sub+=(DisposeImg[x*width+y]-aver)*(DisposeImg[x*width+y]-aver);			 
		 }
	 }
	 delt=(float)(sqrt(sub/(float)(height*width)));

	 BYTE judge;
	 judge=(BYTE)(delt+aver);
	 for(x=0;x<height;x++)
	 {
		for(y=0;y<width;y++)
		 {
			if(DisposeImg[(x*width)+y]>=judge)
			{
				DisposeImg[(x*width)+y]=255;
			}
			else
			{
				DisposeImg[(x*width)+y]=0;
			}
		}
	}
	 
	 free(temp);	
}

// 寻找left==255,right==0的列
int CDipView::FindNextCol_LR(int* HProj, int size, int objectCol)
{
	int num=0;
	int x=0;
	for(x=objectCol;x<size;x++)
	{
		if(HProj[x]>=0&&HProj[x+1]==0)
		{
			num++;			
		}

		if(num==1)
		{
			break;
		}
	}	

	if(num==0)
	{
		return objectCol; 
	}
	else
	{
		return x;
	}	
}

// 寻找right==255,left==0的列
int CDipView::FindNextCol_RL(int* HProj, int size, int objectCol)
{
	int num=0;
	int x=0;
	for(x=objectCol;x>=0;x--)
	{
		if(HProj[x]>=0&&HProj[x-1]==0)
		{
			num++;			
		}

		if(num==1)
		{
			break;
		}
	}	

	if(num==0)
	{
		return objectCol; 
	}
	else
	{
		return x;
	}		
}

void CDipView::OnSobel()
{
	// TODO: 在此添加命令处理程序代码	
}


/// <summary>
/// CDipView::OnVSplit()的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:车牌字符分割
/// 程序流程:1.区域扩展;
///           2.投影分割;
///           3.字符区域的获取;
/// </summary>
void CDipView::OnVSplit()
{
	// TODO: 在此添加命令处理程序代码
	CDipDoc *pDoc=GetDocument();

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

	int row=0;
	int col=0;
	
	//extend area
	int threshold=2;

	Rect_X[0]=Rect_X[0];
	Rect_Y[0]=Rect_Y[0];//-threshold;
	Rect_W[0]=Rect_W[0]+7;
	Rect_H[0]=Rect_H[0];//+2*threshold;

	//车牌区域的高度、宽度
	int w=Rect_W[0];
	int h=Rect_H[0];
	
	BYTE* TempImg=new BYTE[w*h];	
	for(row=0;row<h;row++)
	{
		for(col=0;col<w;col++)
		{
			TempImg[row*w+col]=pDoc->ImgData[(Rect_Y[0]+row)*width+(Rect_X[0]+col)];
		}
	}

	//二值化车牌区域图象
	ForHandle(TempImg,w,h);
	
	//搜索各字符域
	int *projArray=new int[w];
	for(col=0;col<w;col++)
	{
		projArray[col]=0;
	}

	HProj(TempImg,projArray,w,h);
	CharacterSplit(projArray,w);
//	GetCharacter();

	///////////////////////////////标记出各个字符区域
	int area;
	area=CharacterNum;
	for(;area>=0;area--)
	{
		if(cRects[area].w!=0&&cRects[area].x!=-1)
		{
			for(row=cRects[area].y;row<(cRects[area].y+cRects[area].h);row++)  //draw vertical line
			{
				pDoc->ImgData[row*width+cRects[area].x]=255;
				pDoc->ImgData[row*width+(cRects[area].x+cRects[area].w)]=255;	
			}

	    	for(col=cRects[area].x;col<(cRects[area].x+cRects[area].w);col++)    //draw horizontal line
			{
				pDoc->ImgData[cRects[area].y*width+col]=255;
				pDoc->ImgData[(cRects[area].y+cRects[area].h)*width+col]=255;
			}	
		}				
	}

	// 区域刻画
	//int temp=0;
	//for(row=Rect_Y[temp];row<(Rect_Y[temp]+Rect_H[temp]);row++)
	//{
	//	pDoc->ImgData[row*width+Rect_X[temp]]=255;
	//	pDoc->ImgData[row*width+(Rect_X[temp]+Rect_W[temp])]=255;	
	//}
	//
 //   for(col=Rect_X[temp];col<(Rect_X[temp]+Rect_W[temp]);col++)
	//{
	//	pDoc->ImgData[Rect_Y[temp]*width+col]=255;
 //   	pDoc->ImgData[(Rect_Y[temp]+Rect_H[temp])*width+col]=255;
	//}

	//for(row=Rect_Y[temp];row<(Rect_Y[temp]+Rect_H[temp]);row++)
	//{
	//	for(col=0;col<w;col++)
	//	{
	//		if(projArray[col]==1)
	//		{
	//			pDoc->ImgData[row*width+Rect_X[temp]+col]=255;
	//		//	pDoc->ImgData[row*width+(Rect_X[temp]+Rect_W[temp])]=255;	
	//		}
	//	}
	//}

	free(TempImg);
	free(projArray);

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

// 图像规定化0~100
void CDipView::GuiYiHua(BYTE* DisposeImg, int width , int height)
{	
}

// 增强车牌区,削弱背景
void CDipView::Hance(BYTE* DisposeImg, int width , int height)
{	
}

void CDipView::OnGuiYiHua()
{
	// TODO: 在此添加命令处理程序代码	
}

void CDipView::OnHance()
{
	// TODO: 在此添加命令处理程序代码	
}

/// <summary>
/// CDipView::HProj(BYTE* DisposeImg, int* projArray, int width , int height)的摘要说明。
/// 创建人  :刘陈炜
/// 创建时间:2004.5.1
/// 函数功能:水平方向投影,分割出字符
/// 程序流程:1.统计各列白象素个数;
///           2.平滑投影曲线;
///           3.寻找波谷(trough)进行分割;
/// </summary>
void CDipView::HProj(BYTE* DisposeImg, int* projArray, int width , int height)

⌨️ 快捷键说明

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