📄 轧板标号检测演示dlg.cpp
字号:
{
double a=-2.0/3.1415926/dr/dr/dr/dr;
a=a*(1-(x*x+y*y)/2.0/dr/dr);
double b=-(x*x+y*y)/2.0/dr/dr;
b=exp(b);
a=a*b;
a=12.0*a;
Marr[x+BASE][y+BASE]=-1*a;//为什么不把它设置为double呢?周家玮修改于8月8日,2006年
}
}
for(y=BASE;y<nHeight-BASE;y++)
{
for(x=BASE;x<nWidth-BASE;x++)
{
temp=0.0;
for(j=-BASE;j<=BASE;j++)
for(i=-BASE;i<=BASE;i++)
{
temp+=Point[(y+j)*nWidth+i+x]*Marr[j+BASE][i+BASE];
}
m_LpTempPoint[y*nWidth+x]=temp;
}
}
TotalEdgePoint=0;
TotalEdgePointGray=0;
TotalNoEdgePoint=0;
TotalNoEdgePointGray=0;
float t1,t2,t3;
int No;
for(y=0;y<nHeight;y++)//转化成24位色彩
{
for(x=0;x<nWidth;x++)
{
No=y*nByteWidth+x*3;
t1=m_LpTempPoint[x+y*nWidth];
if (t1>0)
{
t1=255;
TotalNoEdgePoint++;
TotalNoEdgePointGray+=Point[x+y*nWidth];
}
else
{
t1=0;//过零点和负数
TotalEdgePoint++;
TotalEdgePointGray+=Point[x+y*nWidth];
}
m_lpBit[No]=(BYTE)t1;
m_lpBit[No+1]=(BYTE)t1;
m_lpBit[No+2]=(BYTE)t1;
}
}
//利用自动阈值法加以调整:分别计算图象中前景区域平均灰度t1和背景区域平均灰度t2;
//如果背景区域中某点的灰度不大于t1,那么就将该点并入前景区域;
//如果前景区域中某点的灰度大于(t1+t2)/2,那么就将该点从前景区域剔除。
t1=(float)TotalEdgePointGray/(TotalEdgePoint);//取得所有边缘点的平均数值
t2=(float)TotalNoEdgePointGray/(TotalNoEdgePoint);// t3=(t1+t2)/2;//效果没有直接用t2好,容易引入干扰
t2=(t1+t2)/2;
t3=t1;
//
for(y=0;y<nHeight;y++)//转化成24位色彩
{
for(x=0;x<nWidth;x++)
{
if (Point[x+y*nWidth]<=t3 )
{
t1=0;
No=y*nByteWidth+x*3;
m_lpBit[No]=(BYTE)t1;
m_lpBit[No+1]=(BYTE)t1;
m_lpBit[No+2]=(BYTE)t1;
}
if (Point[x+y*nWidth]>t2 )
{
t1=255;
No=y*nByteWidth+x*3;
m_lpBit[No]=(BYTE)t1;
m_lpBit[No+1]=(BYTE)t1;
m_lpBit[No+2]=(BYTE)t1;
}
}
}
//去除小面积
long count;
DelLittleArea8(20,&count,0);
BYTE *tempByte= new BYTE[nByteWidth*nHeight];
memcpy(tempByte,m_lpBit,nByteWidth*nHeight);
No=nByteWidth*nHeight*2;
m_lpBit=new BYTE[No];
for(y=0;y<nHeight;y++)//转化成24位色彩
{
for(x=0;x<nByteWidth;x++)
{
No=y*nByteWidth+x;
m_lpBit[No]=tempByte[No];
}
}
for(y=nHeight;y<2*nHeight;y++)//转化成24位色彩
{
for(x=0;x<nByteWidth;x++)
{
No=y*nByteWidth+x;
m_lpBit[No]=m_lpBitOld[(y-nHeight)*nByteWidth+x];
}
}
delete tempByte;
nHeight=nHeight*2;
long T2 = ::GetTickCount();//以毫秒为单位
CString WinCap,strtemp;
WinCap.Format("图像分割:利用Marr算子边缘完成二值化; 滤除小面积\r\n 时间花费:%ims\r\n",T2-T1);
m_edit1.GetWindowText(strtemp);
WinCap=WinCap+strtemp;
m_edit1.SetWindowText(WinCap);
delete m_LpTempPoint;
menuSub->EnableMenuItem(IDD_ONESTEP,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
menuSub->EnableMenuItem(IDD_BINARY,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
menuSub->EnableMenuItem(IDD_PROJECTION, MF_ENABLED);
Invalidate(true);
}
void CMyDlg::OnProjection()
{
//做出垂直投影,并且显示
//利用投影法,对二值图像中的字符进行分割
//由于水平投影的作用重要不是确定上下边界,而是滤波
//所以现在仅仅做垂直投影
int x,y;
double* temp=new double[nWidth];
long PointAddress;
#define DISTANCE 4 //如果黑线得距离很短,就不是字符内容,该剔除
nHeight=nHeight/2;
BYTE *lpTempBit= new BYTE[nHeight*nByteWidth];
BYTE *lpTempByte= new BYTE[2*nHeight*nByteWidth];
long T1 = ::GetTickCount();
memcpy(lpTempByte,m_lpBit,2*nByteWidth*nHeight);
for(x=0;x<nWidth;x++)
{
temp[x]=0;
for(y=0;y<nHeight;y++)
{
PointAddress=y*nByteWidth+3*x;
if(m_lpBit[PointAddress]<150)
temp[x]++;
}
}
for(x=0;x<nWidth;x++)
{
for(y=0;y<nHeight;y++)
{
PointAddress=y*nByteWidth+3*x;
lpTempBit[PointAddress]=255;
if(y<temp[x])
lpTempBit[PointAddress]=0;
lpTempBit[PointAddress+1]=lpTempBit[PointAddress+2]=lpTempBit[PointAddress];
}
}
m_lpBit=new BYTE[3*nHeight*nByteWidth];
for(y=0;y<3*nHeight;y++)
{
for(x=0;x<nByteWidth;x++)
{
PointAddress=y*nByteWidth+x;
if(y>=nHeight)
{
m_lpBit[PointAddress]=lpTempByte[(y-nHeight)*nByteWidth+x];
}
else
{
m_lpBit[PointAddress]=lpTempBit[PointAddress];
}
}
}
nHeight=3*nHeight;
long T2 = ::GetTickCount();
delete lpTempBit;
delete temp;
delete lpTempByte;
CString WinCap,strtemp;
WinCap.Format("二值图计算垂直投影\r\n 时间花费:%ims\r\n",T2-T1);
m_edit1.GetWindowText(strtemp);
WinCap=WinCap+strtemp;
m_edit1.SetWindowText(WinCap);
menuSub->EnableMenuItem(IDD_PROJECTION, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
menuSub->EnableMenuItem(IDD_PROJECTIONDIVIDE, MF_ENABLED);
Invalidate(true);
}
void CMyDlg::OnProjectiondivide()
{
//在投影线上画分区线
//对于某一行进行扫描,确定0-1和1-0的变化位置 记录开始和结尾
int x,y;
lineBlackNum=0,lineWhiteNum=0;
nHeight=nHeight/3;
BYTE *lpTempBit= new BYTE[nHeight*nByteWidth];
BYTE *lpTempByte=new BYTE[nHeight*nByteWidth*3];
#define LINE 3 //对第三行扫描
long T1 = ::GetTickCount();
memcpy(lpTempBit,m_lpBit,nByteWidth*nHeight);
memcpy(lpTempByte,m_lpBit,3*nByteWidth*nHeight);
for(x=0;x<nWidth-1;x++)
{
if((lpTempBit[LINE*nByteWidth+3*x]==255)&&(lpTempBit[LINE*nByteWidth+3*x+3]==0))//白-黑
{
lineBlackNum++;
lineBlackS[lineBlackNum]=x+1;//黑的开始
lineWhiteE[lineWhiteNum]=x;//白的结束
}
if((lpTempBit[LINE*nByteWidth+3*x]==0)&&(lpTempBit[LINE*nByteWidth+3*x+3]==255))//黑-白
{
lineWhiteNum++;
lineWhiteS[lineWhiteNum]=x+1;//白的开始
if((x-lineBlackS[lineBlackNum])>2)
lineBlackE[lineBlackNum]=x;//黑的结束
else
{
lineBlackNum--;
}
}
}
m_lpBit=new BYTE[4*nHeight*nByteWidth];
for(y=0;y<4*nHeight;y++)
for(x=0;x<nByteWidth;x++)
{
long PointAddress=y*nByteWidth+x;
if(y>=nHeight)
{
m_lpBit[PointAddress]=lpTempByte[(y-nHeight)*nByteWidth+x];
}
else
m_lpBit[PointAddress]=lpTempBit[PointAddress];
}
for(x=1;x<=lineBlackNum;x++)//画出黑色区域 x=0 的数组没有使用
for(y=0;y<nHeight;y++)
{
m_lpBit[y*nByteWidth+3*lineBlackS[x]]=255;
m_lpBit[y*nByteWidth+3*lineBlackS[x]+1]=0;
m_lpBit[y*nByteWidth+3*lineBlackS[x]+2]=0;
m_lpBit[y*nByteWidth+3*lineBlackE[x]]=155;
m_lpBit[y*nByteWidth+3*lineBlackE[x]+1]=155;
m_lpBit[y*nByteWidth+3*lineBlackE[x]+2]=155;
}
long T2 = ::GetTickCount();
nHeight=4*nHeight;
delete lpTempBit;
delete lpTempByte;
CString WinCap,strtemp;
WinCap.Format("垂直投影图分区\r\n 时间花费:%ims\r\n",T2-T1);
m_edit1.GetWindowText(strtemp);
WinCap=WinCap+strtemp;
m_edit1.SetWindowText(WinCap);
menuSub->EnableMenuItem(IDD_PROJECTIONDIVIDE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
menuSub->EnableMenuItem(IDD_RECONGNISE, MF_ENABLED);
Invalidate(true);
}
void CMyDlg::OnRecongnise()
{
//识别字符,得到结果
int x,y,i;
long PointAddress;
nHeight=nHeight/4;
BYTE *lpTempBit= new BYTE[nHeight*nByteWidth];
BYTE *lpTempByte=new BYTE[nHeight*nByteWidth*4];
long T1 = ::GetTickCount();
memcpy(lpTempBit,m_lpBit,nByteWidth*nHeight);
memcpy(lpTempByte,m_lpBit,4*nByteWidth*nHeight);
m_lpBit=new BYTE[nHeight*nByteWidth];
//显示图中的第3排为此步骤的分析数据
for(y=2*nHeight;y<3*nHeight;y++)
for(x=0;x<nByteWidth;x++)
{
PointAddress=y*nByteWidth+x;
m_lpBit[(y-2*nHeight)*nByteWidth+x]=lpTempByte[PointAddress];
}
for(i=1;i<=lineBlackNum;i++)//画出黑色区域 x=0 的数组没有使用
{
CharTop[i]=0;CharBottom[i]=nHeight;
for(x=lineBlackS[i];x<lineBlackE[i];x++)
for(y=0;y<nHeight;y++)
{
if(m_lpBit[y*nByteWidth+3*x]==0)
{
if(y==0)y=0;
if(y>CharTop[i])CharTop[i]=y;//最大
if(y<CharBottom[i])
CharBottom[i]=y;//最小
}
}
}
CString result= MatchChar(lineBlackNum,CharTop,CharBottom,lineBlackS,lineBlackE);
//画出横竖4条线
for(i=1;i<=lineBlackNum;i++)//画出黑色区域 x=0 的数组没有使用
{
for(x=lineBlackS[i];x<lineBlackE[i];x++)
{//上横
m_lpBit[CharTop[i]*nByteWidth+3*x]=255;
m_lpBit[CharTop[i]*nByteWidth+3*x+1]=0;
m_lpBit[CharTop[i]*nByteWidth+3*x+2]=0;
//下横
m_lpBit[CharBottom[i]*nByteWidth+3*x]=0;
m_lpBit[CharBottom[i]*nByteWidth+3*x+1]=255;
m_lpBit[CharBottom[i]*nByteWidth+3*x+2]=0;
}
for(y=CharBottom[i];y<CharTop[i];y++)
{//左竖
m_lpBit[y*nByteWidth+3*lineBlackS[i]]=255;
m_lpBit[y*nByteWidth+3*lineBlackS[i]+1]=0;
m_lpBit[y*nByteWidth+3*lineBlackS[i]+2]=255;
//右竖
m_lpBit[y*nByteWidth+3*lineBlackE[i]]=0;
m_lpBit[y*nByteWidth+3*lineBlackE[i]+1]=155;
m_lpBit[y*nByteWidth+3*lineBlackE[i]+2]=255;
}
}
memcpy(lpTempBit,m_lpBit,nByteWidth*nHeight);
m_lpBit=new BYTE[5*nHeight*nByteWidth];
for(y=0;y<5*nHeight;y++)
for(x=0;x<nByteWidth;x++)
{
long PointAddress=y*nByteWidth+x;
if(y>=nHeight)
{
m_lpBit[PointAddress]=lpTempByte[(y-nHeight)*nByteWidth+x];
}
else
m_lpBit[PointAddress]=lpTempBit[PointAddress];
}
nHeight=5*nHeight;
long T2 = ::GetTickCount();
delete lpTempByte;
delete lpTempBit;
CString WinCap,strtemp;
WinCap.Format("识别字符\r\n 字符是 %s 时间花费:%ims\r\n",result,T2-T1);
m_edit1.GetWindowText(strtemp);
WinCap=WinCap+strtemp;
m_edit1.SetWindowText(WinCap);
WinCap.Format("识别结果:%s",result);
m_result.SetWindowText(WinCap);
menuSub->EnableMenuItem(IDD_RECONGNISE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
this->Invalidate(true);
}
void CMyDlg::OnOnestep()
{
if(m_lpBit==NULL)return;
long T1 = ::GetTickCount();
OnBinary();
OnProjection();
OnProjectiondivide();
OnRecongnise();
long T2 = ::GetTickCount();
CString WinCap,strtemp;
WinCap.Format("一步执行所有过程:%ims\r\n",T2-T1);
m_edit1.GetWindowText(strtemp);
WinCap=WinCap+strtemp;
m_edit1.SetWindowText(WinCap);
menuSub->EnableMenuItem(IDD_ONESTEP,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
menuSub->EnableMenuItem(IDD_BINARY,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
this->Invalidate(true);
}
void CMyDlg::OnReloadfile()
{
int ReturnNum=ReadBmpFile(FileName,0);
this->Invalidate(true);
CString Wincap;
Wincap.Format ("重新加载图像数据 文件名%s",FileName);
m_edit1.SetWindowText(Wincap);
menuSub->EnableMenuItem(IDD_BINARY, MF_ENABLED);
menuSub->EnableMenuItem(IDD_ONESTEP, MF_ENABLED);
menuSub->EnableMenuItem(IDD_PROJECTION, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
menuSub->EnableMenuItem(IDD_PROJECTIONDIVIDE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
menuSub->EnableMenuItem(IDD_RECONGNISE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
}
int CMyDlg::DelLittleArea8(int AreaOrPerimeter,long* count,int Type)
{
//八邻域物体;AreaOrPerimeter:最小保留的面积或周长,返回count物体最大可能的数量(第一次标号得到),
//Type操作的类型,0:代表面积过滤中的使用 1:代表周长过滤中的应用
//去掉面积或周长小于AreaOrPerimeter的黑色物体
int x,y,i;
long PointAddress;
bool OneNoFinish;
// int *areaNo;
int *lpTempNo= new int[nHeight*nWidth];//标号序列
*count=1;
OneNoFinish=false;
//行标号
for(y=0;y<nHeight;y++)
for(x=0;x<nWidth;x++)
{
lpTempNo[y*nWidth+x]=0;
}
for(y=1;y<nHeight-1;y++)
for(x=1;x<nWidth-1;x++)
{
PointAddress=y*nByteWidth+3*x;
if((OneNoFinish==false)&&(*(m_lpBit+PointAddress)==0)||(m_lpBit[PointAddress-3]==0&&m_lpBit[PointAddress]==0))
//开始发现是物体标号或物体的连续标号
{
OneNoFinish=true;
lpTempNo[y*nWidth+x]=*count;
}
else
if((OneNoFinish==true)&&*(m_lpBit+PointAddress)==255)//行末尾
{
*count=*count+1;
OneNoFinish=false;
}
}
//上下行判断,从上到下,下行跟上行的编号
int t1,t2,t3,t4,t5;
for(y=1;y<nHeight-1;y++)
for(x=1;x<nWidth-1;x++)
{//这里是唯一和是邻域有区别的地方
PointAddress=y*nWidth+x;
t1=lpTempNo[PointAddress];
t2=lpTempNo[PointAddress+nWidth-1];
t3=lpTempNo[PointAddress+nWidth];
t4=lpTempNo[PointAddress+nWidth+1];
if(t1!=0)//本像素有标号
if(((t2!=0)&&(t1!=t2))||((t3!=0)&&(t1!=t3))||((t4!=0)&&(t1!=t4)))//下行对应像素有不同的标号
{ if((t2!=0)&&(t1!=t2)) t5=t2;
if((t3!=0)&&(t1!=t3)) t5=t3;
if((t4!=0)&&(t1!=t4)) t5=t4;
for(i=0;i<nWidth;i++)
if (lpTempNo[y*nWidth+nWidth+i]==t5) lpTempNo[y*nWidth+nWidth+i]=t1;//改下行所有该标号点
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -