语音识别02

写得不好,大家就当个参考吧,希望对同学有用。
首先说明,我是很久以前(有两年了吧)做过语音识别的,当时使用的微软的Speech API 5.0,以下的说明也是以Speech API 5.0+VC6为例。
语音识别分两种模式:文本识别模式和命令识别模式.此两种模式的主要区别,主要在于识别过程中使用的匹配字典不同.前者使用的是通用字典,特点是内容多,覆盖的词汇量大,字典由sdk提供.适用于没有预定目标的随机听写之类的应用.同时因为词汇量大直接导致识别的精度降低,识别速度较慢.后者的字典需要 开发者自己编写,就是你们所说的xml文件.xml文件作为一种数据存储的方式,有一定的格式,定义了sdk需要确定的一些标签,和用以匹配的词汇.这种方式由开发者定义词汇的数量,大大降低匹配过程中需要检索的词汇量,提高了识别速度.同时因为侯选项极少,所以一般不会识别错误.其缺点也是明显的:词汇量小,只有预先输入字典的词汇可以被识别出来,所以一般用来作为常用命令的识别,方便用户操作,代替菜单命令等.在此次大赛智能精灵(奥运福娃或小狗)创意与实现题目中,第4点功能要求:

软件功能

4、智能基本要求:操作者用语音,命令奥运福娃(或宠物狗)完成以下6个基本动作;
(1)跳上木箱;
(2)跳下木箱;
(3)钻火圈(或一种运动器械);
(4)去追小皮球,并取回来;
(5)卧倒(或福娃的某种动作);
(6)打滚(或福娃的某种动作)。


应该是使用命令识别模式实现比较合适.

这种模式中,先写成一个xml文件保存到软件目录中,使用时先使用sdk命令载入字典,之后可以和使用文本识别命令一样使用.

Microsoft Speech API 5.0是通过COM实现的,由COM提供了良好的封装性,调用语音包的功能非常容易。以下简略说明一下代码:
1.在CWinApp的子类中,先初始化COM调用:
::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED); // 初始化COM
这里注意,需要Alt+F7键进入工程设置(project settings)->C/C++标签,Category中选Preprocessor,在Preprocessor definitions:下的文

本框中加上“,_WIN32_DCOM”。否则编译会通不过。
2.识别事件定义处理:
#define GID_DICTATION    0            // Dictation grammar has grammar ID 0
#define GID_CMD_GR       33333
#define WM_RECOEVENT     WM_USER+1       // Window message used for recognition events
这个语音包是消息事件驱动的。开始语音识别以后,识别引擎就一直在工作,侦听mic,一旦识别出语音,就通过发一个事先注册的事件来通知

调用程序。注册方法如下:
hr = m_cpRecoCtxt->SetNotifyWindowMessage( m_hWnd, WM_RECOEVENT, 0, 0 );//设置消息机制
添加识别事件的处理:
LRESULT CMSspeechexaDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
if(message==WM_RECOEVENT)
{
// All recognition events send this message, because that is how we
// specified we should be notified
RecoEvent(); //语音识别引擎发送了识别消息
return TRUE;
}
return CDialog::DefWindowProc(message, wParam, lParam);
}
3.使用语音输入命令模式之前,先要载入自定义的字典,语法对象:
//创建命令模式的语法对象
hr = m_cpRecoCtxt->CreateGrammar( GID_CMD_GR, &m_cpCmdGrammar);
if( FAILED(hr) )
{
MessageBox("Error CreateGrammar","Error",MB_OK);

}

WCHAR wszXMLFile[20]=L"";

//ANSI转UNINCODE
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)"CmdCtrl.xml"   , -1, wszXMLFile, 256);
//从文件中读取语法词典
hr = m_cpCmdGrammar->LoadCmdFromFile(wszXMLFile,SPLO_DYNAMIC);
if (FAILED(hr))
{
MessageBox("Error LoadCmdFromFile","Error",MB_OK);

}
激活使用命令识别:

if(b_Dic_Grammar)
{
HRESULT hr=m_cpDictationGrammar->SetDictationState( SPRS_INACTIVE );//disable text mode first
if(FAILED(hr))MessageBox("Stop SR error");
b_Dic_Grammar = FALSE;
}
if(!b_Cmd_Grammar)
{
//激活语法规则
HRESULT hr = m_cpCmdGrammar->SetRuleState(NULL,NULL,SPRS_ACTIVE);
if(FAILED(hr))
{
MessageBox("startsr error");
exit(2);
}
}
这之后就是引擎的工作,我们应用程序员不用管了。一旦引擎识别成功,程序就收到一个WM_RECOEVENT消息,通过查询识别上下文对象就可以

知道被识别的命令了。消息处理下面再讲。
再给大家看看所用的字典文件(xml文件的格式),下面是一个非常简单但完整的字典文件:
<GRAMMAR LANGID="804"> #汉语ID
    <DEFINE>
       <ID NAME="CMD" VAL="10"/>
    </DEFINE>
    <RULE NAME="COMMAND" ID="CMD" TOPLEVEL="ACTIVE">
      <L>
<p>文件</P> #识别的词
<p>操作</P>
<p>界面</p>
<p>语音</p>
<P>帮助</P>
<p>最小化</P>

      </L>
    </RULE>
</GRAMMAR>
#后是我加的注释,文件中没有的。要添加识别的词可按上面格式加上即可。
使用命令识别模式要识别的词语不多,一般也就十多个,识别引擎就在这个非常小的范围内搜索,速度非常快,而且精确度极高,我的经验是

基本上能达到95%的正确率以上。
4.文本识别也是语音识别的重要部分,有些高级应用可以考虑使用这个模式。这里也简单说说,同学们可以发挥自己的创意,想象如何应用。
和命令识别模式一样也需要载入字典,语法对象等,但这些通用资源开发包已经包含了,我们只需要简单的调用即可:
//创建听写模式的语法对象
hr = m_cpRecoCtxt->CreateGrammar( GID_DICTATION, &m_cpDictationGrammar );
if   (SUCCEEDED(hr))
{
//加载词典
hr = m_cpDictationGrammar->LoadDictation(NULL, SPLO_STATIC);
}
else
MessageBox("error4");

if (FAILED(hr))
{
m_cpDictationGrammar.Release();
MessageBox("start SR error");
}
文本识别模式的正确率相对命令模式就逊色多了,经过多次训练语音引擎后,能达到80%正确率就很好了。这里也有窍门,一般连贯的整句或短

语比散乱的单字、词的识别率高。例如你连贯的说出:山东大学计算机科学与技术学院,就比拆开的:山东   大学   计算机   科学 与   技术  

学院,的识别正确率高得多。还有,建议大家坚持只用一个普通话标准的人的声音训练引擎,以防止干扰(这是血的教训,我们有一次差点为

这个出问题)。若有其他人也想试试的话,一定要新建一个配置文件。
5.识别成功消息处理。
我们先前在初始化识别引擎的时候,必须先创建一个识别上下文对象,这个对象用来在引擎内外传送数据:
hr = cpRecoEngine->CreateRecoContext( &m_cpRecoCtxt ); //创建识别上下文对象
在识别成功的消息处理中,就要从这个对象中取识别出来的文本了:
USES_CONVERSION;
CSpEvent event;

     // Process all of the recognition events
     while (event.GetFrom(m_cpRecoCtxt) == S_OK)
     {
         switch (event.eEventId)
         {
......
case SPEI_RECOGNITION:
// There may be multiple recognition results, so get all of them
{
//识别出了语音输入
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;
... ...
到这里,语音识别就算完成了,识别到的语音信息用文本方式保存在Recsting中,下面就可以作自己的具体应用了。

我给大家写了一个简单的例子,使用VC6,在Windows XP下通过。我的机器安装了Office2003,我没有装MS speech API 5.0,语音功能也正常实

现了。大家不明白的地方就直接看代码吧。例子程序启动后,按Start CMD Reco按钮进入命令识别模式.对mic说"最小化",窗口就最小化了.说"文件""操作""帮助"等,会弹出相应的对话框.
完整应用的例子大家可以向组委会要第二届大赛作品的代码.其中山东大学Duke队的作品里就包含了语音识别的两种模式的应用,语音识别的代码就集中在Duke软件的界面部分.

我个人认为,这个大赛题目中语音识别的应用技术上不存在太大的困难,这个题目更多的应该是考验同学们的创新能力,设计能力.这些能力在实际工作中是非常重要的,其重要性一点不比技术低.希望大家在这次比赛中可以学到知识,发展能力.

你可能感兴趣的:(api,cmd,null,引擎,events,preprocessor)