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