📄 filters.cs
字号:
dividend+=15;
}
else if (pp[0]>210)
{
sum+=pp[0]*10;
dividend+=10;
}
else if (p[0]>200)
{
sum+=pp[0]*5;
dividend+=5;
}
}
pp=p;
}
sum=sum/dividend;
if (sum>255)
{
sum = 255;
}
p[0]=p[1]=p[2]=(byte)(sum);
}
tt = p[0];
newGray[tt]++;
p+=3;
}
p += nOffset;
}
}
outGray = newGray;
b.UnlockBits(bmData);
return true;
}
/*
* 定位车牌位置
*/
public static bool MarginalFilter(Bitmap b,out int[] outGray,out int outCount,float valve,out int outxu,out int outxd,out int outyl,out int outyr,out int outMaxX,out int outMaxY)
{
BitmapData bmData = b.LockBits(new Rectangle(0, 0,b.Width , b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int[] newGray = new int[256];
foreach(int i in newGray)
{
newGray[i]=0;
}
unsafe
{
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
byte * p = (byte *)(void *)Scan0;
byte * pp;
int tt;
int nOffset = stride - b.Width*3;
int nWidth=b.Width;
int nHeight=b.Height;
int Sx = 0;
int Sy = 0;
// float max = 0;
double sumM = 0;
double sumCount = 0;
//sobel模板
int[] marginalMx = {-1,0,1,-2,0,2,-1,0,1};
int[] marginalMy = {1,2,1,0,0,0,-1,-2,-1};
float[,] m = new float[nHeight,nWidth];
int[,] dlta = new int[nHeight,nWidth];
int div=7;
int lv=11;
long sM=0;
int ccm=0;
int pWR,pWL,pWHL,pWHR,pWH;
int Wmin = 1 ;
int Wmax = 9 ;
int Bmin = 1 ;
int Bmax = 5 ;
bool getStart ;
bool[] lineLabel= new bool[(int)(nHeight/div)+1];
double[] sumC= new double[(int)(nHeight/div)+1];
int[,] countMatch = new int[(int)(nHeight/div)+1,(int)(nWidth/lv)+1];
int[,] mark = new int[(int)(nHeight/div)+1,nWidth];
//////////////////////////////////////////////////////////////////////////
//获取图像边缘 并且二值化
//////////////////////////////////////////////////////////////////////////
//sobel算子
for(int y=0;y < nHeight;++y)
{
for(int x=0; x < nWidth; ++x )
{
if(!(x<=0||x>=nWidth-1||y<=0||y>=nHeight-1))
{
pp=p;
Sx = 0;
Sy = 0;
for(int i = -1;i<= 1;i++)
for(int j = -1;j<= 1;j++)
{
pp+=(j*3+stride*i);
Sx+=pp[0]* marginalMx[(i+1)*3+j+1];
Sy+=pp[0]* marginalMy[(i+1)*3+j+1];
pp=p;
}
m[y,x] =(int)( Math.Sqrt(Sx*Sx+Sy*Sy));
//增强白点
if (m[y,x]>valve/2)
{
if (p[0]>240)
{
m[y,x]+=valve;
}
else if(p[0]>220)
{
m[y,x]+=(float)(valve*0.8);
}
else if (p[0]>200)
{
m[y,x]+=(float)(valve*0.6);
}
else if (p[0]>180)
{
m[y,x]+=(float)(valve*0.4);
}
else if (p[0]>160)
{
m[y,x]+=(float)(valve*0.2);
}
}
float tan ;
if (Sx!= 0)
{
tan = Sy/Sx;
}
else tan = 10000;
if (-0.41421356<=tan && tan < 0.41421356)
{
dlta[y,x] = 0;
// m[y,x]+=valve;
}
else if (0.41421356<=tan&&tan<2.41421356)
{
dlta[y,x] = 1;
//m[y,x] = 0;
}
else if (tan>=2.41421356||tan<-2.41421356)
{
dlta[y,x] = 2;
// m[y,x]+=valve;
}
else
{
dlta[y,x] = 3;
//m[y,x] = 0;
}
}
else
m[y,x]=0;
p+=3;
if (m[y,x]>0)
{
sumCount++;
sumM += m[y,x];
}
}
p += nOffset;
}
//非极大值抑制和阀值
p = (byte *)(void *)Scan0;
for(int y=0;y < nHeight;++y)
{
for(int x=0; x < nWidth; ++x )
{
if (m[y,x]>sumM/sumCount*1.2)
{
p[0] = p[1] = p[2] = (byte)(m[y,x]);
//m[y,x]=1;
}
else
{
m[y,x] = 0;
p[0] = p[1] = p[2] = 0;
}
if(x>=1&&x<=nWidth-1&&y>=1&&y<=nHeight-1&&m[y,x]>valve)
{
switch(dlta[y,x])
{
case 0 :
if (m[y,x]>=m[y,x-1]&&m[y,x]>=m[y,x+1])
{
p[0] = p[1] = p[2] = 255;
}
break;
case 1:
if (m[y,x]>=m[y+1,x-1]&&m[y,x]>=m[y-1,x+1])
{
p[0] = p[1] = p[2] = 255;
}
break;
case 2:
if (m[y,x]>=m[y-1,x]&&m[y,x]>=m[y+1,x])
{
p[0] = p[1] = p[2] = 255;
}
break;
case 3:
if (m[y,x]>=m[y+1,x+1]&&m[y,x]>=m[y-1,x-1])
{
p[0] = p[1] = p[2] = 255;
}
break;
}
}
if (p[0]==255)
{
m[y,x]=1;
}
else
{
m[y,x]=0;
p[0] = p[1] = p[2] = 0;
}
tt = p[0];
newGray[tt]++;
p+=3;
}
p += nOffset;
}
//////////////////////////////////////////////////////////////////////////
//水平扫描(每div像素一次),识别字符特征
//////////////////////////////////////////////////////////////////////////
for (int i=0;i<(int)(nHeight/div)+1;i++)
{
for ( int j=0;j<(int)(nWidth/lv)+1 ;j++)
{
countMatch[i,j]=0;
}
}
p = (byte *)(void *)Scan0;
for(int y=2*div;y < nHeight-2*div;)
{
for (int j=0;j<nWidth;j++)
{
mark[y/div,j]=0;
}
for (int i =0;i<div;i++)
{
getStart = true;
for(pWR=pWL=pWHL=pWHR=pWH=4; pWH< nWidth-1; pWH++ )
{
//标记每行的第一个白点
if (getStart)
{
if (m[y+i,pWH]>0)
{
getStart = false;
pWR=pWL=pWHL=pWHR=pWH;
}
else
continue;
}
if (pWR-pWL>nWidth/3||pWHL-pWR>nWidth/3||pWHR-pWHL>nWidth/3)
{
goto L;
}
if ( m[y+i,pWH-1]>0&&m[y+i,pWH]<=0)//白-->黑
{
pWHR=pWH-1;
if (pWL!=pWHL )
{
if( (Wmin<=(pWR-pWL)&&(pWR-pWL)<=Wmax)
||( Bmin<=(pWHL-pWR-1)&&(pWHL-pWR-1)<=Bmax)
||( Wmin<=(pWHR-pWHL)&&(pWHR-pWHL)<=Wmax ) )
{
//记录该点
//if (pWR-pWL+pWHR-pWHL<11)
if (-pWL+pWHR<30)
{
double rate1=Wmax/(Math.Abs((pWR-pWL)-(Wmax-Wmin))/2+1);
double rate2=Wmax/(Math.Abs((pWHR-pWHL)-(Wmax-Wmin))/2+1);
double rate3=Bmax*3/(pWHL-pWR);
mark[y/div,pWL+(pWR-pWL)/2]+=(int)(rate3+rate2+rate2);
}
}
if (pWR-pWL>2*lv)
{ //连续白(或)宽于一个字符宽度
for (int t=pWL+lv/2;t<pWR-lv/2;t+=lv)
{
countMatch[y/div,t/lv]=-1;
}
//countMatch[y/div,pWR/lv]=-1;
}
if (pWHL-pWR-1>2*lv)
{
for (int t=pWR+lv/2;t<pWHL-lv/2;t+=lv)
{
countMatch[y/div,t/lv]-=1;
}
//countMatch[y/div,pWHL/lv]=-1;
}
if (pWHR-pWHL>2*lv)
{
for (int t=pWHL+lv/2;t<pWHR-lv/2;t+=lv)
{
countMatch[y/div,t/lv]-=1;
}
//countMatch[y/div,pWHR/lv]=-1;
}
}
pWR=pWHR;
pWL=pWHL;
}
else if ( m[y+i,pWH-1]<=0&&m[y+i,pWH]>0)//黑-->白
{
pWHL=pWH;
}
}
}
L:y+=div;
}
//////////////////////////////////////////////////////////////////////////
//去除噪音
//////////////////////////////////////////////////////////////////////////
///
//基与特征点水平间隔的去噪
int toCheck=-1;
foreach (int i in sumC)
{
sumC[i]=0;
}
sM=0;
ccm=0;
//累计连续的特征点
for (int i=2;i<(int)(nHeight/div)-1;i++)
{
toCheck=-1;
lineLabel[i]=false;
//sumLX=0;
pWL=pWR=1;
getStart = true;
for (int j=1;j<nWidth;j++)
{
//标记每行的第一个白点
if (getStart)
{
if (m[i,j]>0)
{
getStart = false;
pWR=pWL=j;
}
else
continue;
}
///*
if (mark[i,j]>0)
{
if (toCheck==-1)
{
toCheck=j;
continue;
}
else
{
if (j-toCheck<=1)
{//////////////////////////////////////////////////////////////////////////
if (countMatch[i,j/lv]>=0)
{
countMatch[i,j/lv]+=(mark[i,toCheck]+mark[i,j]);//两个点相互匹配,累加2
}
toCheck=-1;
//lineLabel[i]=true;
continue;
}
else
{
//mark[i,toCheck]-=(int)(div*0.8);//除去该特征点
if (mark[i,toCheck]<(div*0.7))
{
mark[i,toCheck]=0;
}
else
{
countMatch[i,j/lv]+=2*mark[i,toCheck];
}
toCheck=j;
continue;
}
}
}
}
}
//阀值化
sM=0;
ccm=0;
int va=(int)(lv*div/3);
int[] countL = new int[(int)(nHeight/div)+1] ;
for (int i=0;i<(int)(nHeight/div)+1;i++)
{
bool ok ;
ok = false;
countL[i]=0;
lineLabel[i]=false;
for(int j=0; j < (int)(nWidth/lv)+1 ; ++j )
{
//图像周边特征点为零
if (i==0||i==(int)(nHeight/div)||j==0||j==(int)(nWidth/lv))
{
countMatch[i,j]=0;
continue;
}
if (countMatch[i,j]>va)
{//阀值去噪音
if ( (countMatch[i,j-1]<=va&&countMatch[i,j+1]<=va)||//去除孤立点(水平)
(countMatch[i-1,j]<=va&&(countMatch[i+1,j]<=va||(countMatch[i+1,j-1]<=va&&countMatch[i+1,j+1]<=va))) )//去除孤立点(垂直)
{
countMatch[i,j]=0;
}
else
{
countL[i]+=countMatch[i,j];
ok=true;
}
}
else
countMatch[i,j]=0;
}
if (ok)
{
lineLabel[i]=true;
sM+=countL[i];
ccm++;
}
}
//去除上半部分大面积的噪音
int v1=0,v2=0;
int vm1=0,vm2=0;
int maxL=0,cv=0;
for (int i=1;i<(int)(nHeight/div)+1;i++)
{
if (lineLabel[i]==true&&lineLabel[i-1]==false)
{
v1=i;
v2=i;
}
else if (lineLabel[i]==false&&lineLabel[i-1]==true)
{
v2=i;
cv++;
if (maxL<v2-v1)
{
vm1=v1;
vm2=v2;
maxL=v2-v1;
}
}
}
if (cv>1&&vm2-vm1>5&&vm1+(vm2-vm1+1)/2<(nHeight/div)/3||vm2-vm1>nHeight/div/2)
{
for (int k=vm1;k<=vm2;k++)
{
lineLabel[k]=false;
}
}
int p1=0,p2=0;
for (int i=0;i<(int)(nHeight/div)+1;i++)
{
if (lineLabel[i]==true)
{
p1=0;p2=0;
bool ok=false;
for (int j=1;j<(int)(nWidth/lv)+1;j++)
{
if (countMatch[i,j-1]==0&&countMatch[i,j]>0)
{
p1=p2=j;
}
if (countMatch[i,j-1]>0&&countMatch[i,j]==0)
{
p2=j-1;
if (p2-p1>0)
{
ok=true;
}
else
{
p2=p1=0;
countMatch[i,j-1]=0;
}
}
}
if (!ok&&p2==0&&p1==0)
{
lineLabel[i]=false;
}
}
}
//////////////////////////////////////////////////////////////////////////
//使用2×6矩阵粗定位
//////////////////////////////////////////////////////////////////////////
int lLenght=5,vLenght=1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -