當(dāng)前位置:首頁(yè) > 嵌入式 > 嵌入式軟件
[導(dǎo)讀] //========================================================================//TITLE:// 漫談WinCE的手寫識(shí)別技術(shù)(二)//AUTHOR:// norains//DATE:// Thursday 25-Januar

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

//TITLE:

// 漫談WinCE的手寫識(shí)別技術(shù)(二)

//AUTHOR:

// norains

//DATE:

// Thursday 25-January -2007

//Environment:

// EVC4.0 + Standard SDK

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

在第一章的時(shí)候,已經(jīng)介紹了識(shí)別的一般性過(guò)程,對(duì)于實(shí)際運(yùn)用來(lái)說(shuō),是完全可行的;但從便利性角度出發(fā),卻不免顯得煩瑣:每次輸入筆畫都需留意點(diǎn)陣是否屏幕坐標(biāo)系,每次讀取返回的字符總要分配內(nèi)存然后獲取等等,諸如總總,代碼寫一次還好,如果多處運(yùn)用多次編寫多方維護(hù),實(shí)在不是一件快樂的事情.

而我,最討厭做復(fù)雜又要花費(fèi)腦筋的東東;所以,為了讓自己感覺得寫代碼是一件快樂的事情,自己又很高興地將識(shí)別過(guò)程封裝為一個(gè)類.至于是否達(dá)到簡(jiǎn)便的效果,不敢祈求大家茍同,只愿自己舒坦即可.

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

// 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;

}

不知道大家看到這段代碼有什么感覺,反正我是挺高興的,因?yàn)樽屛覐姆爆嵉淖R(shí)別過(guò)程中脫離出來(lái).

關(guān)于代碼,也許最讓人疑惑的可能是這兩個(gè)宏:RECOGNIZE_FUNCTION_FROM_DLL,RECOGNIZE_FUNCTION_FROM_LIB.

顧名思義,RECOGNIZE_FUNCTION_FROM_DLL表明識(shí)別函數(shù)調(diào)用是來(lái)源于動(dòng)態(tài)鏈接庫(kù)(DLL),同理,RECOGNIZE_FUNCTION_FROM_LIB則是編譯的時(shí)候鏈接到lib庫(kù).為什么需要定義這兩個(gè)宏呢?因?yàn)樵跇?biāo)準(zhǔn)的SDK下,如果直接包含"recog.h"后調(diào)用相關(guān)識(shí)別函數(shù),是會(huì)報(bào)link錯(cuò)誤.因?yàn)闃?biāo)準(zhǔn)的SDK是不包含任何手寫識(shí)別組件的.從調(diào)試的便利性來(lái)說(shuō),這時(shí)候如果只拷貝識(shí)別庫(kù)到模擬器就可以順利測(cè)試程序,絕對(duì)比重新定制一個(gè)包含手寫識(shí)別引擎的系統(tǒng)要來(lái)得方便.

在示例代碼中,因?yàn)槭亲R(shí)別繁體中文,所以包含的動(dòng)態(tài)鏈接庫(kù)為:hwxcht.dll.如果需要識(shí)別其它文字,則只要更改該動(dòng)態(tài)鏈接庫(kù)名稱即可.當(dāng)然,還要更改DEFAULT_ALC宏,這個(gè)宏定義了識(shí)別的范圍.

因?yàn)槭纠a中的識(shí)別函數(shù)全部是宏定義,具體意義根據(jù)函數(shù)的來(lái)源而不同,所以RECOGNIZE_FUNCTION_FROM_DLL和RECOGNIZE_FUNCTION_FROM_LIB同一時(shí)間只能定義一個(gè).如果兩個(gè)都定義,毫無(wú)疑問(wèn),出錯(cuò)!^_^

最后,用偽代碼做范例說(shuō)明如何使用該封裝類,以此做本章結(jié)尾:

CRecognizer recog;

Rect rcWnd;

/*rcWnd 獲取應(yīng)用窗口hWnd的大小*/

//初始化

//直接賦值窗口坐標(biāo),函數(shù)體內(nèi)部會(huì)根據(jù)標(biāo)志直接轉(zhuǎn)換為屏幕坐標(biāo)

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

//開始識(shí)別

recog.BeginRecognize();

POINT pt[200];

int iCount = 0;

/*獲取筆畫坐標(biāo)給pt,坐標(biāo)的數(shù)量?jī)?chǔ)存在iCount中*/

//將筆畫點(diǎn)陣傳送給識(shí)別引擎

//如果有多個(gè)筆畫,則每個(gè)筆畫都需要調(diào)用該函數(shù)進(jìn)行傳入

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

//獲取十個(gè)最接近的字符,iReturn是實(shí)際返回的字符數(shù)

WCHAR wChar[10];

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

//結(jié)束識(shí)別

recog.EndRecognize();

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉