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

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



//-----------------------------------------------------------------------------------
//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
#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"));
        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)
    
{
        
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); 
        
        
//开始识别
        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();
        
        
/*如果
posted @ 2007-01-25 20:56  我的一天  阅读(189)  评论(0编辑  收藏  举报