📄 dipview.cpp
字号:
/// <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 + -