漫谈WinCE的手写识别技术(二)

本文介绍了一种封装WinCE手写识别技术的方法,通过创建CRecognizer类简化了手写识别流程,使得开发者能够更轻松地集成手写识别功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//========================================================================
//TITLE:
// 漫谈WinCE的手写识别技术(二)
//AUTHOR:
// norains
//DATE:
// Thursday 25-January -2007
//Environment:
// EVC4.0 + Standard SDK
//========================================================================

在第一章的时候,已经介绍了识别的一般性过程,对于实际运用来说,是完全可行的;但从便利性角度出发,却不免显得烦琐:每次输入笔画都需留意点阵是否屏幕坐标系,每次读取返回的字符总要分配内存然后获取等等,诸如总总,代码写一次还好,如果多处运用多次编写多方维护,实在不是一件快乐的事情.

而我,最讨厌做复杂又要花费脑筋的东东;所以,为了让自己感觉得写代码是一件快乐的事情,自己又很高兴地将识别过程封装为一个类.至于是否达到简便的效果,不敢祈求大家苟同,只愿自己舒坦即可.


/**///////////////////////////////////////////////////////////////////////
//Recognizer.h:interfacefortheCRecognizerclass.//
/**///////////////////////////////////////////////////////////////////////

#ifndefRECOGNIZER_H
#defineRECOGNIZER_H

//===========================================================================
//Includefile
#include"recog.h"

//=====================================================================================
//Choosethebuildtypefortherecognizingfunction
//--------------------------------------------------------------------------
#defineRECOGNIZE_FUNCTION_FROM_DLL
//#defineRECOGNIZE_FUNCTION_FROM_LIB

#ifndefRECOGNIZE_FUNCTION_FROM_LIB
#ifndefRECOGNIZE_FUNCTION_FROM_DLL
#defineRECOGNIZE_FUNCTION_FROM_DLL
#endif
#endif

#ifdefRECOGNIZE_FUNCTION_FROM_DLL
#defineRECOGNIZE_DLL_PATHTEXT("/WINDOWS/hwxcht.dll")
#endif
//=====================================================================================



//-----------------------------------------------------------------------------------
//Thedatatype

//Thescaletypeforthecoordinate
enumScaleType
...{
SCALE_APPWND,
SCALE_SCREEN
}
;
//------------------------------------------------------------------------------
classCRecognizer
...{
public:
BOOLInputStroke(POINT
*lpPnt,intiCount,ScaleTypescale);
CRecognizer();
virtual~CRecognizer();
intGetCharacter(WCHAR*pWchar,intiCount);
BOOLEndRecognize();
BOOLBeginRecognize();
BOOLInitialize(HWNDhWnd,
constRECT*prcWnd,ScaleTypescale);
protected:
HRCm_hrc;
HWXGUIDEm_hwxGuide;
HWNDm_hWndRecog;
ALCm_alc;

#ifdefRECOGNIZE_FUNCTION_FROM_DLL
typedefBOOL(WINAPI
*DLL_HWXCONFIG)(void);
typedefHRC(WINAPI
*DLL_HWXCREATE)(HRC=NULL);
typedefBOOL(WINAPI
*DLL_HWXSETGUIDE)(HRC,HWXGUIDE*);
typedefBOOL(WINAPI
*DLL_HWXALCVALID)(HRC,ALC);
typedefBOOL(WINAPI
*DLL_HWXALCPRIORITY)(HRC,ALC);
typedefBOOL(WINAPI
*DLL_HWXSETCONTEXT)(HRC,WCHAR);
typedefBOOL(WINAPI
*DLL_HWXINPUT)(HRC,POINT*,UINT,DWORD);
typedefBOOL(WINAPI
*DLL_HWXENDINPUT)(HRC);
typedefBOOL(WINAPI
*DLL_HWXPROCESS)(HRC);
typedefINT(WINAPI
*DLL_HWXRESULTSAVAILABLE)(HRC);
typedefINT32(WINAPI
*DLL_HWXGETRESULTS)(HRC,UINT,UINT,UINT,HWXRESULTS*);
typedefBOOL(WINAPI
*DLL_HWXDESTROY)(HRC);
DLL_HWXCONFIGHWXCONFIG;
DLL_HWXCREATEHWXCREATE;
DLL_HWXSETGUIDEHWXSETGUIDE;
DLL_HWXALCVALIDHWXALCVALID;
DLL_HWXALCPRIORITYHWXALCPRIORITY;
DLL_HWXSETCONTEXTHWXSETCONTEXT;
DLL_HWXINPUTHWXINPUT;
DLL_HWXPROCESSHWXPROCESS;
DLL_HWXRESULTSAVAILABLEHWXRESULTSAVAILABLE;
DLL_HWXGETRESULTSHWXGETRESULTS;
DLL_HWXDESTROYHWXDESTROY;
DLL_HWXENDINPUTHWXENDINPUT;
#endif//RECOGNIZE_FUNCTION_FROM_DLL


#ifdefRECOGNIZE_FUNCTION_FROM_LIB
#defineHWXCONFIG(void)HwxConfig(void)
#defineHWXCREATE(hrc)HwxCreate(hrc)
#defineHWXSETGUIDE(hrc,lpGuide)HwxSetGuide(hrc,lpGuide)
#defineHWXALCVALID(hrc,alc)HwxALCValid(hrc,alc)
#defineHWXALCPRIORITY(hrc,alc)HwxALCPriority(hrc,alc)
#defineHWXSETCONTEXT(hrc,wContext)HwxSetContext(hrc,wContext)
#defineHWXINPUT(hrc,lppnt,upoints,timestamp)HwxInput(hrc,lppnt,upoints,timestamp)
#defineHWXPROCESS(hrc)HwxProcess(hrc)
#defineHWXRESULTSAVAILABLE(hrc)HwxResultsAvailable(hrc)
#defineHWXGETRESULTS(hrc,cAlt,iFirst,cBoxRes,rgBoxResults)HwxGetResults(hrc,cAlt,iFirst,cBoxRes,rgBoxResults)
#defineHWXDESTROY(hrc)HwxDestroy(hrc)
#defineHWXENDINPUT(hrc)HwxEndInput(hrc)
#endif//RECOGNIZE_FUNCTION_FROM_LIB
}
;



//============================================================================================
#endif//!definedRECOGNIZER_H




/**///////////////////////////////////////////////////////////////////////
//Recognizer.cpp:implementationoftheCRecognizerclass.//
/**///////////////////////////////////////////////////////////////////////

#include
"stdafx.h"
#include
"Recognizer.h"

//-------------------------------------------------------------------
//Macrodefine

//ThedefaultvalueofhwxGuide
#defineDEFAULT_HWXGUIDE_CHORZBOX1
#defineDEFAULT_HWXGUIDE_CVERTBOX1
#defineDEFAULT_HWXGUIDE_CXOFFSET1
#defineDEFAULT_HWXGUIDE_CYOFFSET1

//ThedefaultvalueofALC
#defineDEFAULT_ALCALC_KANJI_ALL




//--------------------------------------------------------------------
/**///////////////////////////////////////////////////////////////////////
//Construction/Destruction
/**///////////////////////////////////////////////////////////////////////

CRecognizer::CRecognizer()
...{
m_alc
=NULL;
m_hrc
=NULL;
m_hWndRecog
=NULL;
memset(
&m_hwxGuide,0,sizeof(m_hwxGuide));
}


CRecognizer::
~CRecognizer()
...{

}


//-----------------------------------------------------------------------
//Descriptiong:
//Initializetherecognizer
//
//Parameter:
//hWnd:[in]Thehandleofwindowtoberecognized
//rcWnd:[in]Thewindowareatoberecognized
//scale:[in]ThescalebaseofprcWndpoint
//-----------------------------------------------------------------------
BOOLCRecognizer::Initialize(HWNDhWnd,constRECT*prcWnd,ScaleTypescale)
...{
m_hWndRecog
=hWnd;

m_alc
=DEFAULT_ALC;

RECTrcWnd
=...{0};
switch(scale)
...{
caseSCALE_APPWND:
...{
rcWnd
=*prcWnd;
rcWnd.left
*=4;
rcWnd.right
*=4;
rcWnd.top
*=4;
rcWnd.bottom
*=4;
MapWindowPoints(hWnd,HWND_DESKTOP,(LPPOINT)(
&rcWnd),(sizeof(RECT)/sizeof(POINT)));
break;
}

caseSCALE_SCREEN:
...{
rcWnd
=*prcWnd;
break;
}

}


m_hwxGuide.cHorzBox
=DEFAULT_HWXGUIDE_CHORZBOX;
m_hwxGuide.cVertBox
=DEFAULT_HWXGUIDE_CVERTBOX;
m_hwxGuide.xOrigin
=rcWnd.left;
m_hwxGuide.yOrigin
=rcWnd.top;
m_hwxGuide.cxBox
=rcWnd.right-rcWnd.left;
m_hwxGuide.cyBox
=rcWnd.bottom-rcWnd.top;
m_hwxGuide.cxOffset
=DEFAULT_HWXGUIDE_CXOFFSET;
m_hwxGuide.cyOffset
=DEFAULT_HWXGUIDE_CYOFFSET;
m_hwxGuide.cxWriting
=(rcWnd.right-rcWnd.left)-m_hwxGuide.cxOffset*2;
m_hwxGuide.cyWriting
=(rcWnd.bottom-rcWnd.top)-m_hwxGuide.cyOffset*2;
m_hwxGuide.nDir
=HWX_HORIZONTAL;

#ifdefRECOGNIZE_FUNCTION_FROM_DLL
HINSTANCEhInstDll;
hInstDll
=LoadLibrary(RECOGNIZE_DLL_PATH);
if(hInstDll!=NULL)
...{
HWXCONFIG
=(DLL_HWXCONFIG)GetProcAddress(hInstDll,TEXT("HwxConfig"));
HWXCREATE
=(DLL_HWXCREATE)GetProcAddress(hInstDll,TEXT("HwxCreate"));
HWXSETGUIDE
=(DLL_HWXSETGUIDE)GetProcAddress(hInstDll,TEXT("HwxSetGuide"));
HWXALCVALID
=(DLL_HWXALCVALID)GetProcAddress(hInstDll,TEXT("HwxALCValid"));
HWXALCPRIORITY
=(DLL_HWXALCPRIORITY)GetProcAddress(hInstDll,TEXT("HwxALCPriority"));
HWXSETCONTEXT
=(DLL_HWXSETCONTEXT)GetProcAddress(hInstDll,TEXT("HwxSetContext"));
HWXINPUT
=(DLL_HWXINPUT)GetProcAddress(hInstDll,TEXT("HwxInput"));
HWXPROCESS
=(DLL_HWXPROCESS)GetProcAddress(hInstDll,TEXT("HwxProcess"));
HWXRESULTSAVAILABLE
=(DLL_HWXRESULTSAVAILABLE)GetProcAddress(hInstDll,TEXT("HwxResultsAvailable"));
HWXGETRESULTS
=(DLL_HWXGETRESULTS)GetProcAddress(hInstDll,TEXT("HwxGetResults"));
HWXDESTROY
=(DLL_HWXDESTROY)GetProcAddress(hInstDll,TEXT("HwxDestroy"));
HWXENDINPUT
=(DLL_HWXENDINPUT)GetProcAddress(hInstDll,TEXT("HwxEndInput"));
}

else
...{
returnFALSE;
}

#endif//RECOGNIZE_FUNCTION_FROM_DLL

if(HWXCONFIG()==FALSE)
...{
returnFALSE;
}


returnTRUE;
}



//-----------------------------------------------------------------------
//Descriptiong:
//Beginrecognizing
//-----------------------------------------------------------------------
BOOLCRecognizer::BeginRecognize()
...{
BOOLbRes
=FALSE;

m_hrc
=HWXCREATE();
if(m_hrc==NULL)
...{
gotoEND;
}


bRes
=HWXSETGUIDE(m_hrc,&m_hwxGuide);
if(bRes==FALSE)
...{
gotoEND;
}


bRes
=HWXALCVALID(m_hrc,m_alc);
if(bRes==FALSE)
...{
gotoEND;
}


bRes
=TRUE;

END:
returnbRes;
}



//-----------------------------------------------------------------------
//Descriptiong:
//Endrecognizing
//-----------------------------------------------------------------------
BOOLCRecognizer::EndRecognize()
...{
BOOLbRes
=FALSE;

//Destroytherecognizer
if(HWXDESTROY(m_hrc)==FALSE)
...{
gotoEND;
}


bRes
=TRUE;

END:
returnbRes;
}



//-----------------------------------------------------------------------
//Descriptiong:
//Getthecharacter
//
//Parameters:
//pWchar:[out]Thecharactergettobestored
//iCount:[in]ThenumberofpWchar
//
//ReturnValues:
//0:Failed
//>0:Thenumberofthecharacterstoreturn
//-----------------------------------------------------------------------
intCRecognizer::GetCharacter(WCHAR*pWchar,intiCount)
...{
intiGetNum=0;
inti=0;
HWXRESULTS
*phwxResults;
//BecauseeachHWXRESULTSafterthefirstonecouldstoretwocharacters,
//soonlyallocate(iCount/2+1)
intiNum=iCount/2+1;
phwxResults
=newHWXRESULTS[iNum];
memset(phwxResults,
0,iNum*sizeof(HWXRESULTS));

//Endtheinput
if(HWXENDINPUT(m_hrc)==FALSE)
...{
gotoEND;
}


//Analyzetheinformation
if(HWXPROCESS(m_hrc)==FALSE)
...{
gotoEND;
}




//Getthecharacterfromrecognizer
if(HWXGETRESULTS(m_hrc,iCount,0,1,phwxResults)==FALSE)
...{
gotoEND;
}


//Setthecharactertothestoredbuffer
for(i=0;i<iNum;i++)
...{
if(i==0)
...{
if(phwxResults[i].rgChar[0]!=0)
...{
pWchar[iGetNum
++]=phwxResults[i].rgChar[0];
}

else
...{
break;
}

}

else
...{
//TheindxBoxmemberalsostorethecharacter
if(phwxResults[i].indxBox!=0)
...{
pWchar[iGetNum
++]=phwxResults[i].indxBox;
}

else
...{
break;
}


if(phwxResults[i].rgChar[0]!=0)
...{
pWchar[iGetNum
++]=phwxResults[i].rgChar[0];
}

else
...{
break;
}


}

}


END:
if(phwxResults!=NULL)
...{
delete[]phwxResults;
}

returniGetNum;
}



//-----------------------------------------------------------------------
//Descriptiong:
//Inputthestroke
//
//Parameter:
//lpPnt:[in]PointertothestrokePOINT
//iCount:[in]ThecountofthelpPnt
//scale:[in]ThescalebaseoflpPnt
//-----------------------------------------------------------------------
BOOLCRecognizer::InputStroke(POINT*lpPnt,intiCount,ScaleTypescale)
...{
BOOLbRes
=FALSE;
inti=0;

POINT
*pt;
pt
=newPOINT[iCount];
if(pt==NULL)
...{
gotoEND;
}


for(i=0;i<iCount;i++)
...{
pt[i]
=lpPnt[i];

if(scale==SCALE_APPWND)
...{
//Converttothescreenscale
pt[i].x*=4;
pt[i].y
*=4;
MapWindowPoints(m_hWndRecog,HWND_DESKTOP,
&pt[i],1);
}

}


//Inputstroke
bRes=HWXINPUT(m_hrc,pt,iCount,0);

if(bRes==FALSE)
...{
gotoEND;
}


bRes
=TRUE;

END:
if(pt!=NULL)
...{
delete[]pt;
}

returnbRes;
}

不知道大家看到这段代码有什么感觉,反正我是挺高兴的,因为让我从繁琐的识别过程中脱离出来.

关于代码,也许最让人疑惑的可能是这两个宏:RECOGNIZE_FUNCTION_FROM_DLL,RECOGNIZE_FUNCTION_FROM_LIB.

顾名思义,RECOGNIZE_FUNCTION_FROM_DLL表明识别函数调用是来源于动态链接库(DLL),同理,RECOGNIZE_FUNCTION_FROM_LIB则是编译的时候链接到lib库.为什么需要定义这两个宏呢?因为在标准的SDK下,如果直接包含"recog.h"后调用相关识别函数,是会报link错误.因为标准的SDK是不包含任何手写识别组件的.从调试的便利性来说,这时候如果只拷贝识别库到模拟器就可以顺利测试程序,绝对比重新定制一个包含手写识别引擎的系统要来得方便.

在示例代码中,因为是识别繁体中文,所以包含的动态链接库为:hwxcht.dll.如果需要识别其它文字,则只要更改该动态链接库名称即可.当然,还要更改DEFAULT_ALC宏,这个宏定义了识别的范围.

因为示例代码中的识别函数全部是宏定义,具体意义根据函数的来源而不同,所以RECOGNIZE_FUNCTION_FROM_DLL和RECOGNIZE_FUNCTION_FROM_LIB同一时间只能定义一个.如果两个都定义,毫无疑问,出错!^_^

最后,用伪代码做范例说明如何使用该封装类,以此做本章结尾:

CRecognizerrecog;

RectrcWnd;
/**//*rcWnd获取应用窗口hWnd的大小*/

//初始化
//直接赋值窗口坐标,函数体内部会根据标志直接转换为屏幕坐标
recog.Initialize(hWnd,&rcWnd,SCALE_APPWND);

//开始识别
recog.BeginRecognize();

POINTpt[
200];
intiCount=0;
/**//*获取笔画坐标给pt,坐标的数量储存在iCount中*/

//将笔画点阵传送给识别引擎
//如果有多个笔画,则每个笔画都需要调用该函数进行传入
recog.InputStroke(pt,iCount,SCALE_APPWND);

//获取十个最接近的字符,iReturn是实际返回的字符数
WCHARwChar[10];
intiReturn=recog.GetCharacter(wChar,10);

//结束识别
recog.EndRecognize();

/**//*如果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值