十年前为一个软件公司实现一个自动向第三方站点提交数据获得数据处理结果的接口。
第三方站点只提供了账户未有数据接口,每次提交都需要验证码,该验证码比较规则。于是试着通过模板识别算法实现对该网站验证码的识别,主要原理是首先对验证码图片进行字符分割,然后针对各个字符图片做去噪二值化处理,最后对每个字符图像做5*5分割,算出25个格每个格的黑点特征值,收集验证码进行采样保存特征值,识别同理:对需要识别的验证码做分割字符,二值化,5*5取特征,同模板的各区特征做匹配算法,获得最小偏差的模板数据作为识别的字符结果,核心类库使用和实现代码如下:
主要调用
LoadPicture(CWnd *pWnd,CString FileName,CRect Rt,bool bLi);//加载验证码图片
ChangToHeiBai();//二值话
CaiJiMode(CStringArray &TArray);//采集模板
HeDuiZiFu(CStringArray &ZiArray)//识别字符
使用例子
CShowWnd m_TT;
1.选择验证码图片
CFileDialog MyDlg(true);
if(MyDlg.DoModal()==IDOK)
{
m_TT.m_ShiBie.LoadPicture(&m_TT,MyDlg.GetPathName());
m_TT.Invalidate(true);
}
2.二值化
m_TT.m_ShiBie.ChangToHeiBai();
m_TT.Invalidate(true);
3.采集模板
UpdateData();
CStringArray TArray;
int i;
CString TStr;
for(i=0;i<m_Zi.GetLength();i )
{
TStr.Format("%c",m_Zi.GetAt(i));
TArray.Add(TStr);
}
m_TT.m_ShiBie.CaiJiMode(TArray);
4.识别也是加加载图片二值话然后识别
CStringArray TArray;
TArray.Add("1");
TArray.Add("1");
TArray.Add("1");
TArray.Add("1");
m_TT.m_ShiBie.HeDuiZiFu(TArray);
输出TArray
ShowWnd.h文件
#include ".\ShiBieClass.h"
class CShowWnd : public CStatic
{
// Construction
public:
CShowWnd();
CShiBieClass m_ShiBie;
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CShowWnd)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CShowWnd();
// Generated message map functions
protected:
//{{AFX_MSG(CShowWnd)
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
ShowWnd.cpp文件
CShowWnd::CShowWnd()
{
}
CShowWnd::~CShowWnd()
{
}
BEGIN_MESSAGE_MAP(CShowWnd, CStatic)
//{{AFX_MSG_MAP(CShowWnd)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CShowWnd message handlers
void CShowWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
m_ShiBie.ShowPicture(this);
// Do not call CStatic::OnPaint() for painting messages
}
ShiBieClass.h文件
#include ".\基础类\MemDC.h"
#include ".\基础类\ChunDC.h"
#include ".\图像显示类\Picture.h"
#include <afxtempl.h>
struct TeZhiMa
{
char Str[2];//数字
float TeZheng[5][5];//特征码
int Sum[5][5];
};
struct ModeST
{
int nCount;
BYTE Head[40];
};
//
typedef CArray<struct TeZhiMa,struct TeZhiMa>ModeData;
class CShiBieClass
{
public:
void LoadMode(CString FName);
LPTSTR GetAppPath();
void HeDuiZiFu(CStringArray &ZiArray,CString &sOutStr);
void SaveMode(CString FName);
ModeData m_Mode;
void CaiJiMode(CString FName,CStringArray &TArray);
void HeiBaiFanZhuan();
void FreeNeiChun();
void GetNeiChun();
HGLOBAL hPAL;
COLORREF *pData;
void ChangToHeiBai(int nKuan=1,bool bQuBian=true);
void ShowPicture(CWnd *pWnd,CRect Rt=CRect::CRect(0,0,0,0));
int W,H;//图像的实际宽高
CShiBieClass();
virtual ~CShiBieClass();
CChunDC *pChunDC;
CPicture MyPC;
bool LoadPicture(CWnd *pWnd,CString FileName,CRect Rt=CRect::CRect(0,0,0,0),bool bLi=true);
};
ShiBieClass.cpp文件
CShiBieClass::CShiBieClass()
{
pChunDC=NULL;
hPAL=NULL;
pData=NULL;
}
CShiBieClass::~CShiBieClass()
{
FreeNeiChun();
}
bool CShiBieClass::LoadPicture(CWnd *pWnd,CString FileName,CRect Rt,bool bLi)
{
bool bRet=MyPC.Load(FileName);
if(bRet)
{
CSize nSize=MyPC.GetImageSize();
W=nSize.cx;
H=nSize.cy;
CDC *pDC=pWnd->GetDC();
if(pChunDC!=NULL)
{
delete pChunDC;
pChunDC=NULL;
}
if(Rt==CRect(0,0,0,0))
{
CRect Rt=CRect(0,0,W,H);
pChunDC=new CChunDC(pDC,&Rt);
MyPC.Render(pChunDC,Rt);
}
else
{
pChunDC=new CChunDC(pDC,&CRect(0,0,W,H));
if(bLi)
{
MyPC.Render(pChunDC,Rt);
}
}
GetNeiChun();
pWnd->ReleaseDC(pDC);
}
return bRet;
}
void CShiBieClass::ShowPicture(CWnd *pWnd,CRect Rt)
{
CDC *pDC=pWnd->GetDC();
if(pChunDC!=NULL)
{
CRect Rt0=Rt;
if(Rt==CRect(0,0,0,0))
{
pWnd->GetClientRect(&Rt0);
int XX=Rt0.Width();
int YY=Rt0.Height();
Rt0.left=0;
Rt0.top=0;
Rt0.right=XX;
Rt0.bottom=YY;
}
CMemDCEx MyDC(pDC,Rt0);
MyDC.StretchBlt(0,0,Rt0.Width(),Rt0.Height(),pChunDC,0,0,W,H,SRCCOPY);
}
pWnd->ReleaseDC(pDC);
}
//转成黑白图
void CShiBieClass::ChangToHeiBai(int nKuan,bool bQuBian)
{
if(pChunDC!=NULL)
{
COLORREF Color;
BYTE R,G,B;
int XX,YY;
int KuanGe=W/4;
for(YY=0;YY<H;YY )
for(XX=0;XX<W;XX )
{
if(bQuBian)
{
if((XX 1)%KuanGe==0)
{
pChunDC->SetPixel(XX,YY,RGB(255,255,255));
pData[YY*W XX]=RGB(255,255,255);
continue;
}
}
if(YY<nKuan || H-YY<nKuan 1)
{
Color=RGB(255,255,255);
pChunDC->SetPixel(XX,YY,Color);
pData[YY*W XX]=Color;
}
else
{
if(XX<nKuan || W-XX<nKuan 1)
{
Color=RGB(255,255,255);
pChunDC->SetPixel(XX,YY,Color);
pData[YY*W XX]=Color;
}
else
{
Color=pChunDC->GetPixel(XX,YY);
R=GetRValue(Color);
G=GetGValue(Color);
B=GetBValue(Color);
Color=R*0.11 0.59*G 0.3*B;
if(Color<=127.5)
{
pChunDC->SetPixel(XX,YY,RGB(0,0,0));
pData[YY*W XX]=RGB(0,0,0);
}
else
{
pChunDC->SetPixel(XX,YY,RGB(255
,255,255));
pData[YY*W XX]=RGB(255,255,255);
}
}
}
}
}
HeiBaiFanZhuan();
}
void CShiBieClass::GetNeiChun()
{
FreeNeiChun();
hPAL=GlobalAlloc(GHND,W*H*sizeof(DWORD));
pData=(COLORREF *)GlobalLock(hPAL);
int i,j;
for(i=0;i<H;i )
for(j=0;j<W;j )
{
pData[i*W j]=pChunDC->GetPixel(j,i);
}
}
void CShiBieClass::FreeNeiChun()
{
if(hPAL!=NULL)
{
GlobalUnlock(hPAL);
GlobalFree(hPAL);
hPAL=NULL;
pData=NULL;
}
}
//对黑白点的噪声消除
void CShiBieClass::HeiBaiFanZhuan()
{
int i,j;
DWORD averg;
DWORD *p_data=pData;
int wide,height;
wide=W;
height=H;
DWORD *p_temp=new DWORD[wide*height];
memcpy(p_temp,p_data,W*H*sizeof(DWORD));
for(j=1;j<height-1;j )
for(i=1;i<wide-1;i )
{
averg=0;
if(p_temp[j*wide i]==RGB(255,255,255))
{
continue;
}
averg=p_temp[wide*(j-1) i] p_temp[wide*(j 1) i]
p_temp[wide*j i-1] p_temp[wide*j i 1];
if(averg==RGB(255,255,255)*4)
{
p_temp[j*wide i]=RGB(255,255,255);
pChunDC->SetPixel(i,j,p_temp[j*wide i]);
}
}
memcpy(p_data,p_temp,wide*height*sizeof(DWORD));
delete[] p_temp;
}
//采集模板
void CShiBieClass::CaiJiMode(CString FName,CStringArray &TArray)
{
int nZiCount;
int ZiW,ZiH;//字宽高
int k,i,j;
int nWeiX,nWeiY;
nZiCount=TArray.GetSize();
ZiW=W/nZiCount;
ZiH=H-1;
int iX=ZiW/5;
int iY=ZiH/5;
CString TStr;
float Sum=0;
CDC *pDC=CWnd::GetDesktopWindow()->GetWindowDC();
for(k=0;k<TArray.GetSize();k )
{
TStr=TArray.GetAt(k);
struct TeZhiMa TMa;
memset(&TMa,0,sizeof(struct TeZhiMa));
sprintf(TMa.Str,"%s",(char *)(const char *)TStr);
for(i=0;i<ZiH;i )
{
for(j=k*ZiW;j<(k 1)*ZiW;j )
{
nWeiX=(j-k*ZiW)/iX;
nWeiY=i/iY;
if(pData[j i*W]==RGB(0,0,0))
{
// TRACE("%d,%d\n",nWeiX,nWeiY);
TMa.Sum[nWeiX][nWeiY] =1;
}
pDC->SetPixel(j,i,pData[j i*W]);
}
}
for(i=0;i<5;i )
{
for(j=0;j<5;j )
{
TMa.TeZheng[i][j]=TMa.Sum[i][j]/(float)(iX*iY);
TRACE("%.3f,",TMa.TeZheng[i][j]);
}
TRACE("\n");
}
TRACE("----------------\n");
m_Mode.Add(TMa);
}
// CWnd::GetDesktopWindow()->ReleaseDC(pDC);
SaveMode(FName);
}
void CShiBieClass::SaveMode(CString FName)
{
CString Path;
CFile MyFile;
Path.Format("%s\Mode",GetAppPath());
::CreateDirectory(Path,NULL);
Path ="\\" FName;//"\\ModeFu.dat";
::DeleteFile((char *)(const char *)Path);
int k;
if(MyFile.Open((char *)(const char *)Path,CFile::modeReadWrite|CFile::modeCreate))
{
struct ModeST ST;
memset(&ST,0,sizeof(ST));
ST.nCount=m_Mode.GetSize();
MyFile.Write(&ST,sizeof(ST));
struct TeZhiMa Ma;
for(k=0;k<ST.nCount;k )
{
Ma=m_Mode.GetAt(k);
MyFile.Write(&Ma,sizeof(struct TeZhiMa));
}
MyFile.Close();
}
}
//核对字符号
void CShiBieClass::HeDuiZiFu(CStringArray &ZiArray,CString &sOutStr)
{
int nZiCount;
int ZiW,ZiH;//字宽高
int k,i,j;
int nWeiX,nWeiY;
nZiCount=ZiArray.GetSize();
ZiW=W/nZiCount;
ZiH=H-1;
int iX=ZiW/5;
int iY=ZiH/5;
CString TStr;
struct TeZhiMa TMa[4];
CDC *pDC=CWnd::GetDesktopWindow()->GetWindowDC();
for(k=0;k<ZiArray.GetSize();k )
{
TStr=ZiArray.GetAt(k);
memset(&TMa[k],0,sizeof(struct TeZhiMa));
sprintf(TMa[k].Str,"%s",(char *)(const char *)TStr);
for(i=0;i<ZiH;i )
{
for(j=k*ZiW;j<(k 1)*ZiW;j )
{
nWeiX=(j-k*ZiW)/iX;
nWeiY=i/iY;
if(pData[j i*W]==RGB(0,0,0))
{
// TRACE("%d,%d\n",nWeiX,nWeiY);
TMa[k].Sum[nWeiX][nWeiY] =1;
}
pDC->SetPixel(j,i,pData[j i*W]);
}
}
for(i=0;i<5;i )
{
for(j=0;j<5;j )
{
TMa[k].TeZheng[i][j]=TMa[k].Sum[i][j]/(float)(iX*iY);
//TRACE("%.3f,",TMa[k].TeZheng[i][j]);
}
TRACE("\n");
}
TRACE("----------------\n");
//m_Mode.Add(TMa);
}
int m;
CString AllStr="";
for(m=0;m<4;m )
{
float fMin=99999;
for(k=0;k<m_Mode.GetSize();k )
{
struct TeZhiMa TMa0;
TMa0=m_Mode.GetAt(k);
float fSum=0;
for(i=0;i<5;i )
for(j=0;j<5;j )
{
fSum =(TMa0.TeZheng[i][j]-TMa[m].TeZheng[i][j])*(TMa0.TeZheng[i][j]-TMa[m].TeZheng[i][j]);
}
if(fSum<fMin)
{
fMin=fSum;
TStr.Format("%s",TMa0.Str);
}
}
AllStr =TStr;
}
sOutStr=AllStr;
//AfxMessageBox(AllStr);
}
LPTSTR CShiBieClass::GetAppPath()
{
static LPTSTR AppPath=NULL;
LPTSTR str;
int i,loc=0,len;
if (AppPath==NULL)
{
AppPath=new char[MAX_PATH];
str=GetCommandLine() 1;
len=strlen(str);
for (i=0;i<len;i )
if(str[i]=='\\') loc=i 1;
strncpy(AppPath,str,loc);
*(AppPath loc)=0;
}
return AppPath;
}
void CShiBieClass::LoadMode(CString FName)
{
m_Mode.RemoveAll();
CString Path;
CFile MyFile;
Path.Format("%s\Mode",GetAppPath());
Path ="\\" FName;//"\\ModeFu.dat";
int k;
if(MyFile.Open((char *)(const char *)Path,CFile::modeReadWrite))
{
struct ModeST ST;
memset(&ST,0,sizeof(ST));
ST.nCount=m_Mode.GetSize();
MyFile.Read(&ST,sizeof(ST));
struct TeZhiMa Ma;
for(k=0;k<ST.nCount;k )
{
//Ma=m_Mode.GetAt(k);
MyFile.Read(&Ma,sizeof(struct TeZhiMa));
m_Mode.Add(Ma);
}
MyFile.Close();
}
}