This article has been localized into Chinese by the community.
语音识别-让WPF听
在前面的文章中我们提到我们可以使用 SpeechSynthesizer 类把文字变成语音. 这篇文章中我们反过来, 把语音变成文字, 使用 System.Speech 中的 SpeechRecognition 类. 默认的情况下你的解决方案不包括这个引用, 不过我们可以很简答的添加它. 不同版本的Visual Studio有点不同, 不过它大概长这样:
添加完引用之后, 我们来做一个非常简单的语音识别:
<Window x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitionTextSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SpeechRecognitionTextSample" Height="200" Width="300">
<DockPanel Margin="10">
<TextBox Margin="0,10" Name="txtSpeech" AcceptsReturn="True" />
</DockPanel>
</Window>
using System;
using System.Speech.Recognition;
using System.Windows;
namespace WpfTutorialSamples.Audio_and_Video
{
public partial class SpeechRecognitionTextSample : Window
{
public SpeechRecognitionTextSample()
{
InitializeComponent();
SpeechRecognizer speechRecognizer = new SpeechRecognizer();
}
}
}
就这样, 上面截图中的文字是 SpeechRecognizer 通过我的耳麦听写并插入到输入框中的.
当SpeechRecognizer对象初始化的时候, Windows 启动语音识别程序, 处理剩下的事情, 把听写的结果输入到活动的程序中, 在我的电脑中, 语音识别程序长这样:
如果你从来没有使用过语音识别程序的话, Windows 会使用向导来帮助你开始使用和做些微小的调整
第一个例子允许你听写文字到你的应用程序中, 这很好, 但如果你要听到指令怎么办? Windows 和 WPF 会一起把你的按钮控件变成可以通过语音识别程序点到的指令, 你不用做什么, 就像这样:
<Window x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitionTextCommandsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SpeechRecognitionTextCommandsSample" Height="200" Width="300">
<DockPanel Margin="10">
<WrapPanel DockPanel.Dock="Top">
<Button Name="btnNew" Click="btnNew_Click">New</Button>
<Button Name="btnOpen" Click="btnOpen_Click">Open</Button>
<Button Name="btnSave" Click="btnSave_Click">Save</Button>
</WrapPanel>
<TextBox Margin="0,10" Name="txtSpeech" AcceptsReturn="True" TextWrapping="Wrap" />
</DockPanel>
</Window>
using System;
using System.Speech.Recognition;
using System.Windows;
namespace WpfTutorialSamples.Audio_and_Video
{
public partial class SpeechRecognitionTextCommandsSample : Window
{
public SpeechRecognitionTextCommandsSample()
{
InitializeComponent();
SpeechRecognizer recognizer = new SpeechRecognizer();
}
private void btnNew_Click(object sender, RoutedEventArgs e)
{
txtSpeech.Text = "";
}
private void btnOpen_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Command invoked: Open");
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Command invoked: Save");
}
}
}
你可以试下在运行上面的例子的时候说出一些指令, 比如, "New" 或者 "Open". 这会允许你听写文字到文本框中, 同时使用语音指令控制按钮, 这很酷吧?
特定的指令
在上面的例子中, Windows 会自动的进入听写模式并在文本框获得焦点额度同时, Window会尝试区分语音指令和听写文字, 然而, 某些时候, 这很困难,
上面的例子专注于听写和UI的互动, 下面我们来尝试关注特定的语音指令, 这也意味着我们将忽略听写, 就算文本框已经获得焦点.
我们将使用 SpeechRecognitionEngine 而不是 SpeechRecognizer. 这两个类最大的不同在于 SpeechRecognitionEngine 不会需要 Windows 语音识别程序运行也不需要语音识别向导, 它只关注于你在类中配置的特定语法.
在下一个例子中, 我们将会输入一些语音指定到 语音识别引擎. 我们希望它听到一个指令(属性) 和 一个值. 我们将用听到的属性和值来改变Label控件文字的颜色大小和粗细. 在我给出完整的例子前, 我想指出指令是怎么添加到语音识别引擎中的.
GrammarBuilder grammarBuilder = new GrammarBuilder();
Choices commandChoices = new Choices("weight", "color", "size");
grammarBuilder.Append(commandChoices);
Choices valueChoices = new Choices();
valueChoices.Add("normal", "bold");
valueChoices.Add("red", "green", "blue");
valueChoices.Add("small", "medium", "large");
grammarBuilder.Append(valueChoices);
speechRecognizer.LoadGrammar(new Grammar(grammarBuilder));
我们使用 GrammarBuilder来定义一些语法规则. 它有几个添加方法, 最简单的是Append(). 这个方法接受一个choices列表. 我们实例化 Choices 并加入语音指令的第一部分(命令/属性)的选项.
现在每次你使用 GrammerBuilder 的 Append 方法的时候, 你指示它听取一个单词. 对于这个例子而言, 我们希望听取两个单词, 一个用于 命令/属性, 另一个用于值(大小/颜色/粗细), 所以我们创建了两个Choices, Append 到了 GrammerBuilder 里面.
最后, 我们把整个语法 使用 LoadGrammer() 载入到了 GrammarBuilder 实例里.
以上就是指令怎么添加到语音识别引擎中的, 来看看完整的例子:
<Window x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitionCommandsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SpeechRecognitionCommandsSample" Height="200" Width="325"
Closing="Window_Closing">
<DockPanel>
<WrapPanel DockPanel.Dock="Bottom" HorizontalAlignment="Center" Margin="0,10">
<ToggleButton Name="btnToggleListening" Click="btnToggleListening_Click">Listen</ToggleButton>
</WrapPanel>
<Label Name="lblDemo" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48">Hello, world!</Label>
</DockPanel>
</Window>
using System;
using System.Globalization;
using System.Speech.Recognition;
using System.Windows;
using System.Windows.Media;
namespace WpfTutorialSamples.Audio_and_Video
{
public partial class SpeechRecognitionCommandsSample : Window
{
private SpeechRecognitionEngine speechRecognizer = new SpeechRecognitionEngine();
public SpeechRecognitionCommandsSample()
{
InitializeComponent();
speechRecognizer.SpeechRecognized += speechRecognizer_SpeechRecognized;
GrammarBuilder grammarBuilder = new GrammarBuilder();
Choices commandChoices = new Choices("weight", "color", "size");
grammarBuilder.Append(commandChoices);
Choices valueChoices = new Choices();
valueChoices.Add("normal", "bold");
valueChoices.Add("red", "green", "blue");
valueChoices.Add("small", "medium", "large");
grammarBuilder.Append(valueChoices);
speechRecognizer.LoadGrammar(new Grammar(grammarBuilder));
speechRecognizer.SetInputToDefaultAudioDevice();
}
private void btnToggleListening_Click(object sender, RoutedEventArgs e)
{
if(btnToggleListening.IsChecked == true)
speechRecognizer.RecognizeAsync(RecognizeMode.Multiple);
else
speechRecognizer.RecognizeAsyncStop();
}
private void speechRecognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
lblDemo.Content = e.Result.Text;
if(e.Result.Words.Count == 2)
{
string command = e.Result.Words[0].Text.ToLower();
string value = e.Result.Words[1].Text.ToLower();
switch(command)
{
case "weight":
FontWeightConverter weightConverter = new FontWeightConverter();
lblDemo.FontWeight = (FontWeight)weightConverter.ConvertFromString(value);
break;
case "color":
lblDemo.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value));
break;
case "size":
switch(value)
{
case "small":
lblDemo.FontSize = 12;
break;
case "medium":
lblDemo.FontSize = 24;
break;
case "large":
lblDemo.FontSize = 48;
break;
}
break;
}
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
speechRecognizer.Dispose();
}
}
}
截图中就是例子运行后我说了 "weight bold" 和 "color blue" 的结果, 很酷吧?
这个例子语法相关的已经解释了, 这个程序的界面也非常简单, 让我们来看下剩下的代码吧.
我们使用 ToggleButton 来启用或禁用识别, 对应的方法是 RecognizeAsync() 和 RecognizeAsyncStop(). RecognizeAsync() 使用一个参数来告诉识别引擎这是一个单一指令识别或多指令识别. 比如, 我们想要程序接受多个指令, 这个参数就是 Multiple. 按下这个按钮就会启动识别, 按钮按下的时候就是识别已启用, 按钮松开的时候就是识别已禁用, 按钮视觉上指示引擎的状态.
在语法建立完后最有意思的地方在于我们怎么解释指令, 我们在SpeechRecognitionCommandsSample() 中订阅了 SpeechRecognized 事件. 我们使用完全识别的文本来更新label控件的内容, 然后我们使用 e.Result.Words 来处理指令具体的要求.
首先我们检查确实有两个单词, 如果确实有两个, 那么我们根据情况分别处理.
对于粗细和颜色, 我们可以使用对应的FontWeightConverter/ColorConverter转换指令的String值到label控件可以处理的形式, 然而对于大小, 我们手动处理因为我们选择的单词不是可以自动转换的形式. 请注意你应该处理异常, 应为如果识别结果为 "weight blue" 的话你将试图为label控件的粗细设定为蓝色, 这当然会引发异常.
小结
正如你所看到的, WPF中的语音识别是简单而强大的, 你可以同过听写和(或)识别语音指令的方式来为你的应用程序提供额外的输入方式.