当前位置:首页 > 嵌入式 > 嵌入式软件
[导读] //========================================================================//TITLE:// 漫谈WinCE的手写识别技术(二)//AUTHOR:// norains//DATE:// Thursday 25-Januar

 //========================================================================

//TITLE:

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

//AUTHOR:

// norains

//DATE:

// Thursday 25-January -2007

//Environment:

// EVC4.0 + Standard SDK

//========================================================================

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

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

//////////////////////////////////////////////////////////////////////

// Recognizer.h: interface for the CRecognizer class. //

/////////////////////////////////////////////////////////////////////

#ifndef RECOGNIZER_H

#define RECOGNIZER_H

//===========================================================================

//Include file

#include "recog.h"

//=====================================================================================

//Choose the build type for the recognizing function

//--------------------------------------------------------------------------

#define RECOGNIZE_FUNCTION_FROM_DLL

//#define RECOGNIZE_FUNCTION_FROM_LIB

#ifndef RECOGNIZE_FUNCTION_FROM_LIB

#ifndef RECOGNIZE_FUNCTION_FROM_DLL

#define RECOGNIZE_FUNCTION_FROM_DLL

#endif

#endif

#ifdef RECOGNIZE_FUNCTION_FROM_DLL

#define RECOGNIZE_DLL_PATH TEXT("/WINDOWS/hwxcht.dll")

#endif

//=====================================================================================

//-----------------------------------------------------------------------------------[!--empirenews.page--]

//The data type

//The scale type for the coordinate

enum ScaleType

{

SCALE_APPWND,

SCALE_SCREEN

};

//------------------------------------------------------------------------------

class CRecognizer

{

public:

BOOL InputStroke(POINT *lpPnt, int iCount, ScaleType scale);

CRecognizer();

virtual ~CRecognizer();

int GetCharacter(WCHAR *pWchar, int iCount);

BOOL EndRecognize();

BOOL BeginRecognize();

BOOL Initialize(HWND hWnd,const RECT *prcWnd,ScaleType scale);

protected:

HRC m_hrc;

HWXGUIDE m_hwxGuide;

HWND m_hWndRecog;

ALC m_alc;

#ifdef RECOGNIZE_FUNCTION_FROM_DLL

typedef BOOL (WINAPI *DLL_HWXCONFIG)(void);

typedef HRC (WINAPI *DLL_HWXCREATE)(HRC = NULL);

typedef BOOL (WINAPI *DLL_HWXSETGUIDE)(HRC ,HWXGUIDE*);

typedef BOOL (WINAPI *DLL_HWXALCVALID)(HRC,ALC);

typedef BOOL (WINAPI *DLL_HWXALCPRIORITY)(HRC,ALC);

typedef BOOL (WINAPI *DLL_HWXSETCONTEXT)(HRC,WCHAR);

typedef BOOL (WINAPI *DLL_HWXINPUT)(HRC,POINT*,UINT, DWORD);

typedef BOOL (WINAPI *DLL_HWXENDINPUT)(HRC);

typedef BOOL (WINAPI *DLL_HWXPROCESS)(HRC);

typedef INT (WINAPI *DLL_HWXRESULTSAVAILABLE)(HRC);

typedef INT32 (WINAPI *DLL_HWXGETRESULTS)(HRC, UINT, UINT, UINT, HWXRESULTS*);

typedef BOOL (WINAPI *DLL_HWXDESTROY)(HRC);

DLL_HWXCONFIG HWXCONFIG;

DLL_HWXCREATE HWXCREATE;

DLL_HWXSETGUIDE HWXSETGUIDE;

DLL_HWXALCVALID HWXALCVALID;

DLL_HWXALCPRIORITY HWXALCPRIORITY;

DLL_HWXSETCONTEXT HWXSETCONTEXT;

DLL_HWXINPUT HWXINPUT;

DLL_HWXPROCESS HWXPROCESS;

DLL_HWXRESULTSAVAILABLE HWXRESULTSAVAILABLE;

DLL_HWXGETRESULTS HWXGETRESULTS;

DLL_HWXDESTROY HWXDESTROY;

DLL_HWXENDINPUT HWXENDINPUT;

#endif //RECOGNIZE_FUNCTION_FROM_DLL

#ifdef RECOGNIZE_FUNCTION_FROM_LIB

#define HWXCONFIG(void) HwxConfig(void)

#define HWXCREATE(hrc) HwxCreate(hrc)

#define HWXSETGUIDE(hrc,lpGuide) HwxSetGuide(hrc,lpGuide)

#define HWXALCVALID(hrc,alc) HwxALCValid(hrc,alc)

#define HWXALCPRIORITY(hrc,alc) HwxALCPriority(hrc,alc)

#define HWXSETCONTEXT(hrc,wContext) HwxSetContext(hrc,wContext)

#define HWXINPUT(hrc,lppnt,upoints,timestamp) HwxInput(hrc,lppnt,upoints,timestamp)

#define HWXPROCESS(hrc) HwxProcess(hrc)

#define HWXRESULTSAVAILABLE(hrc) HwxResultsAvailable(hrc)

#define HWXGETRESULTS(hrc,cAlt,iFirst,cBoxRes,rgBoxResults) HwxGetResults(hrc,cAlt,iFirst,cBoxRes,rgBoxResults)

#define HWXDESTROY(hrc) HwxDestroy(hrc)

#define HWXENDINPUT(hrc) HwxEndInput(hrc)

#endif //RECOGNIZE_FUNCTION_FROM_LIB

};

//============================================================================================

#endif // !defined RECOGNIZER_H

//////////////////////////////////////////////////////////////////////

// Recognizer.cpp: implementation of the CRecognizer class. //

//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "Recognizer.h"

//----------------------------------------------------------------

//Macro define

//The default value of hwxGuide

#define DEFAULT_HWXGUIDE_CHORZBOX 1[!--empirenews.page--]

#define DEFAULT_HWXGUIDE_CVERTBOX 1

#define DEFAULT_HWXGUIDE_CXOFFSET 1

#define DEFAULT_HWXGUIDE_CYOFFSET 1

//The default value of ALC

#define DEFAULT_ALC ALC_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:

// Initialize the recognizer

//

//Parameter:

// hWnd: [in] The handle of window to be recognized

// rcWnd: [in] The window area to be recognized

// scale: [in] The scale base of prcWnd point

//-----------------------------------------------------------------------

BOOL CRecognizer::Initialize(HWND hWnd,const RECT *prcWnd,ScaleType scale)

{

m_hWndRecog = hWnd;

m_alc = DEFAULT_ALC;

RECT rcWnd = {0};

switch(scale)

{

case SCALE_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;

}

case SCALE_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;

#ifdef RECOGNIZE_FUNCTION_FROM_DLL

HINSTANCE hInstDll;

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"));[!--empirenews.page--]

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

{

return FALSE;

}

#endif //RECOGNIZE_FUNCTION_FROM_DLL

if(HWXCONFIG() == FALSE)

{

return FALSE;

}

return TRUE;

}

//-----------------------------------------------------------------------

//Descriptiong:

// Begin recognizing

//-----------------------------------------------------------------------

BOOL CRecognizer::BeginRecognize()

{

BOOL bRes = FALSE;

m_hrc = HWXCREATE();

if(m_hrc == NULL)

{

goto END;

}

bRes = HWXSETGUIDE(m_hrc,&m_hwxGuide);

if(bRes == FALSE)

{

goto END;

}

bRes = HWXALCVALID(m_hrc,m_alc);

if(bRes == FALSE)

{

goto END;

}

bRes = TRUE;

END:

return bRes;

}

//-----------------------------------------------------------------------

//Descriptiong:

// End recognizing

BOOL CRecognizer::EndRecognize()

{

BOOL bRes = FALSE;

//Destroy the recognizer

if(HWXDESTROY(m_hrc) == FALSE)

{

goto END;

}

bRes = TRUE;

END:

return bRes;

}

//Descriptiong:

// Get the character

//Parameters:

// pWchar: [out] The character get to be stored

// iCount: [in] The number of pWchar

//Return Values:

// 0: Failed

// >0: The number of the characters to return

int CRecognizer::GetCharacter(WCHAR *pWchar, int iCount)

{

int iGetNum = 0;

int i = 0;

HWXRESULTS *phwxResults;

//Because each HWXRESULTS after the first one could store two characters,

//so only allocate (iCount / 2 + 1)

int iNum = iCount / 2 + 1;

phwxResults = new HWXRESULTS[iNum];

memset(phwxResults,0,iNum * sizeof(HWXRESULTS));

//End the input

if(HWXENDINPUT(m_hrc) == FALSE)

{

goto END;

}

//Analyze the information

if(HWXPROCESS(m_hrc) == FALSE)[!--empirenews.page--]

{

goto END;

}

//Get the character from recognizer

if(HWXGETRESULTS(m_hrc,iCount,0,1,phwxResults) == FALSE)

{

goto END;

}

//Set the character to the stored buffer

for(i = 0; i < iNum; i++)

{

if(i == 0)

{

if(phwxResults[i].rgChar[0] != 0)

{

pWchar[iGetNum ++] = phwxResults[i].rgChar[0];

}

else

{

break;

}

}

else

{

//The indxBox member also store the character

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;

}

return iGetNum;

}

//Descriptiong:

// Input the stroke

//Parameter:

// lpPnt: [in] Pointer to the stroke POINT

// iCount: [in] The count of the lpPnt

// scale: [in] The scale base of lpPnt

BOOL CRecognizer::InputStroke(POINT *lpPnt, int iCount, ScaleType scale)

{

BOOL bRes = FALSE;

int i = 0;

POINT *pt;

pt = new POINT[iCount];

if(pt == NULL)

{

goto END;

}

for(i = 0; i < iCount; i++)

{

pt[i] = lpPnt[i];

if(scale == SCALE_APPWND)

{

//Convert to the screen scale

pt[i].x *= 4;

pt[i].y *= 4;

MapWindowPoints(m_hWndRecog, HWND_DESKTOP, &pt[i], 1);

}

}

//Input stroke

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

if(bRes == FALSE)

{

goto END;

}

bRes = TRUE;

END:

if(pt != NULL)

{

delete [] pt;

}

return bRes;

}

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

关于代码,也许最让人疑惑的可能是这两个宏: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同一时间只能定义一个.如果两个都定义,毫无疑问,出错!^_^

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

CRecognizer recog;

Rect rcWnd;

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

//初始化

//直接赋值窗口坐标,函数体内部会根据标志直接转换为屏幕坐标

recog.Initialize(hWnd,&rcWnd,SCALE_APPWND);[!--empirenews.page--]

//开始识别

recog.BeginRecognize();

POINT pt[200];

int iCount = 0;

/*获取笔画坐标给pt,坐标的数量储存在iCount中*/

//将笔画点阵传送给识别引擎

//如果有多个笔画,则每个笔画都需要调用该函数进行传入

recog.InputStroke(pt,iCount,SCALE_APPWND);;

//获取十个最接近的字符,iReturn是实际返回的字符数

WCHAR wChar[10];

int iReturn = recog.GetCharacter(wChar,10);

//结束识别

recog.EndRecognize();

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

-2025年智慧城市博览会将以史上最大规模召开,呼吁城市成为变革推动者 西班牙巴塞罗那 2025年7月4日 /美通社/ -- 由巴塞罗那会展中心(Fira de Barc...

关键字: 智慧城市 CE RC AI

上海 2025年5月26日 /美通社/ -- 5月26日,国际独立第三方检测、检验和认证机构德国莱茵TÜV大中华区(简称"TÜV莱茵"...

关键字: 数字化 RC 供应链管理 中国制造

旧金山2025年2月6日 /美通社/ -- 基于深度学习的领先智能广告平台MediaGo宣布获得TrustArc的2025年《通用数据保护条例》(GDPR)合规认证。这一权威的第三方认证体现了MediaGo对数据安全保护...

关键字: MEDIA GO RC TRUST

第二子代MRCD和MDB最高支持12800MT/s速率,较第一子代产品提升45% 上海2025年1月24日 /美通社/ -- 澜起科技今日宣布,其最新研发的第二子代多路复用寄存时钟驱动器(MRCD)和第二子代多路复用数...

关键字: DDR RC CD MT

上海2024年11月5日 /美通社/ -- 保点 (Checkpoint Systems,以下简称Checkpoint) 是高度垂直集成的RFID解决方案领导者,也是业内能够提供最全面的RFID标签的供货商之一。随着Im...

关键字: RFID标签 RC 系列芯片 POINT

上海2024年10月8日 /美通社/ -- 2024年9月24日至25日,全球领先的汽车涂料供应商PPG受邀参加了在上海举行的SURCAR亚洲大会。会议期间,PPG与国内外各大汽车制造商、行业专家进行了深入的交流,共同探...

关键字: 汽车 RC PRIME 奇瑞

北京2024年9月3日 /美通社/ -- 近日,中共中央、国务院发布了《关于加快经济社会发展全面绿色转型的意见》,这是中央层面首次对加快经济社会发展全面绿色转型进行系统部署。其中,《意见》对交通运输领域的绿色转型提出了明...

关键字: POWER 新能源汽车 MDASH RC

中国深圳2024年8月27日 /美通社/ -- 深圳市联代科技有限公司(NASDAQ: WTO)(以下简称"联代科技"或"该公司")欣然宣布与战略合作伙伴Ehud Baron博士合作开发一款核心连续血压测量技术系统Cir...

关键字: 血压 测量技术 RC TI

深圳2024年8月21日 /美通社/ -- 今年4月在上海圆满落幕的"CHINAPLAS 2024 国际橡塑展",以无限的创新魔力书写了璀璨的篇章。如同一艘满载商机的巨轮,展会将乘风破浪,再度驶向充满活力的粤港澳大湾区。...

关键字: CHINA CE RC COM

北京2024年8月15日 /美通社/ -- 日前,杭州来布科技有限公司(以下简称"来布科技")数保保软件V1.0与浪潮信息服务器操作系统云峦KeyarchOS V5完成浪潮信息澎湃技术认证。经联合测试...

关键字: 软件 RC OS 测试
关闭