灵云SDK开发手册(C API)  5.2
 全部 结构体 函数 变量 类型定义 枚举 枚举值  
HWR能力

以下描述了如何使用灵云HWR能力。

1. HWR简介

HWR (HandWritten Recognition) 联机手写识别技术,可以将在手写设备上书写时产生的有序轨迹信息化转化为汉字内码。

2. 选择模块和能力

手写识别提供了三种模式:

  1. 单字识别,只能将一段输入的笔迹识别为一个单字。这种模式目前可支持87种语言的识别 (包括英文、阿拉伯数字、符号)。单字识别支持本地端识别和云端识别。 在某些确保一次输入一个单字的情况下,可以选用单字识别模式。

  2. 多字识别,支持叠写和行写模式,也即会自动将输入的笔迹进行切割,按照多字进行识别。 目前这种模式支持云端和本地,支持中文简繁体、英文、韩语、日语的识别(都包括英文、阿拉伯数字、符号等)。 一般都应该选用这种模式,包括云端和本地总共8种能力可以选择(HWR能力描述)。



  1. 笔势识别,输入的笔迹被识别为列表里50种笔势(笔势列表)中的一种,输出结果为对应的索引值,存于结果条目HWR_RECOG_RESULT_ITEM 中字段pszResult。

另外,手写识别还提供了一些开发手写识别应用时有用的辅助能力,例如获取联想词和拼音、模拟笔形等,目前只有本地端能力, 分别是 hwr.local.associateword 和 hwr.local.pinyin 能力,以及 hwr.local.penscript 能力。

无论使用何种能力,基础模块 hci_hwr都是需要的。 使用云端识别时,需要加上hci_hwr_cloud_recog模块; 需要使用本地端识别时,需要加上hci_hwr_local_recog模块; 需要使用联想词,需要加上hci_hwr_associate模块; 需要使用拼音,需要加上hci_hwr_pinyin模块; 需要使用笔形,需要加上hci_hwr_penscript模块。

3. 手写识别

一个手写识别的过程如下:

int nSessionId = -1;
char * pszSessionConfig = "capKey=hwr.local.freestylus";
errCode = hci_hwr_session_start(pszSessionConfig, &nSessionId);
short g_StrokeData[]=
{
103 ,283 ,105 ,283 ,107 ,283 ,113 ,283 ,120 ,283,
129 ,283 ,138 ,283 ,146 ,283 ,156 ,283 ,162 ,283,
...
-1 ,0 , -1, -1
};
char * strRecogConfig = "";
HWR_RECOG_RESULT hwrRecogResult;
errCode = hci_hwr_recog( nSessionId, g_StrokeData, sizeof(g_StrokeData), pszRecogConfig, &hwrRecogResult );
errCode = hci_hwr_free_recog_result(&hwrRecogResult);
errCode = hci_hwr_session_stop(nSessionId);

手写笔迹的数据是一连串的坐标点,每个坐标点是两个short,分别是 x 和 y 坐标。如果是 (-1, 0) 表示一个笔画结束(抬笔),如果是 (-1, -1) 则表示整个字结束。

云端识别只需要将能力key改为相应的云端能力key即可。

4. 实时识别

缺省情况下,识别会话是不启动实时识别的,也即每次调用 hci_hwr_recog() 函数时所输入的笔迹数据被认为是完整的笔迹数据, 如果不是(-1,0)(-1,-1)结束,会认为数据非法。

而当启用实时识别时,对于每次连续的识别内容,可以多次调用hci_hwr_recog() 。每次调用追加输入新的数据, 每次输入的数据以(-1,0)结束,也即每次输入的笔画是完整的,可以一次输入多个笔画。 最后一次以(-1,0)(-1,-1)结束,表示整次识别结束。

启动实时识别时,需要在创建识别会话时,加入realtime=yes选项。

char * pszSessionConfig = "capKey=hwr.local.freestylus,realtime=yes";
int nSessionId;
errCode = hci_hwr_session_start(pszSessionConfig, &nSessionId);
while (true)
{
// 获取新的笔迹放在 g_StrokeData中,长度为g_StorkeLen
get_storke();
char * strRecogConfig = "";
HWR_RECOG_RESULT hwrRecogResult;
errCode = hci_hwr_recog( nSessionId, g_StrokeData, g_StrokeLen, pszRecogConfig, &hwrRecogResult );
// 可以打印当前的识别结果,每次返回都是从头开始的完整结果
...
// 每次的返回结果都需要释放
errCode = hci_hwr_free_recog_result(&hwrRecogResult);
// 如果是最后一笔,跳出循环
if (is_last_stroke())
break;
}

实时识别时,每次调用本函数都会返回从头开始的完整结果,新输入的数据会导致切分发生变化, 因此后一次结果不一定是前次结果再追加字符,可能会更改掉部分前次结果。实时识别中每次返回的识别结果都需要释放。

注解
实时识别仅对 本地 多字 识别模式的能力起作用,也即本地多字能力才能设置realtime,否则会提示 HCI_ERR_CONFIG_UNSUPPORT.

5. 识别选项

识别时可以同时配置一些识别选项,来进一步控制识别流程,下面介绍部分主要选项:

  1. recogRange
    使用 recogRange 可以将识别范围限制在有限的字符集内,例如可以设置 recogRange=alphabet, 则输出肯定在52个大小写英文字母中,如果设置 recogRange=gb, 则输出为简体汉字集合, 如果设置 recogRange=big5,则输出为繁体汉字集合。也可以采用 '+' 连接多个识别范围, 例如可以设置 recogRange=lower+number+gb。英文能力hwr.local.freestylus和hwr.cloud.freewrite.english 暂时不支持识别范围的设置,传入此参数不会返回HCI_ERR_CONFIG_UNSUPPORT,会在识别时忽略此参数,但若传入的值 非法,则会返回HCI_ERR_CONFIG_INVALID。英文连写能力hwr.local.freestylus.v7只支持大小写字母范围,即lower, upper, alphabet

  2. splitMode
    在多字识别时,我们可以用splitMode设置行写或叠写模式。当应用的书写区域较宽时,可以配置splitMode=line, 表示采用行写模式,当书写区域较小时,可以配置splitMode=overlap,表示叠写模式。英文暂不支持叠写模式

  3. candNum
    表示输出的候选结果数目。

其余选项请参见 hci_hwr_recog() 函数说明。

6. 提交确认结果

当用户选择了候选中的其它结果,可以考虑提交确认结果,来帮助灵云学习用户的笔迹习惯, 以便建立针对此用户的个性化模型。

HWR_CONFIRM_ITEM confirmResult;
// 此数据必须是UTF8的
confirmResult.pszText = "确认结果";
errCode = hci_hwr_confirm(nSessionId, &confirmResult);

当采用云端识别能力时,提交确认结果时会直接将确认结果发送到云端。由于发送结果可能会带来一定的延迟感, 因此最好放在一个后台线程中进行。

当采用本地识别能力时,提交的确认结果会缓存在本地,会在上传用户历史数据时一同上传。

7. 获取联想词

灵云手写能力提供了获取联想词的功能。

为了使用联想词功能,使用capkey=hwr.local.associateword(或其他能力)开启会话:

int nSessionId = -1;
string session_config = "capkey=hwr.local.associateword";
hci_hwr_session_start(session_config.c_str(),&nSessionId);

获取联想词的方法如下:

// 输入必须是UTF8的,在某些平台上需要转码
char * szWords = "中华人民";
// 获取联想词
errCode = hci_hwr_associate_words(nSessionId,"",szWords, &sWords );
// 显示联想词
for (int i = 0; i < (int)sWords.uiItemCount; ++i)
{
// 输出是UTF8的,在某些平台下输出需要转码
printf("Associate result[%d]: %s\n",i,sWords.pItemList[i].pszWord);
}
// 释放联想词结果

上述代码的输出结果如下:

Associate result[0]: 共和国
Associate result[1]: 币
Associate result[2]: 政府
Associate result[3]: 法院
Associate result[4]: 群众
Associate result[5]: 网
Associate result[6]: 代表
Associate result[7]: 银行
Associate result[8]: 日报
Associate result[9]: 代表大会
Associate result[10]: 大学
Associate result[11]: 检察院
Associate result[12]: 币汇率
Associate result[13]: 解放军
Associate result[14]: 出版社
Associate result[15]: 生活
Associate result[16]: 大会堂
Associate result[17]: 医院
Associate result[18]: 政府关于
Associate result[19]: 广播电台
Associate result[20]: 族
Associate result[21]: 主
Associate result[22]: 间
Associate result[23]: 营
Associate result[24]: 事
Associate result[25]: 警
Associate result[26]: 众
Associate result[27]: 国
Associate result[28]: 工
Associate result[29]: 营企业
Associate result[30]: 航
Associate result[31]: 俗
Associate result[32]: 用

可以看到,获取联想词的时候会先按照输入串整体进行联想,然后依次从前去除字符进行联想, 例如,这里会先给出"共和国"(按照"中华人民"匹配),然后是"币"(按照"人民"匹配)等, 然后是"族"等(按照"民"匹配)等。(此特性可通过联想参数recursive进行打开或关闭,默认打开) 纯英文不支持此特性,中文或中英混杂时支持)

总的联想词的累计字数有一定限制,是由SDK内部确定的, 目前不能由开发者设置大小。

联想capkey中hwr.local.associateword支持英文词的联想功能(所需资源文件不同)。传入全英文请求时可以返回英文联想结果,例如:

string session_config = "capkey=hwr.local.associateword";
hci_hwr_session_start(session_config.c_str(),&nSessionId);
...
errCode = hci_hwr_associate_words( nSessionId,"","app", &sWords );

其输出为:

Associate result[0]: appal
Associate result[1]: appall
Associate result[2]: appalling
Associate result[3]: appallingly
Associate result[4]: apparatus
Associate result[5]: apparel
Associate result[6]: apparent
Associate result[7]: apparently
Associate result[8]: appeal
Associate result[9]: appealed
Associate result[10]: appealing
Associate result[11]: appeals
Associate result[12]: appear
Associate result[13]: appearance
Associate result[14]: appeared
Associate result[15]: appearing
Associate result[16]: appears
Associate result[17]: appease
Associate result[18]: appeased
Associate result[19]: appeasement

如果输入是中英文混杂的,仍会按照中文匹配方式,一个一个从前去除字符后进行联想。

联想词动态调整功能

hci_hwr_associate_words_adjust( MUST IN int nSessionId, OPT IN const char * pszConfig, MUST IN const char * pszWord )

支持中文的联想词动态调整,若输入的是词库中已有的词,则会使其出现位置提前。联想结果的排序是按词频数值进行的,词频有最大值, 如果多个词的词频都达到最大值,按照达到最大值的先后顺序,它们会被依次置顶。

若输入的是词库中没有的词,则插入词库,存于字典内的预留空间,字典大小不变,预留空间写满后较早插入的新词将被覆盖。

不支持英文联想词动态调整,当输入串为全部英文时,返回失败。

pszConfig 初始化配置串,ASCII字符串,以'\0'结束,保留接口,暂时无配置项。

pszWord 字符串指针,UTF-8格式,以'\0'为结束符,最少2个字符,最多15个字符(注意:不是15个字节)。

err_code = hci_hwr_associate_words_adjust(nSessionId,NULL,(char *)psUtf8);
if( err_code == HCI_ERR_NONE )
{
printf( "hci_hwr_associate_words_adjust success\n" );
}
else
{
printf( "hci_hwr_associate_words_adjust return (%d:%s)\n", err_code ,hci_get_error_info(err_code));
}

8. 获取拼音

灵云手写能力提供了获取拼音的功能(此功能目前仅在Windows平台上支持)。

开启会话:

int nSessionId = -1;
string session_config = "capkey=hwr.local.pinyin";
hci_hwr_session_start(session_config.c_str(),&nSessionId);

获取拼音:

// 输入必须是UTF8的,在某些平台上需要转码
char * szWords = "重";
// 获取拼音
HCI_ERR_CODE errCode = hci_hwr_pinyin( szWords, &sPy );
// 显示拼音
for (int i = 0; i < (int)sPy.uiItemCount; ++i)
{
printf("Pinyin result[%d] : %s\n",i,sPy.pItemList[i].pszPinyin);
}
// 释放拼音结果

上述代码的输出为:

Pinyin result[0] : chóng
Pinyin result[1] : zhòng

9. 笔形库功能

输出时支持笔形