📄 filters.cs
字号:
int maxAverage=0;
int maxX=0;
int maxY=0;
for (int i=0;i<(int)(nHeight/div)+1;i++)
{
if (lineLabel[i]==true&&lineLabel[i+1]==true)
{
for(int j=0; j < (int)(nWidth/lv)-lLenght ; ++j )
{
int average =countMatch[i,j] +countMatch[i,j+1] +countMatch[i,j+2]
+countMatch[i,j+3]+countMatch[i,j+4] +countMatch[i,j+5]// +countMatch[i,j+6]
+countMatch[i+1,j]+countMatch[i+1,j+1]+countMatch[i+1,j+2]
+countMatch[i+1,j+3]+countMatch[i+1,j+4] +countMatch[i+1,j+5];// +countMatch[i+1,j+6] ;
average=average/(lLenght+1)/(vLenght+1);
if (maxAverage<average)
{
maxAverage=average;
maxX=i;
maxY=j;
}
}
}
}
bool jx1=true,jx2=true;
int x1=0,x2=0;
for (int j=0;jx1||jx2;j++)
{
if (jx1&&lineLabel[maxX-j]==false)
{
jx1=false;
x1=maxX-j;
}
if (jx2&&lineLabel[maxX+j]==false)
{
jx2=false;
x2=maxX+j;
}
}
for (int i=0;i<x1;i++)
{
lineLabel[i]=false;
}
for (int i=x2;i<(int)(nHeight/div)+1;i++)
{
lineLabel[i]=false;
}
//////////////////////////////////////////////////////////////////////////
//寻找车牌的四边
//////////////////////////////////////////////////////////////////////////
// 位置调整
int lKZValve=(int)(maxAverage/3);
int vKZValve=(int)(maxAverage/2.5);
//int kz1=0,kz2=0;
int pX1=0,pX2=0,pX3=0,pX4=0,pY1=0,pY2=0,pY3=0,pY4=0; //用于搜索边框的范围
int pXU=0,pXD=0,pYL=0,pYR=0,pXM=0,pYM=0;
//除去两边噪音
bool l=true,r=true;
pY1=maxY;
pY4=maxY+lLenght;
for (int j=1;l||r;j++)
{
if (maxY-j<0&&l)
{
l=false;
//pY1=0;
}
else if ( l&&countMatch[maxX,maxY-j]<vKZValve&&countMatch[maxX+1,maxY-j]<vKZValve)
{
if (maxY-j-2>=0&&countMatch[maxX,maxY-j-2]<vKZValve&&countMatch[maxX+1,maxY-j-2]<vKZValve)
{
l=false;
pY1=maxY-j+1;
}
}
if (maxY+lLenght+j>(int)(nWidth/lv)&&r)
{
r=false;
pY4=(int)(nWidth/lv);
}
else if (r&&countMatch[maxX,maxY+lLenght+j]<vKZValve&&countMatch[maxX+1,maxY+lLenght+j]<vKZValve)
{
if (maxY+lLenght+j+2<(int)(nWidth/lv)+1&&countMatch[maxX,maxY+lLenght+j+2]<vKZValve&&countMatch[maxX+1,maxY+lLenght+j+2]<vKZValve)
{
r=false;
pY4=maxY+lLenght+j-1;
}
}
}
pY2=(pY1+1)*lv;
pY3=(pY4-1)*lv;
// 进一步去除不必要的边线
bool u=true,d=true;
pX1=maxX;
pX4=maxX+vLenght;
while (u||d)
{
if (u&&pX1-1<0)
{
u=false;
//pX1=0;
}
else if (u&&lineLabel[pX1-1])
{
bool ok=false;
for (int j=pY1;j<=pY4;j++)
{
if (pX1-1>=0&&countMatch[pX1-1,j]>lKZValve)
{
ok=true;
pX1--;
break;
}
}
if (!ok)
{
u=false;
}
}
else
u=false;
if (d&&pX4+1>(int)(nHeight/div))
{
d=false;
}
else if (d&&lineLabel[pX4+1])
{
bool ok=false;
for (int j=pY1;j<=pY4;j++)
{
if (pX4+1<(int)(nHeight/div)+1&&countMatch[pX4+1,j]>lKZValve)
{
ok=true;
pX4++;
break;
}
}
if (!ok)
{
d=false;
}
}
else
d=false;
}
pXM=pX1*div+(pX4-pX1)/2*div;
pYM=pY1*lv+(pY4-pY1)/2*lv;
//maxX=x1;
vLenght=x2-x1;
//水平再调整
l=true;r=true;
while (l||r)
{
if (pY1-1<0&&l)
{
l=false;
}
else if(l)
{
bool match=false;
for (int i=0;i<=vLenght;i++)
{
if (countMatch[x1+i,pY1-1]>vKZValve)
{
match=true;
break;
}
}
if (!match)
{
l=false;
}
else
pY1--;
}
if (pY4+1>(int)(nWidth/lv)&&r)
{
r=false;
}
else if(r)
{
bool match=false;
for (int i=0;i<=vLenght;i++)
{
if (countMatch[x1+i,pY4+1]>vKZValve)
{
match=true;
break;
}
}
if (!match)
{
r=false;
}
else
pY4++;
}
}
for (int i=0;i<pX1;i++)
{
lineLabel[i]=false;
}
for (int i=pX4+1;i<(int)(nHeight/div)+1;i++)
{
lineLabel[i]=false;
}
pX2=x1*div-div/2;
if (pX2<0) {
pX2=0;
}
pX3=x2*div+div/2;
if (pX3>=nHeight) {
pX3=nHeight-1;
}
pYL=pY1*lv;//-lv;
bool kz=false;
for (int i=x1;i<=x2;i++)
{
if (countMatch[i,pY1]>vKZValve)
{
kz=true;
break;
}
if (pY1-1>=0&&countMatch[i,pY1-1]>vKZValve)
{
pYL-=lv;
break;
}
}
if (kz)
{
pYL-=lv/2;
}
if (pYL<=0) {
pYL=0;
}
pYR=(pY4+1)*lv+lv/2;//+lv;
kz=false;
for (int i=x1;i<=x2;i++) {
if (pY4+1<(int )(nWidth/lv)+1&& countMatch[i,pY4+1]>vKZValve) {
kz=true;
break;
}
if (pY4+2<(int )(nWidth/lv)+1&&countMatch[i,pY4+2]>vKZValve)
{
pYR+=lv;
break;
}
}
if (kz) {
pYR+=lv/2;
}
if (pYR>=nWidth) {
pYR=nWidth-1;
}
if (pX4-pX1<=3)
{
if (pX1-1>=0)
{
pXU=(pX1-1)*div;
}
else
pXU=0;
if (pX4+2>=(int)(nHeight/div))
{
pXD=nHeight;
}
else
pXD=(int)((pX4+1.5)*div+div);
}
else if (4<=pX4-pX1&&pX4-pX1<=5)
{
pXU=pX1*div-div/2;
pXD=(pX4+1)*div+div/2;
}
else
pXU=pX1*div;
pXD=(int)((pX4+1.5)*div-div/2);
pXD+=div/2;
if (pXD>nHeight-1) {
pXD=nHeight-1;
}
pYL-=lv/2;
if (pYL<0) {
pYL=0;
}
//调整截取的边缘
LR(m,pX2,pX3,pYL,pYR,out pYL,out pYR);
UD(m,pXU,pXD,pYL,pYR,out pXU,out pXD);
///////////////////////////////////////////////////////////////////////////
//在图像上添加辅助线
//////////////////////////////////////////////////////////////////////////
//显示边框
p = (byte *)(void *)Scan0;
pp = p;
for (int i=0;i<nHeight;i++)
{
if(i==pXU||i==pXD)
{
for (int j=pYL;j<=pYR;j++)
{
pp=p+i*stride+j*3;
pp[2]=255;pp[0]=pp[1]=0;
}
}
else if (pXU<i&&i<pXD)
{
pp=p+i*stride+pYL*3;
pp[2]=255;pp[0]=pp[1]=0;
pp=p+i*stride+pYR*3;
pp[2]=255;pp[0]=pp[1]=0;
}
}
//截取的行线显示在图上
p = (byte *)(void *)Scan0;
pp = p;
for (int i=0;i<(int)(nHeight/div)-1;i++)
{
//画垂线
for (int k=0;k<nWidth+1;k+=lv)
{
pp=p+(i*div+div/2)*stride+k*3;
pp[2]=255;
}
//在车牌所在水平区域画出横线
if (lineLabel[i])
{
for(int j=0; j < nWidth; ++j )
{
pp=p+(i*div+div/2)*stride+j*3;
pp[2]=255;
}
}
}
outCount=ccm;
outCount=maxAverage;
outxu=pXU;
outxd=pXD;
outyl=pYL;
outyr=pYR;
outMaxX=maxX*div-pXU;
outMaxY=maxY*lv-pYL;
}
outGray = newGray;
b.UnlockBits(bmData);
return true;
}
/*
* 调整车牌左右位置
*/
private static bool LR( float[,] m, int xu,int xd,int yl,int yr,out int pYL,out int pYR)
{
int[] projection=new int[yr-yl+1];
foreach (int i in projection)
{
projection[i]=0;
}
//垂直投影
for (int i=xu;i<=xd;i++)
{
for (int j=yl;j<=yr;j++)
{
if (m[i,j]>0)
{
projection[j-yl]++;
}
}
}
bool l=true,r=true;
int temp_yr=yr,temp_yl=yl;
while (l||r)
{
if (temp_yr-temp_yl<=60)
{
l=r=false;
}
if (l&&projection[temp_yl-yl]<5){
temp_yl++;
}
else
{
l=false;
}
if (r&&projection[temp_yr-yl]<5)
{
temp_yr--;
}
else
{
r=false;
}
}
pYL=temp_yl;
pYR=temp_yr;
return true;
}
/*
* 调整车牌上下位置
*/
private static bool UD(float[,] m,int pXU,int pXD,int pYL,int pYR,out int xu,out int xd)
{
int[] projection=new int[pXD-pXU+1];
foreach (int i in projection)
{
projection[i]=0;
}
//水平投影
for (int i=pXU;i<=pXD;i++) {
for (int j=pYL;j<=pYR;j++) {
if (m[i,j]>0)
{
projection[i-pXU]++;
}
}
}
bool u=true,d=true;
int temp_xd=pXD-1,temp_xu=pXU+1;
while (u||d)
{
if (temp_xd-temp_xu<=60)
{
u=d=false;
}
if (u&&projection[temp_xu-pXU]<2)
{
temp_xu++;
}
else
{
u=false;
}
if (d&&projection[temp_xd-pXU]<2)
{
temp_xd--;
}
else
{
d=false;
}
}
xu=temp_xu;
xd=temp_xd;
return true;
}
/*
* 对车牌图像二值化
*/
public static bool TowValue(Bitmap b,Bitmap c_Bitmap, int maxX,int maxY)
{
int[] c_gray=new int[256];
int[] c_r=new int[256];
int[] c_g=new int[256];
int[] c_b=new int[256];
zft(b,out c_gray,out c_r,out c_g,out c_b);
//获取车牌小区域的灰度阶
int Mr=0;//灰度均值
long sum=0;
int count=0;
for (int i=0;i<256;i++) {
sum+=c_gray[i]*i;
count+=c_gray[i];
}
Mr=(int)(sum /count);
int sum1=0;
int count1=0;
for (int i=0;i<=Mr;i++) {
sum1+=c_gray[i]*i;
count1+=c_gray[i];
}
int g1=sum1/count1;
int sum2=0;
int count2=0;
for (int i=Mr;i<=255;i++)
{
sum2+=c_gray[i]*i;
count2+=c_gray[i];
}
int g2=sum2/count2;
//求阀值
int va;
if (count1<count2) {//白底黑字
va=Mr-count1/count2*Math.Abs(g1-Mr);
}
else //黑底白字
va=Mr+count2/count1*Math.Abs(g2-Mr);
//对图像二值化
BitmapData bmData = b.LockBits(new Rectangle(0, 0,b.Width , b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
byte * p = (byte *)(void *)Scan0;
int nOffset = stride - b.Width*3;
int nWidth=b.Width;
int nHeight=b.Height;
for(int y=0;y < nHeight;++y)
{
for(int x=0; x < nWidth; ++x )
{
if (p[0]>va)
{
p[0]=p[1]=p[2]=255;
}
else
p[0]=p[1]=p[2]=0;
p+=3;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
return true;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -