语音识别
语音识别项目03/10/2015使用.NET桌面应用程序进行语音识别JamesMcCaffrey
下载代码示例
自个人语音助理WindowsPhoneCortana(以及来自水果公司的那个不能直呼其名的类似产品)面世以来,支持语音的应用程序在软件开发方面发挥着越来越重要的作用。在本文中,我将介绍如何在Windows控制台应用程序、WindowsForms应用程序和WindowsPresentationFoundation(WPF)应用程序中开始进行语音识别和语音合成。
请注意,您还可以向WindowsPhone应用程序、ASP.NETWeb应用程序、Windows应用商店应用程序、WindowsRT应用程序和XboxKinect中添加语音功能,但实现这些功能的技术与本文所述的技术有所不同。
了解本文内容的最好方法是查看图1和图2中两个不同演示程序的屏幕截图。图1中的控制台应用程序启动之后,该应用程序会立刻说出“我醒了”这句话。当然,您在阅读这篇文章时无法听到演示所说的话,因此演示程序会以文本方式显示计算机所说的内容。接下来,用户说出命令“开启语音”。演示将回显识别的文本,然后在后台启用应用程序,以侦听并响应将两个数字相加的请求。
图1控制台应用程序中的语音识别和合成
图2WindowsForms应用程序中的语音识别
用户要求应用程序计算一加二,然后计算二加三。应用程序将识别这些语音命令并说出答案。稍后,我将说明使用语音识别的更有用的方法。
然后,用户发出命令“关闭语音”,此命令将停用侦听将数字相加的命令,但不会完全停用语音识别。语音关闭后,将忽略下一个要求计算一加二的语音命令。最后,用户重新打开语音并说出无意义的命令:“Klatubaradanikto”,应用程序将其识别为完全停用语音识别并退出应用程序的命令。
图2显示了支持语音的虚拟WindowsForms应用程序。该应用程序将识别语音命令,但不会以语音输出方式响应。该应用程序首次启用时,“开启语音”复选框控件为未选中状态,表示语音识别功能尚未激活。用户选中“开启语音”控件,然后说:“你好”。该应用程序将在应用程序底部的ListBox控件中回显识别的语音文本。
然后用户说:“将文本框1设置为红色”。该应用程序将识别“设置文本框1红色”,这与用户所说的内容几乎一致,但不完全一致。尽管在图2中未显示,但应用程序顶部的TextBox控件中的文本的确已设置为“红色”。
接下来,用户说:“请将文本框1设置为白色”。该应用程序将识别“设置文本框1白色”,并按此执行操作。用户最后说:“再见”,该应用程序将回显该命令,但并未操作WindowsForms,尽管它可以(例如)通过取消选中“开启语音”复选框控件执行此操作。
在接下来的部分中,我将向您介绍创建这两种演示程序的过程,包括安装所需的.NET语音库。本文假设您至少具有中级编程技能,但并不假定您完全了解语音识别或语音合成。
将语音添加到控制台应用程序为了创建图1中所示的演示,我启动了VisualStudio并创建了一个名为ConsoleSpeech的新C#控制台应用程序。我成功地在VisualStudio2010和2012中使用了语音,任何最新版本应该都能正常使用。在将模板代码加载到编辑器之后,我在解决方案资源管理器窗口中将文件Program.cs重命名为更具描述性的ConsoleSpeechProgram.cs,然后VisualStudio将重命名Program类。
接下来,我向C:ProgramFiles(x86)MicrosoftSDKsSpeechv11.0Assembly中的文件Microsoft.Speech.dll添加了一个引用。我的主机上没有该DLL,必须进行下载。安装向应用程序添加语音识别与合成所需的文件并不是一件容易的事。我将在本文的下一部分详细解释这一安装过程,但现在,假设我的计算机上有Microsoft.Speech.dll。
将引用添加到语音DLL之后,我在源代码顶部删除了除指向顶级System命名空间的using语句之外的所有其他using语句。然后,我将using语句添加到命名空间Microsoft.Speech.Recognition、Microsoft.Speech.Synthesis和System.Globalization。前两个命名空间与语音DLL相关联。注:有点令人困惑的是,还有System.Speech.Recognition和System.Speech.Synthesis命名空间。我随后会解释二者之间的不同。默认情况下,Globalization命名空间可用,且无需向项目中添加新引用。
控制台应用程序演示的完整源代码如图3所示,且本文随附的代码下载部分提供完整源代码。我去掉了所有常规错误检查,以尽可能突出核心内容。
图3演示控制台应用程序源代码
usingSystem;usingMicrosoft.Speech.Recognition;usingMicrosoft.Speech.Synthesis;usingSystem.Globalization;namespaceConsoleSpeech{ classConsoleSpeechProgram { staticSpeechSynthesizerss=newSpeechSynthesizer(); staticSpeechRecognitionEnginesre; staticbooldone=false; staticboolspeechOn=true; staticvoidMain(string[]args) { try { ss.SetOutputToDefaultAudioDevice(); Console.WriteLine(" (Speaking:Iamawake)"); ss.Speak("Iamawake"); CultureInfoci=newCultureInfo("en-us"); sre=newSpeechRecognitionEngine(ci); sre.SetInputToDefaultAudioDevice(); sre.SpeechRecognized+=sre_SpeechRecognized; Choicesch_StartStopCommands=newChoices(); ch_StartStopCommands.Add("speechon"); ch_StartStopCommands.Add("speechoff"); ch_StartStopCommands.Add("klatubaradanikto"); GrammarBuildergb_StartStop=newGrammarBuilder(); gb_StartStop.Append(ch_StartStopCommands); Grammarg_StartStop=newGrammar(gb_StartStop); Choicesch_Numbers=newChoices(); ch_Numbers.Add("1"); ch_Numbers.Add("2"); ch_Numbers.Add("3"); ch_Numbers.Add("4"); GrammarBuildergb_WhatIsXplusY=newGrammarBuilder(); gb_WhatIsXplusY.Append("Whatis"); gb_WhatIsXplusY.Append(ch_Numbers); gb_WhatIsXplusY.Append("plus"); gb_WhatIsXplusY.Append(ch_Numbers); Grammarg_WhatIsXplusY=newGrammar(gb_WhatIsXplusY); sre.LoadGrammarAsync(g_StartStop); sre.LoadGrammarAsync(g_WhatIsXplusY); sre.RecognizeAsync(RecognizeMode.Multiple); while(done==false){;} Console.WriteLine(" Hittocloseshell "); Console.ReadLine(); } catch(Exceptionex) { Console.WriteLine(ex.Message); Console.ReadLine(); } }//Main staticvoidsre_SpeechRecognized(objectsender, SpeechRecognizedEventArgse) { stringtxt=e.Result.Text; floatconfidence=e.Result.Confidence; Console.WriteLine(" Recognized:"+txt); if(confidence=0) { Console.WriteLine("SpeechisnowON"); speechOn=true; } if(txt.IndexOf("speechoff")>=0) { Console.WriteLine("SpeechisnowOFF"); speechOn=false; } if(speechOn==false)return; if(txt.IndexOf("klatu")>=0&&txt.IndexOf("barada")>=0) { ((SpeechRecognitionEngine)sender).RecognizeAsyncCancel(); done=true; Console.WriteLine("(Speaking:Farewell)"); ss.Speak("Farewell"); } if(txt.IndexOf("What")>=0&&txt.IndexOf("plus")>=0) { string[]words=txt.Split('); intnum1=int.Parse(words[2]); intnum2=int.Parse(words[4]); intsum=num1+num2; Console.WriteLine("(Speaking:"+words[2]+"plus"+ words[4]+"equals"+sum+")"); ss.SpeakAsync(words[2]+"plus"+words[4]+ "equals"+sum); } }//sre_SpeechRecognized }//Program}//ns在using语句后,演示代码的开头如下所示:
namespaceConsoleSpeech{ classConsoleSpeechProgram { staticSpeechSynthesizerss=newSpeechSynthesizer(); staticSpeechRecognitionEnginesre; staticbooldone=false; staticboolspeechOn=true; staticvoidMain(string[]args) {...类作用域SpeechSynthesizer对象使应用程序具有朗读的功能。SpeechRecognitionEngine对象使应用程序可以侦听并识别语音单词或短语。布尔型变量“done”确定整个应用程序何时完成。布尔型变量speechOn控制应用程序是否侦听除退出程序的命令之外的任何命令。
这里的思路是控制台应用程序不接受从键盘键入的输入,因此应用程序始终侦听命令。但是,如果speechOn为false,则应用程序将只识别退出程序的命令并执行此命令;同时会识别但忽略其他命令。
Main方法开始执行:
try{ ss.SetOutputToDefaultAudioDevice(); Console.WriteLine(" (Speaking:Iamawake)"); ss.Speak("Iamawake");在声明SpeechSynthesizer对象时,将其实例化。使用合成器对象非常简单。SetOutputToDefaultAudioDevice方法将输出发送到计算机的扬声器(也可将输出发送到文件)。Speak方法将接受字符串,并朗读出来。就是这么简单。
语音识别要比语音合成困难得多。Main方法继续创建识别器对象:
CultureInfoci=newCultureInfo("en-us");sre=newSpeechRecognitionEngine(ci);sre.SetInputToDefaultAudioDevice();sre.SpeechRecognized+=sre_SpeechRecognized;首先,在CultureInfo对象中指定要识别的语言,本例中为美国英语。CultureInfo对象位于使用using语句引用的Globalization命名空间中。接下来,在调用SpeechRecognitionEngine构造函数之后,将语音输入设置为默认音频设备,在大多数情况下默认音频设备为麦克风。请注意,大多数笔记本电脑有内置麦克风,但大多数台式计算机需要外接麦克风(现在通常与耳机组合在一起)。
识别器对象的关键方法是SpeechRecognized事件处理程序。在使用VisualStudio时,如果您键入“sre.SpeechRecognized+=”并等待片刻,IntelliSense功能将附加上“sre_SpeechRecognized”自动完成该语句,作为事件处理程序的名称。我建议点击Tab键来接受并使用该默认名称。
接下来,演示将设置识别将两个数字相加的命令的功能:
Choicesch_Numbers=newChoices();ch_Numbers.Add("1");ch_Numbers.Add("2");ch_Numbers.Add("3");ch_Numbers.Add("4");//TechnicallyAdd(newstring[]{"4"});GrammarBuildergb_WhatIsXplusY=newGrammarBuilder();gb_WhatIsXplusY.Append("Whatis");gb_WhatIsXplusY.Append(ch_Numbers);gb_WhatIsXplusY.Append("plus");gb_WhatIsXplusY.Append(ch_Numbers);Grammarg_WhatIsXplusY=newGrammar(gb_WhatIsXplusY);此处的三个关键对象是Choices集合、GrammarBuilder模板和控制Grammar。在我设计识别Grammar时,我首先列出了一些要识别的特定示例。例如,“一加二等于几?”以及“三加四等于几?”
然后确定相应的通用模板,例如,“加等于几?”此模板是GrammarBuilder,填入模板的特定值是Choices。Grammar对象将封装模板和Choices。
在本演示中,我将要相加的数字限制为1到4,并将它们作为字符串添加到Choices集合。更好的方法是:
string[]numbers=newstring[]{"1","2","3","4"};Choicesch_Numbers=newChoices(numbers);我介绍创建Choices集合的较差的方法是出于以下两个原因。第一,一次添加一个字符串是我在其他语音示例中所看到过的唯一方法。第二,您可能认为一次添加一个字符串可能无法实现;实时VisualStudioIntelliSense表明其中一个Add重载将接受类型为“paramsstring[]phrases”的参数。如果您没有注意params关键字,您可能认为Add方法仅接受字符串数组,而不是类型字符串数组或单个字符串。我建议传递数组。
创建连续数字的Choices集合是一个特例,允许如下所示的编程方法:
string[]numbers=newstring[100];for(inti=0;i=0){ Console.WriteLine("SpeechisnowOFF"); speechOn=false;}if(speechOn==false)return;尽管最初逻辑可能并不明显,但如果您查看几分钟,逻辑可能会有意义。接下来处理秘密退出命令:
if(txt.IndexOf("klatu")>=0&&txt.IndexOf("barada")>=0){ ((SpeechRecognitionEngine)sender).RecognizeAsyncCancel(); done=true; Console.WriteLine("(Speaking:Farewell)"); ss.Speak("Farewell");}请注意,语音识别引擎实际上可以识别无意义的单词。如果Grammar对象包含对象内置词典中没有的单词,则Grammar将使用语义试探法来尝试尽可能识别这些单词,且通常都会成功。这就是为什么我使用“klatu”而不是正确的“klaatu”(出自一部老的科幻电影)的原因。
还请注意,您无需处理已完整识别的Grammar文本(“klatubaradanikto”),只需获取足够的信息来唯一标识语法短语(“klatu”和“barada”)。
接下来,将处理将两个数字相加的命令,然后处理事件处理程序,最后处理Program类和命名空间:
... if(txt.IndexOf("What")>=0&&txt.IndexOf("plus")>=0) { string[]words=txt.Split('); intnum1=int.Parse(words[2]); intnum2=int.Parse(words[4]); intsum=num1+num2; Console.WriteLine("(Speaking:"+words[2]+ "plus"+words[4]+"equals"+sum+")"); ss.SpeakAsync(words[2]+"plus"+words[4]+ "equals"+sum); } }//sre_SpeechRecognized }//Program}//ns请注意,Results.Text中的文本区分大小写(“What”与“what”)。识别短语之后,则可以解析出特定单词。在这种情况下,已识别的文本的格式为“x加y等于几”,因此“几”在words[0]中,要相加的两个数字(作为字符串)分别在words[2]和words[4]中。
安装库对演示程序的介绍假定您的计算机上已安装所有必需的语音库。要创建并运行演示程序,您需要安装四个程序包:用于在VisualStudio中创建演示的SDK、用于在创建演示后执行演示的运行时、识别语言、以及合成(朗读)语言。
要安装SDK,请在Internet上搜索“SpeechPlatform11SDK”。将打开Microsoft下载中心的正确页面,如图4所示。单击“下载”按钮后,您将看到如图5所示的选项。SDK有32位和64位两种版本。我强烈建议使用32位版本,无论您的主机是什么版本。64位版本无法与某些应用程序互操作。
图4Microsoft下载中心的SDK安装主页
图5安装语音SDK
您只需要一个x86(32位).msi文件。选择该文件并单击“下一步”按钮后,即可直接运行安装程序。语音库不会提供安装何时完成的反馈信息,因此,不要期待收到安装成功的消息。
接下来,要安装语音运行时。找到主页并单击“下一步”按钮之后,您将看到如图6所示的选项。
图6安装语音运行时
选择与SDK相同的平台版本(本演示为11)和位数版本(32[x86]或64[x64]),这一点非常重要。同样,我强烈建议使用32位版本,即使您在使用64位计算机。
接下来,您可以安装识别语言。下载页面如图7所示。此演示使用了文件MSSpeech_SR_en-us_TELE.msi(美国英语)。SR代表语音识别,TELE代表电话,表示识别语言设计成在低质量音频输入下工作,例如识别来自电话或台式计算机麦克风的音频输入。
图7安装识别语言
最后,您可以安装语音合成语言和语音。下载页面如图8所示。此演示使用文件MSSpeech_TTS_en-us_Helen.msi。TTS代表文本到语音,这实际上是语音合成的同义词短语。请注意,有两种英语可以使用美国语音。其他英语可以使用非美国语音。创建合成文件相当困难。您可以从几家公司购买并安装其他语音。
图8安装合成语言和语音
有趣的是,虽然语音识别语言和语音合成语音/语言完全不同,但两者的下载是同一个下载页面上的选项。可以从下载中心UI同时选中识别语言和合成语言,但尝试同时安装它们对我来说是个灾难,因此,我建议一次安装一个。
Microsoft.Speech与System.Speech如果您不熟悉Windows应用程序的语音识别与合成,您很容易被这些文档弄糊涂,因为有多个语音平台。尤其是,除了本文演示所使用的Microsoft.Speech.dll库之外,还有作为Windows操作系统一部分的System.Speech.dll库。从API几乎相同(但并非完全相同)的意义上来讲,这两个库相似。因此,如果您联机搜索语音示例,找到了代码段而不是完整的程序,则您将很难判断示例引用的是System.Speech还是Microsoft.Speech。
关键问题在于,如果您是语音开发方面的初学者,请使用Microsoft.Speech库而不是System.Speech库来将语音添加到.NET应用程序。
尽管两个库共享某些相同的核心基础代码,且API相似,但它们是完全不同的。图9的表中总结了一些主要的区别。
图9Microsoft.Speech与System.Speech
Microsoft.Speech.dllSystem.Speech.dll必须单独安装操作系统的一部分(WindowsVista+)可以与应用程序打包在一起无法重新分发必须构造Grammar使用Grammar或自由听写没有用户培训培训特定用户托管代码API(C#)本机代码API(C++)System.SpeechDLL是操作系统的一部分,因此它安装在每个Windows计算机上。Microsoft.SpeechDLL(以及关联的运行时和语言)必须下载并安装到计算机上。System.Speech识别通常需要用户培训,其中用户朗读一些文本,系统学习理解特定用户的发音。Microsoft.Speech识别可立即适用于任何用户。System.Speech几乎可以识别任何单词(称为自由听写)。Microsoft.Speech只识别程序定义的Grammar中的单词和短语。
将语音识别添加到WindowsForms应用程序将语音识别与合成添加到WindowsForms或WPF应用程序的过程类似于将语音添加到控制台应用程序的过程。要创建如图2所示的虚拟演示程序,我启动了VisualStudio并创建了新的C#WindowsForms应用程序,将其命名为WinFormSpeech。
将模板代码加载到VisualStudio编辑器之后,在解决方案资源管理器窗口中,我向文件Microsoft.Speech.dll中添加了一个引用,正如我在控制台应用程序演示中所做的操作一样。在源代码的顶端,我删除了不必要的using语句,只剩下对System、Data、Drawing和Forms命名空间的引用。我添加了两个using语句来将Microsoft.Speech.Recognition和System.Globalization命名空间引入作用域。
WindowsForms演示不使用语音合成,因此,我没有使用对Microsoft.Speech.Synthesis库的引用。将语音合成添加到WindowsForms应用程序与将合成添加到控制台应用程序完全相同。
在VisualStudio设计视图中,我将TextBox控件、CheckBox控件和ListBox控件拖放到Form上。在CheckBox控件上双击后,VisualStudio自动创建了CheckChanged事件处理程序方法的框架。
请注意,控制台应用程序演示将立即开始侦听语音命令,并一直侦听直到退出应用程序。该方法可用于WindowsForms应用程序,但我决定允许用户通过使用CheckBox控件来在语音识别开启和关闭之间进行切换。
演示程序Form1.cs文件的源代码定义了局部类,如图10所示。将声明语音识别引擎对象,并实例化为Form成员。在Form构造函数中,我挂接了SpeechRecognized事件处理程序,创建并加载了两个Grammar:
publicForm1(){ InitializeComponent(); sre.SetInputToDefaultAudioDevice(); sre.SpeechRecognized+=sre_SpeechRecognized; Grammarg_HelloGoodbye=GetHelloGoodbyeGrammar(); Grammarg_SetTextBox=GetTextBox1TextGrammar(); sre.LoadGrammarAsync(g_HelloGoodbye); sre.LoadGrammarAsync(g_SetTextBox); //sre.RecognizeAsync()isinCheckBoxevent}图10将语音识别添加到WindowsForms
usingSystem;usingSystem.Data;usingSystem.Drawing;usingSystem.Windows.Forms;usingMicrosoft.Speech.Recognition;usingSystem.Globalization;namespaceWinFormSpeech{ publicpartialclassForm1:Form { staticCultureInfoci=newCultureInfo("en-us"); staticSpeechRecognitionEnginesre=newSpeechRecognitionEngine(ci); publicForm1() { InitializeComponent(); sre.SetInputToDefaultAudioDevice(); sre.SpeechRecognized+=sre_SpeechRecognized; Grammarg_HelloGoodbye=GetHelloGoodbyeGrammar(); Grammarg_SetTextBox=GetTextBox1TextGrammar(); sre.LoadGrammarAsync(g_HelloGoodbye); sre.LoadGrammarAsync(g_SetTextBox); //sre.RecognizeAsync()isinCheckBoxevent } staticGrammarGetHelloGoodbyeGrammar() { Choicesch_HelloGoodbye=newChoices(); ch_HelloGoodbye.Add("hello"); ch_HelloGoodbye.Add("goodbye"); GrammarBuildergb_result=newGrammarBuilder(ch_HelloGoodbye); Grammarg_result=newGrammar(gb_result); returng_result; } staticGrammarGetTextBox1TextGrammar() { Choicesch_Colors=newChoices(); ch_Colors.Add(newstring[]{"red","white","blue"}); GrammarBuildergb_result=newGrammarBuilder(); gb_result.Append("settextbox1"); gb_result.Append(ch_Colors); Grammarg_result=newGrammar(gb_result); returng_result; } privatevoidcheckBox1_CheckedChanged(objectsender,EventArgse) { if(checkBox1.Checked==true) sre.RecognizeAsync(RecognizeMode.Multiple); elseif(checkBox1.Checked==false)//Turnoff sre.RecognizeAsyncCancel(); } voidsre_SpeechRecognized(objectsender,SpeechRecognizedEventArgse) { stringtxt=e.Result.Text; floatconf=e.Result.Confidence; if(conf {listBox1.Items.Add("Iheardyousay:"+txt);}));//WinFormspecific if(txt.IndexOf("text")>=0&&txt.IndexOf("box")>= 0&&txt.IndexOf("1")>=0) { string[]words=txt.Split('); this.Invoke(newMethodInvoker(()=> {textBox1.Text=words[4];}));//WinFormspecific } } }//Form}//ns我可以像在控制台应用程序演示中一样直接创建两个Grammar对象,但为了简化操作,我定义了两个Helper方法GetHelloGoodbyeGrammar和GetTextBox1TextGrammar来执行此操作。
请注意,Form构造函数不会调用RecognizeAsync方法,表示当应用程序启动时,不会立即激活语音识别。
Helper方法GetHelloGoodbyeGrammar遵循本文前面所述的相同模式:
staticGrammarGetHelloGoodbyeGrammar(){ Choicesch_HelloGoodbye=newChoices(); ch_HelloGoodbye.Add("hello");//Shouldbeanarray! ch_HelloGoodbye.Add("goodbye"); GrammarBuildergb_result= newGrammarBuilder(ch_HelloGoodbye); Grammarg_result=newGrammar(gb_result); returng_result;}同样,创建Grammar对象以在WindowsFormsTextBox控件中设置文本的Helper方法不存在任何惊喜:
staticGrammarGetTextBox1TextGrammar(){ Choicesch_Colors=newChoices(); ch_Colors.Add(newstring[]{"red","white","blue"}); GrammarBuildergb_result=newGrammarBuilder(); gb_result.Append("settextbox1"); gb_result.Append(ch_Colors); Grammarg_result=newGrammar(gb_result); returng_result;}Helper将识别短语“设置文本框1红色”。但是,用户无需准确地说出这一短语。例如,用户可能会说“请将文本框1中的文本设置为红色”,语音识别引擎仍会将此短语识别为“设置文本框1红色”,尽管与用户完全匹配Grammar模式的情况相比,上述情况的置信度值较低。换句话说,当您创建Grammar时,无需考虑短语的每个变体。这极大地简化了语音识别的使用。
定义CheckBox事件处理程序,如下所示:
privatevoidcheckBox1_CheckedChanged(objectsender,EventArgse){ if(checkBox1.Checked==true) sre.RecognizeAsync(RecognizeMode.Multiple); elseif(checkBox1.Checked==false)//Turnoff sre.RecognizeAsyncCancel();}在WindowsForms应用程序的生存期期间,始终存在语音识别引擎对象sre。用户切换CheckBox控件时,将使用RecognizeAsync和RecognizeAsyncCancel方法来激活和停用该对象。
语音识别的事件处理程序的定义的开头部分如下所示:
voidsre_SpeechRecognized(objectsender,SpeechRecognizedEventArgse){ stringtxt=e.Result.Text; floatconf=e.Result.Confidence; if(conf {listBox1.Items.Add("Iheardyousay:"+txt);})); if(txt.IndexOf("text")>=0&& txt.IndexOf("box")>=0&&txt.IndexOf("1")>=0) { string[]words=txt.Split('); this.Invoke(newMethodInvoker(()=> {textBox1.Text=words[4];})); }}已识别的文本将使用MethodInvoker委托在ListBox控件中回显。由于语音识别器在不同于WindowsFormsUI线程的其他线程中运行,直接尝试访问ListBox控件,如:
listBox1.Items.Add("Iheardyousay:"+txt);将会失败,并引发异常。MethodInvoker的替代方法是使用Action委托,如下所示:
this.Invoke((Action)(()=> listBox1.Items.Add("Iheardyousay:"+txt)));理论上,在这种情况下,使用MethodInvoker委托要比使用Action委托略高效,因为MethodInvoker是Windows.Forms命名空间的一部分,因此专用于Windows.Forms应用程序。Action委托更通用。本示例表明您可以使用极其强大和有用的语音识别完全操控WindowsForms应用程序。
总结如果您要研究使用.NET应用程序进行语音识别和语音合成,本文所提供的信息应该可以让您开始入门。您克服了最初的安装和学习障碍之后,掌握技术本身并不是特别困难。语音识别与合成的真正问题在于确定它们何时有用。
通过控制台应用程序,您可以创建有趣的一问一答对话,用户提出问题,应用程序回答,形成类似Cortana的环境。您要注意的是,当您的计算机朗读时,麦克风会拾取这些语音,并可能进行识别。我发现了一些有趣的情况,我询问一个问题,应用程序识别并回答,但语音回答又触发了另一个识别事件,我最终进入了一个有趣的无限语音循环。
控制台应用程序语音的另一个可能的用途是识别命令,如“启动记事本”和“启动Word”。换句话说,控制台应用程序可用于在主机上执行通常需使用多个鼠标和键盘交互来执行的操作。
JamesMcCaffrey博士 任职于华盛顿州雷德蒙德市的Microsoft研究中心。他长期从事多个Microsoft产品(包括InternetExplorer和Bing)的研发工作。可以在jammc@microsoft.com上联系McCaffrey博士。
衷心感谢以下MicrosoftResearch技术专家对本文的审阅:RobGruen、MarkMarron和CurtisvonVeh