文本识别模式和命令识别模式

:听写识别模式和命令识别模式。此两种模式的主要区别:主要在于识别过程中使用的匹配字典不同。前者使用的是通用字典,特点是内容多、覆盖的词汇量大、字典由sdk提供。适用于没有预定目标的随机听写之类的应用。同时因为词汇量大直接导致识别的精度降低,识别速度较慢。后者的字典需要开发者自己编写,就是你们所说的xml文件。xml文件作为一种数据存储的方式,有一定的格式,定义了sdk需要确定的一些标签,和用以匹配的词汇。这种方式由开发者定义词汇的数量,大大降低匹配过程中需要检索的词汇量,提高了识别速度。同时因为侯选项极少,所以一般不会识别错误。其缺点也是明显的:词汇量小,只有预先输入字典的词汇可以被识别出来,所以一般用来作为常用命令的识别,方便用户操作,代替菜单命令等。


利用微软Speech SDK 5.1在MFC中进行语音识别开发时的主要步骤,以Speech API 5.1+VC6为例

1、初始化COM端口


CWinApp的子类中,调用CoInitializeEx函数进行COM初始化,代码如下:

::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED); //初始化COM端口    <==>::CoInitialize(NULL);

project settings)->C/C++标签,Category中选Preprocessor,在Preprocessor definitions:下的文本框中加上“,_WIN32_DCOM”。否则编译不能通过。


2、创建识别引擎

Speech SDK 5.1 支持两种模式的:共享(Share)和独享(InProc)。一般情况下可以使用共享型,大的服务型程序使用InProc。

Share模式:

HRESULT hr = m_cpRecognizer.CoCreateInstance(CLSID_SpSharedRecognizer);//Share


Inproc模式:

HRESULT hr = m_cpRecognizer.CoCreateInstance(CLSID_SpInprocRecognizer);//InProc
//InProc型,还必须使用 ISpRecognizer::SetInput 设置语音输入
CComPtr<ISpObjectToken> cpAudioToken; //定义一个token
hr = SpGetDefaultTokenFromCategoryId(SPCAT_AUDIOIN, &cpAudioToken); //建立默认的音频输入对象
if (SUCCEEDED(hr)) 
{ 
   hr = m_cpRecognizer->SetInput(cpAudioToken, TRUE);
}
//或者
CComPtr<ISpAudio> cpAudio; //定义一个音频对象
hr = SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOIN, &cpAudio);//建立默认的音频输入对象
hr = m_cpRecoEngine->SetInput(cpAudio, TRUE);//设置识别引擎输入源
hr = cpRecoEngine->SetRecoState( SPRST_ACTIVE );





3、创建识别上下文接口

ISpRecognizer::CreateRecoContext 创建识别上下文接口(ISpRecoContext),如下:

hr = m_cpRecoEngine->CreateRecoContext( &m_cpRecoCtxt );//创建识别上下文接口



4、设置识别消息


SetNotifyWindowMessage 告诉Windows哪个是我们的识别消息,需要进行处理。如下:

hr = m_cpRecoCtxt->SetNotifyWindowMessage(m_hWnd, WM_RECOEVENT, 0, 0);//设置识别信息,SetNotifyWindowMessage 定义在                                                                          //ISpNotifySource 中





5、设置我们感兴趣的事件

SPEI_RECOGNITION“。参照 SPEVENTENUM。代码如下:

const ULONGLONG ullInterest = SPFEI(SPEI_SOUND_START) | SPFEI(SPEI_SOUND_END) | SPFEI(SPEI_RECOGNITION) ;
hr = m_cpRecoCtxt->SetInterest(ullInterest, ullInterest);



6、创建语法规则


    语法规则是识别的灵魂,必须要设置。分为两种,一种是听说式(dictation),一种是命令式(command and control---C&C)。首先利用ISpRecoContext::CreateGrammar 创建语法对象,然后加载不同的语法规则,如下:

dictation:

hr = m_cpRecoCtxt->CreateGrammar( GIDDICTATION, &m_cpDictationGrammar );
if (SUCCEEDED(hr))
{
hr = m_cpDictationGrammar->LoadDictation(NULL, SPLO_STATIC);//加载词典
}


C&C:

hr = m_cpRecoCtxt->CreateGrammar( GIDCMDCTRL, &m_cpCmdGrammar);
//然后利用ISpRecoGrammar::LoadCmdxxx 加载语法,例如从CmdCtrl.xml中加载:
WCHAR wszXMLFile[20]=L"";
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)"CmdCtrl.xml" , -1, wszXMLFile, 256);//ANSI转UNINCODE
hr = m_cpCmdGrammar->LoadCmdFromFile(wszXMLFile,SPLO_DYNAMIC);



    注意:C&C时,语法文件使用xml格式,参见Speech SDK 5.1 中的 Designing Grammar Rules。简单例子:


<GRAMMAR LANGID="804"> 
<DEFINE>
<ID NAME="CMD" VAL="10"/>
</DEFINE>
<RULE NAME="COMMAND" ID="CMD" TOPLEVEL="ACTIVE">
<L>
<p>你</P>
<p>我</p>
<p>他</p>
</L>
</RULE>
</GRAMMAR>
//LANGID="804"代表简体中文,在<*>...</*>中增加命令。



7、在开始识别时,激活语法进行识别


    dictation:

hr = m_cpDictationGrammar->SetDictationState( SPRS_ACTIVE );


    C&C:

hr = m_cpCmdGrammar->SetRuleState( NULL,NULL,SPRS_ACTIVE );



8、获取识别消息,进行处理


WM_RECOEVENT),然后处理。识别的结果放在CSpEvent的ISpRecoResult 中。如下:

USES_CONVERSION;
CSpEvent event;
switch (event.eEventId)
{
case SPEI_RECOGNITION:
{
//识别出了语音输入
m_bGotReco = TRUE;
static const WCHAR wszUnrecognized[] = L"<Unrecognized>";
CSpDynamicString dstrText;
//取得识别结果
if (FAILED(event.RecoResult()->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, TRUE ,&dstrText, NULL)))
{
dstrText = wszUnrecognized;
}
BSTR SRout;
dstrText.CopyToBSTR(&SRout);
CString Recstring;
Recstring.Empty();
Recstring = SRout;
//进一步处理
......
}
break;
}



9、释放创建的引擎、识别上下文对象、语法等。调用相应的Release函数即可。

cpRecoEngine.Release();
m_cpRecoCtxt.Release();
m_cpDictationGrammar.Release();



XML初探示例



<GRAMMAR LANGID="804"> <!--此为语音号,409为英语,804为汉语-->
  <RULE NAME="start" TOPLEVEL="ACTIVE">//规则名称任意。TopLevel选项明确搜索范围。"INACTIVE"意味着它们为复杂顶层规则的一部分,默认为INACTIVE,阻止过早识别
    <O>颜色</O>
    <RULEREF NAME="colour" PROPNAME="chosencolour"/>
  </RULE>

  <RULE NAME="colour"> //列名,任起//该名下列表中所有词将匹配加载总规则之后
    <L PROPNAME="colourvalue">
      <PHRASE VALSTR="calc.vbs">start calculator</PHRASE>//VALSTR属性只向一脚本文件
      <P VAL="1">红色</P>
      <P VAL="2">黄色</P>
      <P VAL="3">绿色</P>
    </L>
  </RULE>
</GRAMMAR>


从其他帖子中抽取的,有助于理解的


1.  ID NAME="RID_start" VAL="1"  有什么作用? VAL 是干什么用的?

这里ID我们称之为一个元素,而其中 NAME VAL 我们称之为这个元素的属性


2. RULE 定义的时候 有ID、TOPLEVEL和没有这两项有什么区别呀?ID、TOPLEVEL是干什么用的?


RULE在这里只是一个元素,ID,TOPLEVER包括那个NAME 都是它的属性,他和之前的RULE同名,但是是不同的两个元素,因为




他们属性不同


3. <P VAL="1">上</P> 和 <P>上</P> 有什么区别?


这里没有什么区别,我们把<xx>作为一个元素的开始</xx>作为一个元素的结束


4. <P>...</P> 写在 <L>...</L>有什么作用?


这个代表一个元素的开始和结束 上面已经说了