www.gusucode.com > VC++数字、英文字符、汉字及手写识别实例源码程序 > VC++数字、英文字符、汉字及手写识别实例源码程序\code\联机手写数字识别\patternView.cpp

    //Download by http://www.NewXing.com
//patternView.cpp

#include "stdafx.h"
#include "pattern.h"

#include "patternDoc.h"
#include "patternView.h"
#include "InputDialog.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include<windows.h>
#include<math.h>

#define startX 8  //模拟面板的X起点
#define startY 8  //模拟面板的Y起点
#define stepX 11  //X方向每格的长度
#define stepY 15  //Y方向每格的长度
int disable=0;


/////////////////////////////////////////////////////////////////////////////
// CPatternView

IMPLEMENT_DYNCREATE(CPatternView, CView)

BEGIN_MESSAGE_MAP(CPatternView, CView)
	//{{AFX_MSG_MAP(CPatternView)
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPatternView construction/destruction

CPatternView::CPatternView()
{
	// TODO: add construction code here
	mouseDown=0;

	//初始化,使得每个点皆为白点
	for(int i=0;i<16;i++)
		for(int j=0;j<16;j++)
			bitgraph[i][j]=0;

	//初始化,使得坐标序列中的点皆为空点
	mytime=0;
	for(i=0;i<100;i++){
		mypoint[i].x=-1;
		mypoint[i].y=-1;
	}

	mytime=0;
	curvalue=-1;
	mytezheng=(TEZHENG *)malloc(sizeof(TEZHENG));
	mytezheng->value=-1;
	mytezheng->lenth=0;
	mytezheng->lenth1=0;
	for(i=0;i<15;i++)
		mytezheng->VHDerection[i]=-1;
	mytezheng->decon=0;

	//打开保存模板特征量的文件
	if(cf.Open("mydata.dat",CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite)==NULL){
		AfxMessageBox("打开文件失败,\n您最好退出程序");
	}
}

CPatternView::~CPatternView()
{
	cf.Close();
}

BOOL CPatternView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CPatternView drawing

void CPatternView::OnDraw(CDC* pDC)
{
	CPatternDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	//画整个系统的背景
	//Erase the background
	// Create a pruple brush.
	CBrush Brush (RGB (128, 0 , 0) );
	// Select the brush into the device context .
	CBrush* pOldBrush = pDC->SelectObject (&Brush);
	// Get the area that needs to be erased .
	CRect rcClip;
	pDC->GetClipBox (&rcClip);
	//Paint the area.
	pDC-> PatBlt (rcClip.left , rcClip.top , rcClip.Width ( ) , rcClip.Height( ) , PATCOPY );
	//Unselect brush out of device context .
	
	pDC->SelectObject (pOldBrush );

	//四个模拟位图按钮
	CBitmap bitmapstudy,bitmaprecognize,bitmapclear,bitmaphelp; // Sequence is important
    CDC dcMemory1,dcMemory2,dcMemory3,dcMemory4;

    bitmapstudy.LoadBitmap(IDB_BITMAP_STUDY);
    dcMemory1.CreateCompatibleDC(pDC);
    dcMemory1.SelectObject(&bitmapstudy);
    pDC->BitBlt(220, 20, 50, 20, &dcMemory1, 0, 0, SRCCOPY);

	bitmaprecognize.LoadBitmap(IDB_BITMAP_RECOGNIZE);
    dcMemory2.CreateCompatibleDC(pDC);
    dcMemory2.SelectObject(&bitmaprecognize);
    pDC->BitBlt(220, 60, 50, 20, &dcMemory2, 0, 0, SRCCOPY);

	bitmapclear.LoadBitmap(IDB_BITMAP_CLEAR);
    dcMemory3.CreateCompatibleDC(pDC);
    dcMemory3.SelectObject(&bitmapclear);
    pDC->BitBlt(220, 100, 50, 20, &dcMemory3, 0, 0, SRCCOPY);

	bitmaphelp.LoadBitmap(IDB_BITMAP_HELP);
    dcMemory4.CreateCompatibleDC(pDC);
    dcMemory4.SelectObject(&bitmaphelp);
    pDC->BitBlt(220,140, 50, 20, &dcMemory4, 0, 0, SRCCOPY);

	//画板
	CBrush BrushBoard (RGB (255, 255 , 255) );
	// Select the brush into the device context .
	pOldBrush = pDC->SelectObject (&BrushBoard);
	//Paint the area.
	pDC-> PatBlt (8,8,176,240, PATCOPY );
	//Unselect brush out of device context 
    pDC->SelectObject (pOldBrush );
	pDC->SetTextColor(RGB(255,255,255));
	pDC->SetTextAlign(TA_CENTER|TA_TOP);
	pDC->SetBkMode(TRANSPARENT);
	pDC->TextOut(245,175,"请您尽量");
	pDC->TextOut(245,200,"写慢一点");
	pDC->TextOut(245,225,"  呵呵!");
}

/////////////////////////////////////////////////////////////////////////////
// CPatternView printing

BOOL CPatternView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CPatternView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CPatternView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CPatternView diagnostics

#ifdef _DEBUG
void CPatternView::AssertValid() const
{
	CView::AssertValid();
}

void CPatternView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CPatternDoc* CPatternView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPatternDoc)));
	return (CPatternDoc*)m_pDocument;
}
#endif //_DEBUG

//接受新的数字类型,以加入模板文件中
void CPatternView::OnStudy(void)
{
	//输入数字值的对话框
	InputDialog inputdlg;
	cf.SeekToBegin();
	int nFileSize=cf.GetLength();
	int i=nFileSize/sizeof(TEZHENG);
	TEZHENG *temp;
	temp=(TEZHENG *)malloc(sizeof(TEZHENG));

	//计算当前画板中数字的特征值
	GetTeZheng();

	//首先判断当前的数字类型是否已经在模板中
	for(int j=0;j<i;j++){
		cf.Read((void *)temp,sizeof(TEZHENG));
		for(int k=0;k<15;k++){
			if(temp->VHDerection[k]!=mytezheng->VHDerection[k])
				break;
		}
		if((k==15)&&(temp->decon==mytezheng->decon)&&(temp->lenfirst==mytezheng->lenfirst)&&(temp->lenth1==mytezheng->lenth1)&&(temp->lenth==mytezheng->lenth)&&(temp->lenend==mytezheng->lenend)){
			char s[20];
			sprintf(s,"您输入的是:%d,数据已有",temp->value);
			AfxMessageBox(s);
			break;
		}
	}
	//说明该数字类型不在模板中
	if(j==i){
		if(inputdlg.DoModal()==IDOK){
			//判断数字输入对话框中的两个数字是否相同
			if(inputdlg.m_value1!=inputdlg.m_value2){
				AfxMessageBox("您的输入有误,\n请重新输入");
			}
			//相同,则将新的数字类型写入模板文件中
			else{
				GetTeZheng();
				try{
					mytezheng->value=inputdlg.m_value1;
					cf.SeekToEnd();
					cf.Write(&mytezheng->value,sizeof(signed char));
					cf.Write(mytezheng->VHDerection,sizeof(signed char)*15);
					cf.Write(&mytezheng->lenth1,sizeof(signed char));
					cf.Write(&mytezheng->lenth,sizeof(signed char));
					cf.Write(&mytezheng->decon,sizeof(signed char));
					cf.Write(&mytezheng->lenfirst,sizeof(signed char));
					cf.Write(&mytezheng->lenend,sizeof(signed char));
				}
				catch(CFileException *e){
					//Alert user to error
					e->Delete();
				}//end try-catch
			}//end if-else
		}//end if
	}//end if

	OnClear();

	return;
}

//识别功能
void CPatternView::OnRecognize(void)
{
	cf.SeekToBegin();
	int nFileSize=cf.GetLength();
	int i=nFileSize/sizeof(TEZHENG);
	TEZHENG *temp;
	temp=(TEZHENG *)malloc(sizeof(TEZHENG));
	//计算特征值
	GetTeZheng();

	//在模板文件中寻找,是否有与当前特征值相同的
	for(int j=0;j<i;j++){
		cf.Read((void *)temp,sizeof(TEZHENG));
		for(int k=0;k<15;k++){
			if(temp->VHDerection[k]!=mytezheng->VHDerection[k])
				break;
		}
		//找到识别结果
		if((k==15)&&(temp->decon==mytezheng->decon)&&(temp->lenfirst==mytezheng->lenfirst)&&(temp->lenth1==mytezheng->lenth1)&&(temp->lenth==mytezheng->lenth)&&(temp->lenend==mytezheng->lenend)){
			char s[20];
			sprintf(s,"您输入的是:%d",temp->value);
			AfxMessageBox(s);
			break;//搜索结束
		}
	}
	if(j==i){
		AfxMessageBox("抱歉,无法识别");
	}

	OnClear();

	return;
}

//清空画板
void CPatternView::OnClear(void)
{
	CDC *pDC=GetDC();

	CBrush BrushBoard (RGB (255, 255 , 255) );
	CBrush pOldBrush;
	pDC-> PatBlt (8,8,176,240, PATCOPY );

	for(int i=0;i<16;i++)
		for(int j=0;j<16;j++)
			bitgraph[i][j]=0;

	mouseDown=0;
	mytime=0;
	for(i=0;i<100;i++){
		mypoint[i].x=-1;
		mypoint[i].y=-1;
	}
	
	curvalue=-1;
	mytezheng->value=-1;
	mytezheng->lenth=0;
	mytezheng->lenth1=0;
	for(i=0;i<15;i++)
		mytezheng->VHDerection[i]=-1;
	mytezheng->decon=0;

	return;
}

void CPatternView::OnMyHelp(void)
{
	return;
}

///////////////////////////////////////////////////////////////////////////
//从输入的序列钟提取特征
void CPatternView::GetTeZheng()
{
	int p,q;
	int i=0;
	//从第一个点到最后一个点
	for(int j=0;j<mytime-1;j++){
		if(i==0){
			mytezheng->lenth1++;
		}
		if(i>=13){
			AfxMessageBox("内存溢出,呵呵",NULL,NULL);
			return;
		}
		
		//判断两个相邻点的距离
		p=(mypoint[j+1].x-mypoint[j].x)*(mypoint[j+1].x-mypoint[j].x);
		q=(mypoint[j+1].y-mypoint[j].y)*(mypoint[j+1].y-mypoint[j].y);
		//如果不是8连接,则为断裂点或者是写的太快
		if((p>1)||(q>1)){
			mytezheng->decon=1;
			j++;
			i++;
			if(j+1>mytime-1){
				AfxMessageBox("您可能写得太快了,呵呵",NULL,NULL);
				return;
			}
			if(mypoint[j+1].x>mypoint[j].x)
				mytezheng->VHDerection[i]=1;
			else if(mypoint[j+1].y>mypoint[j].y)
				mytezheng->VHDerection[i]=2;
			else if(mypoint[j+1].x<mypoint[j].x)
				mytezheng->VHDerection[i]=3;
			else
				mytezheng->VHDerection[i]=4;
				
			mytezheng->lenth=1;	
		}

		//尽量保持目前的方向
		else{
			if(j==0){
				if(mypoint[1].x>mypoint[0].x)
					mytezheng->VHDerection[0]=1;
				else if(mypoint[1].y>mypoint[0].y)
					mytezheng->VHDerection[0]=2;
				else if(mypoint[1].x<mypoint[0].x)
					mytezheng->VHDerection[0]=3;
				else
					mytezheng->VHDerection[0]=4;
				
				mytezheng->lenth=1;
			}//end if
			else{
				switch(mytezheng->VHDerection[i]){
				case 1:
					if(mypoint[j+1].x<=mypoint[j].x){
						i++;
						mytezheng->lenth=1;
						if(mypoint[j+1].y>mypoint[j].y)
							mytezheng->VHDerection[i]=2;
						else if(mypoint[j+1].y<mypoint[j].y)
							mytezheng->VHDerection[i]=4;
						else
							mytezheng->VHDerection[i]=3;
					}
					else
						mytezheng->lenth++;
					break;
				case 2:
					if(mypoint[j+1].y<=mypoint[j].y){
						i++;
						mytezheng->lenth=1;
						if(mypoint[j+1].x<mypoint[j].x)
							mytezheng->VHDerection[i]=3;
						else if(mypoint[j+1].x>mypoint[j].x)
							mytezheng->VHDerection[i]=1;
						else
							mytezheng->VHDerection[i]=4;
					}
					else
						mytezheng->lenth++;
					break;
				case 3:
					if(mypoint[j+1].x>=mypoint[j].x){
						i++;
						mytezheng->lenth=1;
						if(mypoint[j+1].y<mypoint[j].y)
							mytezheng->VHDerection[i]=4;
						else if(mypoint[j+1].y>mypoint[j].y)
							mytezheng->VHDerection[i]=2;
						else
							mytezheng->VHDerection[i]=1;
					}
					else
						mytezheng->lenth++;
					break;
				case 4:
					if(mypoint[j+1].y>=mypoint[j].y){
						i++;
						mytezheng->lenth=1;
						if(mypoint[j+1].x>mypoint[j].x)
							mytezheng->VHDerection[i]=1;
						else if(mypoint[j+1].x<mypoint[j].x)
							mytezheng->VHDerection[i]=3;
						else
							mytezheng->VHDerection[i]=2;
					}
					else
						mytezheng->lenth++;
					break;
				default:
					break;
				}//end switch
			}//end else
		}//end else
	}//end for
	for(p=0;p<4;p++){
		for(q=p+1;q<mytime;q++){
			if(mypoint[p]==mypoint[q])
				break;
		}
		if(q<mytime)
			break;
	}
	if(p>=4)
		mytezheng->lenfirst=2;
	else
		mytezheng->lenfirst=1;

	for(p=mytime-1;p>mytime-6;p--){
		for(q=p-1;q>=0;q--){
			if(mypoint[p]==mypoint[q])
				break;
		}
		if(q>=0)
			break;
	}
	if(p<=mytime-6)
		mytezheng->lenend=2;
	else
		mytezheng->lenend=1;

	if((mytezheng->lenth)>0&&(mytezheng->lenth)<=4)
		mytezheng->lenth=1;
	else
		mytezheng->lenth=2;

	if(mytezheng->lenth1>=4)
		mytezheng->lenth1=2;
	else
		mytezheng->lenth1=1;
}//end fuction GetTeZheng()


/////////////////////////////////////////////////////////////////////////////
// CPatternView message handlers
//模拟按钮事件
//通过判断鼠标左键按下事件发生在哪个区域来判断该触发哪个事情
void CPatternView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	mouseDown=1;
	
	if((point.x>=220)&&(point.x<270)&&(point.y>=20)&&(point.y<40)){
		OnStudy();
	}

	if((point.x>=220)&&(point.x<270)&&(point.y>=60)&&(point.y<80)){
		OnRecognize();
	}

	if((point.x>=220)&&(point.x<270)&&(point.y>=100)&&(point.y<120)){
		OnClear();
	}

	if((point.x>=220)&&(point.x<270)&&(point.y>=140)&&(point.y<160)){
		OnMyHelp();
	}

	CView::OnLButtonDown(nFlags, point);
}

//鼠标移动事件,模拟手写笔输入
void CPatternView::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	CDC *pDC=GetDC();
	CRgn Rgn;

	//限制在输入区域的范围内
	Rgn.CreateRectRgn(startX,startY,startX+stepX*16-1,startY+stepY*16-1);
	pDC->SelectClipRgn(&Rgn);
	if((point.x>=startX)&&(point.x<startX+stepX*16)&&(point.y>=startY)&&(point.y<startY+stepY*16)){
		HCURSOR m_HCross;
		m_HCross=AfxGetApp()->LoadStandardCursor(IDC_CROSS);
		::SetCursor(m_HCross);
	}
	int i=(point.x-startX)/stepX;
	int j=(point.y-startY)/stepY;
	if((mouseDown==1)&&(point.x>=startX)&&(point.x<startX+stepX*16)&&(point.y>=startY)&&(point.y<startY+stepY*16)){
		CBrush Brush (RGB (0, 0 , 0) );
		// Select the brush into the device context .
		CBrush* pOldBrush = pDC->SelectObject (&Brush);
		pDC->Ellipse(point.x-6,point.y-6,point.x+6,point.y+6);
		pDC->SelectObject (pOldBrush );
		//保存数据
	
		if(mytime>=100){
			AfxMessageBox("内存溢出(画图时)",NULL,NULL);
			OnClear();
		}

		if(mytime==0){
			mypoint[mytime].x=i;
			mypoint[mytime].y=j;
			oldpoint=mypoint[mytime];
			mytime++;
		}
		//在输入过程中动态的去除直角点
		else{
			if((i!=oldpoint.x)||(j!=oldpoint.y)){
				int k,n;
				if(mytime<2){
					k=0;
					n=0;
				}
				else{
					k=(i-mypoint[mytime-2].x)*(i-mypoint[mytime-2].x);
					n=(j-mypoint[mytime-2].y)*(j-mypoint[mytime-2].y);
				}
				if((k==1)&&(n==1)){
					mypoint[mytime-1].x=i;
					mypoint[mytime-1].y=j;
					oldpoint=mypoint[mytime-1];
				}
				//disable=1;
				else{
					mypoint[mytime].x=i;
					mypoint[mytime].y=j;
					oldpoint=mypoint[mytime];
					mytime++;
				}
			}
		}
		bitgraph[i][j]=1;
	}

	CView::OnMouseMove(nFlags, point);
}

//鼠标左键抬起
void CPatternView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	//设置mouseDown为false
	mouseDown=0;
	CView::OnLButtonUp(nFlags, point);
}