使用定向麦克风进行波束追踪 (Beam Tracking for a Directional Microphone)

可以使用这4个麦克风来模拟定向麦克风产生的效果,这个过程称之为波束追踪(beam tracking)

界面上的细长矩形用来指示某一时刻探测到的说话者的语音方向。矩形有一个旋转变换,在垂直轴上左右摆动,以表示声音的不同来源方向。

  1. <Rectangle Fill="#1BA78B" HorizontalAlignment="Left" Margin="240,41,0,39" Stroke="Black" Width="" RenderTransformOrigin="0.5,0">
  2. <Rectangle.RenderTransform>
  3. <TransformGroup>
  4. <ScaleTransform/>
  5. <SkewTransform/>
  6. <RotateTransform Angle="{Binding BeamAngle}"/>
  7. <TranslateTransform/>
  8. </TransformGroup>
  9. </Rectangle.RenderTransform>
  10. </Rectangle>

上图是程序的UI界面。后台逻辑代码和之前的例子大部分都是相同的。首先实例化一个KinectAudioSource对象,然后将主窗体的DataContext赋值给本身。将BeamAngleMode设置为Adaptive,使得能够自动追踪说话者的声音。我们需要编写KinectAudioSource对象的BeamChanged事件对应的处理方法。当用户的说话时,位置发生变化时就会触发该事件。我们需要创建一个名为BeamAngle的属性,使得矩形的RotateTransform可以绑定这个属性。

  1. public partial class MainWindow : Window, INotifyPropertyChanged
  2. {
  3. public MainWindow()
  4. {
  5. InitializeComponent();
  6. this.DataContext = this;
  7. this.Loaded += delegate { ListenForBeamChanges(); };
  8. }
  9.  
  10. private KinectAudioSource CreateAudioSource()
  11. {
  12. var source = KinectSensor.KinectSensors[].AudioSource;
  13. source.NoiseSuppression = true;
  14. source.AutomaticGainControlEnabled = true;
  15. source.BeamAngleMode = BeamAngleMode.Adaptive;
  16. return source;
  17. }
  18.  
  19. private void ListenForBeamChanges()
  20. {
  21. KinectSensor.KinectSensors[].Start();
  22. var audioSource = CreateAudioSource();
  23. audioSource.BeamAngleChanged += audioSource_BeamAngleChanged;
  24. audioSource.Start();
  25. }
  26.  
  27. public event PropertyChangedEventHandler PropertyChanged;
  28.  
  29. private void OnPropertyChanged(string propName)
  30. {
  31. if (PropertyChanged != null)
  32. PropertyChanged(this, new PropertyChangedEventArgs(propName));
  33. }
  34.  
  35. private double _beamAngle;
  36. public double BeamAngle
  37. {
  38. get { return _beamAngle; }
  39. set
  40. {
  41. _beamAngle = value;
  42. OnPropertyChanged("BeamAngle");
  43. }
  44. }
  45. }

以上代码中,还需要对BeamChanged事件编写对应的处理方法。每次当波束的方向发生改变时,就更改BeamAngle的属性。SDK中使用弧度表示角度。所以在事件处理方法中我们需要将弧度换成度。为了能达到说话者移到左边,矩形条也能够向左边移动的效果,我们需要将角度乘以一个 –1

  1. void audioSource_BeamAngleChanged(object sender, BeamAngleChangedEventArgs e)
  2. {
  3. BeamAngle = - * e.Angle;
  4. }

语音命令识别

结合KinectAudioSource和SpeechRecognitionEngine来演示语音命令识别的强大功能。为了展示语音命令能够和骨骼追踪高效结合,我们会使用语音命令向窗体上绘制图形,并使用命令移动这些图形到光标的位置

CrossHair用户控件简单的以十字光标形式显示当前用户右手的位置。下面的代码显示了这个自定义控件的XAML文件。注意到对象于容器有一定的偏移使得十字光标的中心能够处于Grid的零点。

自定义控件  CrossHairs

CrossHair用户控件简单的以十字光标形式显示当前用户右手的位置。下面的代码显示了这个自定义控件的XAML文件。注意到对象于容器有一定的偏移使得十字光标的中心能够处于Grid的零点。

  1. <Grid Height="50" Width="50" RenderTransformOrigin="0.5,0.5">
  2. <Grid.RenderTransform>
  3. <TransformGroup>
  4. <ScaleTransform/>
  5. <SkewTransform/>
  6. <RotateTransform/>
  7. <TranslateTransform X="-25" Y="-25"/>
  8. </TransformGroup>
  9. </Grid.RenderTransform>
  10. <Rectangle Fill="#FFF4F4F5" Margin="22,0,20,0" Stroke="#FFF4F4F5"/>
  11. <Rectangle Fill="#FFF4F4F5" Margin="0,22,0,21" Stroke="#FFF4F4F5"/>
  12. </Grid>

在应用程序的主窗体中,将根节点从 grid 对象改为 canvas对象。Canvas对象使得将十字光标使用动画滑动到手的位置比较容易。在主窗体上添加一个CrossHairs自定义控件。在下面的代码中,我们可以看到将Canvas对象嵌套在了一个Viewbox控件中。这是一个比较老的处理不同屏幕分辨率的技巧。ViewBox控件会自动的将内容进行缩放以适应实际屏幕的大小。设置MainWindows的背景色,并将Canvas的颜色设置为黑色。然后在Canvas的底部添加两个标签。一个标签用来显示SpeechRecognitionEngine将要处理的语音指令,另一个标签显示匹配正确的置信度。CrossHair自定义控件绑定了HandTop和HandLeft属性。两个标签分别绑定了HypothesizedText和Confidence属性。

  1. <Window x:Class="KinectPutThatThere.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:local="clr-namespace:KinectPutThatThere"
  5. Title="Put That There" Background="Black">
  6. <Viewbox>
  7. <Canvas x:Name="MainStage" Height="1080" Width="1920" Background="Black" VerticalAlignment="Bottom">
  8. <local:CrossHairs Canvas.Top="{Binding HandTop}" Canvas.Left="{Binding HandLeft}" />
  9. <Label Foreground="White" Content="{Binding HypothesizedText}" Height="55" FontSize="32" Width="965" Canvas.Left="115" Canvas.Top="1025" />
  10. <Label Foreground="Green" Content="{Binding Confidence}" Height="55" Width="114" FontSize="32" Canvas.Left="0" Canvas.Top="1025" />
  11. </Canvas>
  12. </Viewbox>
  13. </Window>

在后台逻辑代码中,让MainWindows对象实现INofityPropertyChanged事件并添加OnPropertyChanged帮助方法。我们将创建4个属性用来为前台UI界面进行绑定。

  1. public partial class MainWindow : Window, INotifyPropertyChanged
  2. {
  3. private double _handLeft;
  4. public double HandLeft
  5. {
  6. get { return _handLeft; }
  7. set
  8. {
  9. _handLeft = value;
  10. OnPropertyChanged("HandLeft");
  11. }
  12.  
  13. }
  14.  
  15. private double _handTop;
  16. public double HandTop
  17. {
  18. get { return _handTop; }
  19. set
  20. {
  21. _handTop = value;
  22. OnPropertyChanged("HandTop");
  23. }
  24. }
  25.  
  26. private string _hypothesizedText;
  27. public string HypothesizedText
  28. {
  29. get { return _hypothesizedText; }
  30. set
  31. {
  32. _hypothesizedText = value;
  33. OnPropertyChanged("HypothesizedText");
  34. }
  35. }
  36.  
  37. private string _confidence;
  38. public string Confidence
  39. {
  40. get { return _confidence; }
  41. set
  42. {
  43. _confidence = value;
  44. OnPropertyChanged("Confidence");
  45. }
  46. }
  47.  
  48. public event PropertyChangedEventHandler PropertyChanged;
  49.  
  50. private void OnPropertyChanged(string propertyName)
  51. {
  52. if (PropertyChanged != null)
  53. {
  54. PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  55. }
  56.  
  57. }
  58. }

添加CreateAudioSource方法,在该方法中,将KinectAudioSource对象的AutoGainControlEnabled的属性设置为false。

  1. private KinectAudioSource CreateAudioSource()
  2. {
  3. var source = KinectSensor.KinectSensors[].AudioSource;
  4. source.AutomaticGainControlEnabled = false;
  5. source.EchoCancellationMode = EchoCancellationMode.None;
  6. return source;
  7. }

接下来实现骨骼追踪部分逻辑来获取右手的坐标,相信看完骨骼追踪那两篇文章后这部分的代码应该会比较熟悉。首先创建一个私有字段_kinectSensor来保存当前的KienctSensor对象,同时创建SpeechRecognitionEngine对象。在窗体的构造函数中,对这几个变量进行初始化。例外注册骨骼追踪系统的Skeleton事件并将主窗体的DataContext对象赋给自己。

  1. KinectSensor _kinectSensor;
  2. SpeechRecognitionEngine _sre;
  3. KinectAudioSource _source;
  4.  
  5. public MainWindow()
  6. {
  7. InitializeComponent();
  8. this.DataContext = this;
  9. this.Unloaded += delegate
  10. {
  11. _kinectSensor.SkeletonStream.Disable();
  12. _sre.RecognizeAsyncCancel();
  13. _sre.RecognizeAsyncStop();
  14. _sre.Dispose();
  15. };
  16. this.Loaded += delegate
  17. {
  18. _kinectSensor = KinectSensor.KinectSensors[];
  19. _kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters()
  20. {
  21. Correction = 0.5f,
  22. JitterRadius = 0.05f,
  23. MaxDeviationRadius = 0.04f,
  24. Smoothing = 0.5f
  25. });
  26. _kinectSensor.SkeletonFrameReady += nui_SkeletonFrameReady;
  27. _kinectSensor.Start();
  28. StartSpeechRecognition();
  29. };
  30. }

在上面的代码中,我们添加了一些TransformSmoothParameters参数来使得骨骼追踪更加平滑。nui_SkeletonFrameReady方法如下。方式使用骨骼追踪数据来获取我们感兴趣的右手的关节点位置。这部分代码和之前文章中的类似。大致流程是:遍历当前处在追踪状态下的骨骼信息。然后找到右手关节点的矢量信息,然后使用SkeletonToDepthImage来获取相对于屏幕尺寸的X,Y坐标信息。

  1. void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
  2. {
  3. using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
  4. {
  5. if (skeletonFrame == null)
  6. return;
  7.  
  8. var skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
  9. skeletonFrame.CopySkeletonDataTo(skeletons);
  10. foreach (Skeleton skeletonData in skeletons)
  11. {
  12. if (skeletonData.TrackingState == SkeletonTrackingState.Tracked)
  13. {
  14. Microsoft.Kinect.SkeletonPoint rightHandVec = skeletonData.Joints[JointType.HandRight].Position;
  15. var depthPoint = _kinectSensor.MapSkeletonPointToDepth(rightHandVec
  16. , DepthImageFormat.Resolution640x480Fps30);
  17. HandTop = depthPoint.Y * this.MainStage.ActualHeight / ;
  18. HandLeft = depthPoint.X * this.MainStage.ActualWidth / ;
  19. }
  20. }
  21. }
  22. }

接下来我们需要实现语音识别部分的逻辑。SpeechRecognitionEngine中的StartSpeechRecognition方法必须找到正确的语音识别库来进行语音识别。下面的代码展示了如何设置语音识别库预计如何将KinectAudioSource传递给语音识别引起。我们还添加了SpeechRecognized,SpeechHypothesized以及SpeechRejected事件对应的方法。SetInputToAudioStream中的参数和前篇文章中的含义一样,这里不多解释了。注意到SpeechRecognitionEngine和KinectAudioSource都是Disposable类型,因此在整个应用程序的周期内,我们要保证这两个对象都处于打开状态。

  1. private void StartSpeechRecognition()
  2. {
  3. _source = CreateAudioSource();
  4.  
  5. Func<RecognizerInfo, bool> matchingFunc = r =>
  6. {
  7. string value;
  8. r.AdditionalInfo.TryGetValue("Kinect", out value);
  9. return "True".Equals(value, StringComparison.InvariantCultureIgnoreCase)
  10. && "en-US".Equals(r.Culture.Name, StringComparison.InvariantCultureIgnoreCase);
  11. };
  12. RecognizerInfo ri = SpeechRecognitionEngine.InstalledRecognizers().Where(matchingFunc).FirstOrDefault();
  13.  
  14. _sre = new SpeechRecognitionEngine(ri.Id);
  15. CreateGrammars(ri);
  16. _sre.SpeechRecognized += sre_SpeechRecognized;
  17. _sre.SpeechHypothesized += sre_SpeechHypothesized;
  18. _sre.SpeechRecognitionRejected += sre_SpeechRecognitionRejected;
  19.  
  20. Stream s = _source.Start();
  21. _sre.SetInputToAudioStream(s,
  22. new SpeechAudioFormatInfo(
  23. EncodingFormat.Pcm, , , ,
  24. , , null));
  25. _sre.RecognizeAsync(RecognizeMode.Multiple);
  26. }

要完成程序逻辑部分,我们还需要处理语音识别时间以及语音逻辑部分,以使得引擎能够直到如何处理和执行我们的语音命令。SpeechHypothesized以及SpeechRejected事件代码如下,这两个事件的逻辑很简单,就是更新UI界面上的label。SpeechRecognized事件有点复杂,他负责处理传进去的语音指令,并对识别出的指令执行相应的操作。另外,该事件还负责创建一些GUI对象(实际就是命令模式),我们必须使用Dispatcher对象来发挥InterpretCommand到主UI线程中来。

  1. void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
  2. {
  3. HypothesizedText += " Rejected";
  4. Confidence = Math.Round(e.Result.Confidence, ).ToString();
  5. }
  6.  
  7. void sre_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
  8. {
  9. HypothesizedText = e.Result.Text;
  10. }
  11.  
  12. void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
  13. {
  14. Dispatcher.BeginInvoke(new Action<SpeechRecognizedEventArgs>(InterpretCommand), e);
  15. }

现在到了程序核心的地方。创建语法逻辑并对其进行解析。本例中的程序识别普通的以“put”或者“create”开头的命令。前面是什么我们不关心,紧接着应该是一个颜色,然后是一种形状,最后一个词应该是“there”。下面的代码显示了创建的语法。

  1. private void CreateGrammars(RecognizerInfo ri)
  2. {
  3. var colors = new Choices();
  4. colors.Add("cyan");
  5. colors.Add("yellow");
  6. colors.Add("magenta");
  7. colors.Add("blue");
  8. colors.Add("green");
  9. colors.Add("red");
  10.  
  11. var create = new Choices();
  12. create.Add("create");
  13. create.Add("put");
  14.  
  15. var shapes = new Choices();
  16. shapes.Add("circle");
  17. shapes.Add("triangle");
  18. shapes.Add("square");
  19. shapes.Add("diamond");
  20.  
  21. var gb = new GrammarBuilder();
  22. gb.Culture = ri.Culture;
  23. gb.Append(create);
  24. gb.AppendWildcard();
  25. gb.Append(colors);
  26. gb.Append(shapes);
  27. gb.Append("there");
  28.  
  29. var g = new Grammar(gb);
  30. _sre.LoadGrammar(g);
  31.  
  32. var q = new GrammarBuilder{ Culture = ri.Culture };
  33. q.Append("quit application");
  34. var quit = new Grammar(q);
  35.  
  36. _sre.LoadGrammar(quit);
  37. }

上面的代码中,我们首先创建一个Choices对象,这个对象会在命令解析中用到。在程序中我们需要颜色和形状对象。另外,第一个单词是“put”或者“create”,因此我们也创建Choices对象。然后使用GrammarBuilder类将这些对象组合到一起。首先是”put”或者“create”然后是一个占位符,因为我们不关心内容,然后是一个颜色Choices对象,然后是一个形状Choices对象,最后是一个“there”单词。

我们将这些语法规则加载进语音识别引擎。同时我们也需要有一个命令来停止语音识别引擎。因此我们创建了第二个语法对象,这个对象只有一个”Quit”命令。然后也将这个语法规则加载到引擎中。

一旦识别引擎确定了要识别的语法,真正的识别工作就开始了。被识别的句子必须被解译,出别出来想要的指令后,我们必须决定如何进行下一步处理。下面的代码展示了如何处理识别出的命令,以及如何根据特定的指令来讲图形元素绘制到UI界面上去。

  1. private void InterpretCommand(SpeechRecognizedEventArgs e)
  2. {
  3. var result = e.Result;
  4. Confidence = Math.Round(result.Confidence, ).ToString();
  5. if (result.Confidence < && result.Words[].Text == "quit" && result.Words[].Text == "application")
  6. {
  7. this.Close();
  8. }
  9. if (result.Words[].Text == "put" || result.Words[].Text == "create")
  10. {
  11. var colorString = result.Words[].Text;
  12. Color color;
  13. switch (colorString)
  14. {
  15. case "cyan": color = Colors.Cyan;
  16. break;
  17. case "yellow": color = Colors.Yellow;
  18. break;
  19. case "magenta": color = Colors.Magenta;
  20. break;
  21. case "blue": color = Colors.Blue;
  22. break;
  23. case "green": color = Colors.Green;
  24. break;
  25. case "red": color = Colors.Red;
  26. break;
  27. default:
  28. return;
  29. }
  30.  
  31. var shapeString = result.Words[].Text;
  32. Shape shape;
  33. switch (shapeString)
  34. {
  35. case "circle":
  36. shape = new Ellipse();
  37. shape.Width = ;
  38. shape.Height = ;
  39. break;
  40. case "square":
  41. shape = new Rectangle();
  42. shape.Width = ;
  43. shape.Height = ;
  44. break;
  45. case "triangle":
  46. var poly = new Polygon();
  47. poly.Points.Add(new Point(, ));
  48. poly.Points.Add(new Point(, ));
  49. poly.Points.Add(new Point(, -));
  50. shape = poly;
  51. break;
  52. case "diamond":
  53. var poly2 = new Polygon();
  54. poly2.Points.Add(new Point(, ));
  55. poly2.Points.Add(new Point(, ));
  56. poly2.Points.Add(new Point(, ));
  57. poly2.Points.Add(new Point(, -));
  58. shape = poly2;
  59. break;
  60. default:
  61. return;
  62. }
  63. shape.SetValue(Canvas.LeftProperty, HandLeft);
  64. shape.SetValue(Canvas.TopProperty, HandTop);
  65. shape.Fill = new SolidColorBrush(color);
  66. MainStage.Children.Add(shape);
  67. }
  68. }

方法中,我们首先检查语句识别出的单词是否是”Quit”如果是的,紧接着判断第二个单词是不是”application”如果两个条件都满足了,就不进行绘制图形,直接返回。如果有一个条件不满足,就继续执行下一步。

InterpretCommand方法然后判断第一个单词是否是“create”或者“put”,如果不是这两个单词开头就什么也不执行。如果是的,就判断第三个单词,并根据识别出来的颜色创建对象。如果第三个单词没有正确识别,应用程序也停止处理。否则,程序判断第四个单词,根据接收到的命令创建对应的形状。到这一步,基本的逻辑已经完成,最后第五个单词用来确定整个命令是否正确。命令处理完了之后,将当前受的X,Y坐标赋给创建好的对象的位置。



  1. namespace KinectPutThatThere
  2. {
  3. /// <summary>
  4. /// Interaction logic for MainWindow.xaml
  5. /// </summary>
  6. public partial class MainWindow : Window, INotifyPropertyChanged
  7. {
  8. KinectSensor _kinectSensor;
  9. SpeechRecognitionEngine _sre;
  10. KinectAudioSource _source;
  11.  
  12. public MainWindow()
  13. {
  14. InitializeComponent();
  15. this.DataContext = this;
  16. this.Unloaded += delegate
  17. {
  18. _kinectSensor.SkeletonStream.Disable();
  19. _sre.RecognizeAsyncCancel();
  20. _sre.RecognizeAsyncStop();
  21. //_source.Dispose();
  22. _sre.Dispose();
  23. };
  24. this.Loaded += delegate
  25. {
  26. _kinectSensor = KinectSensor.KinectSensors[];
  27. _kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters() // 对骨骼数据进行平滑处理
  28. {
  29. // This struct is used to setup the skeleton smoothing values
  30. Correction = 0.5f,
  31. JitterRadius = 0.05f,
  32. MaxDeviationRadius = 0.04f,
  33. Smoothing = 0.5f
  34. });
  35. _kinectSensor.SkeletonFrameReady += nui_SkeletonFrameReady;
  36. _kinectSensor.Start();
  37. StartSpeechRecognition();
  38. };
  39. }
  40.  
  41. #region 骨骼数据处理
  42.  
  43. void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
  44. {
  45. using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
  46. {
  47. if (skeletonFrame == null)
  48. return;
  49.  
  50. var skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength]; // 不定类型 —— Skeleton
  51. skeletonFrame.CopySkeletonDataTo(skeletons);
  52. foreach (Skeleton skeletonData in skeletons)
  53. {
  54. if (skeletonData.TrackingState == SkeletonTrackingState.Tracked)
  55. {
  56. Microsoft.Kinect.SkeletonPoint rightHandVec = skeletonData.Joints[JointType.HandRight].Position;
  57. var depthPoint = _kinectSensor.MapSkeletonPointToDepth(rightHandVec
  58. , DepthImageFormat.Resolution640x480Fps30);
  59. HandTop = depthPoint.Y * this.MainStage.ActualHeight / ;
  60. HandLeft = depthPoint.X * this.MainStage.ActualWidth / ;
  61. }
  62. }
  63. }
  64. }
  65. #endregion
  66.  
  67. private KinectAudioSource CreateAudioSource()
  68. {
  69. var source = KinectSensor.KinectSensors[].AudioSource;
  70. source.AutomaticGainControlEnabled = false;
  71. source.EchoCancellationMode = EchoCancellationMode.None;
  72. return source;
  73. }
  74.  
  75. private void StartSpeechRecognition()
  76. {
  77. _source = CreateAudioSource();
  78.  
  79. Func<RecognizerInfo, bool> matchingFunc = r =>
  80. {
  81. string value;
  82. r.AdditionalInfo.TryGetValue("Kinect", out value);
  83. return "True".Equals(value, StringComparison.InvariantCultureIgnoreCase)
  84. && "en-US".Equals(r.Culture.Name, StringComparison.InvariantCultureIgnoreCase);
  85. };
  86. // 识别库
  87.  
  88. RecognizerInfo ri = SpeechRecognitionEngine.InstalledRecognizers().Where(matchingFunc).FirstOrDefault();
  89.  
  90. _sre = new SpeechRecognitionEngine(ri.Id); // 需要设置识别引擎的ID编号
  91. CreateGrammars(ri);
  92. _sre.SpeechRecognized += sre_SpeechRecognized;
  93. _sre.SpeechHypothesized += sre_SpeechHypothesized;
  94. _sre.SpeechRecognitionRejected += sre_SpeechRecognitionRejected;
  95.  
  96. Stream s = _source.Start();
  97. _sre.SetInputToAudioStream(s,
  98. new SpeechAudioFormatInfo(
  99. EncodingFormat.Pcm, , , ,
  100. , , null));
  101. _sre.RecognizeAsync(RecognizeMode.Multiple);
  102. }
  103.  
  104. private void CreateGrammars(RecognizerInfo ri)
  105. {
  106. // 创建语法
  107.  
  108. var colors = new Choices(); // 通配符 —— 择类(Choices)是通配符类(Wildcard)的一种,它可以包含多个值。但与通配符不同的是,我们可以指定可接受的值的顺序。
  109. colors.Add("cyan");
  110. colors.Add("yellow");
  111. colors.Add("magenta");
  112. colors.Add("blue");
  113. colors.Add("green");
  114. colors.Add("red");
  115.  
  116. var create = new Choices();
  117. create.Add("create");
  118. create.Add("put");
  119.  
  120. var shapes = new Choices();
  121. shapes.Add("circle");
  122. shapes.Add("triangle");
  123. shapes.Add("square");
  124. shapes.Add("diamond");
  125.  
  126. var gb = new GrammarBuilder();
  127. gb.Culture = ri.Culture;
  128. gb.Append(create);
  129. gb.AppendWildcard();
  130. gb.Append(colors);
  131. gb.Append(shapes);
  132. gb.Append("there");
  133.  
  134. var g = new Grammar(gb);
  135. _sre.LoadGrammar(g);
  136.  
  137. var q = new GrammarBuilder { Culture = ri.Culture };
  138. q.Append("quit application");
  139. var quit = new Grammar(q);
  140.  
  141. _sre.LoadGrammar(quit);
  142. }
  143.  
  144. #region 语音事件处理
  145.  
  146. void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
  147. {
  148. HypothesizedText += " Rejected";
  149. Confidence = Math.Round(e.Result.Confidence, ).ToString();
  150. }
  151.  
  152. void sre_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
  153. {
  154. HypothesizedText = e.Result.Text;
  155. }
  156.  
  157. void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
  158. {
  159. Dispatcher.BeginInvoke(new Action<SpeechRecognizedEventArgs>(InterpretCommand), e);
  160. }
  161.  
  162. #endregion
  163. private void InterpretCommand(SpeechRecognizedEventArgs e)
  164. {
  165. var result = e.Result;
  166. Confidence = Math.Round(result.Confidence, ).ToString();
  167. if (result.Confidence < && result.Words[].Text == "quit" && result.Words[].Text == "application")
  168. {
  169. this.Close();
  170. }
  171. if (result.Words[].Text == "put" || result.Words[].Text == "create")
  172. {
  173. var colorString = result.Words[].Text;
  174. Color color;
  175. switch (colorString)
  176. {
  177. case "cyan": color = Colors.Cyan;
  178. break;
  179. case "yellow": color = Colors.Yellow;
  180. break;
  181. case "magenta": color = Colors.Magenta;
  182. break;
  183. case "blue": color = Colors.Blue;
  184. break;
  185. case "green": color = Colors.Green;
  186. break;
  187. case "red": color = Colors.Red;
  188. break;
  189. default:
  190. return;
  191. }
  192.  
  193. var shapeString = result.Words[].Text;
  194. Shape shape;
  195. switch (shapeString)
  196. {
  197. case "circle":
  198. shape = new Ellipse();
  199. shape.Width = ;
  200. shape.Height = ;
  201. break;
  202. case "square":
  203. shape = new Rectangle();
  204. shape.Width = ;
  205. shape.Height = ;
  206. break;
  207. case "triangle":
  208. var poly = new Polygon();
  209. poly.Points.Add(new Point(, ));
  210. poly.Points.Add(new Point(, ));
  211. poly.Points.Add(new Point(, -));
  212. shape = poly;
  213. break;
  214. case "diamond":
  215. var poly2 = new Polygon();
  216. poly2.Points.Add(new Point(, ));
  217. poly2.Points.Add(new Point(, ));
  218. poly2.Points.Add(new Point(, ));
  219. poly2.Points.Add(new Point(, -));
  220. shape = poly2;
  221. break;
  222. default:
  223. return;
  224. }
  225. shape.SetValue(Canvas.LeftProperty, HandLeft);
  226. shape.SetValue(Canvas.TopProperty, HandTop);
  227. shape.Fill = new SolidColorBrush(color);
  228. MainStage.Children.Add(shape);
  229. }
  230. }
  231.  
  232. #region 前台控件的绑定
  233.  
  234. private double _handLeft;
  235. public double HandLeft
  236. {
  237. get { return _handLeft; }
  238. set
  239. {
  240. _handLeft = value;
  241. OnPropertyChanged("HandLeft");
  242. }
  243.  
  244. }
  245.  
  246. private double _handTop;
  247. public double HandTop
  248. {
  249. get { return _handTop; }
  250. set
  251. {
  252. _handTop = value;
  253. OnPropertyChanged("HandTop"); // 驱动控件
  254. }
  255. }
  256.  
  257. private string _hypothesizedText;
  258. public string HypothesizedText
  259. {
  260. get { return _hypothesizedText; }
  261. set
  262. {
  263. _hypothesizedText = value;
  264. OnPropertyChanged("HypothesizedText");
  265. }
  266. }
  267.  
  268. private string _confidence;
  269. public string Confidence
  270. {
  271. get { return _confidence; }
  272. set
  273. {
  274. _confidence = value;
  275. OnPropertyChanged("Confidence");
  276. }
  277. }
  278.  
  279. public event PropertyChangedEventHandler PropertyChanged;
  280.  
  281. private void OnPropertyChanged(string propertyName)
  282. {
  283. if (PropertyChanged != null)
  284. {
  285. PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  286. }
  287.  
  288. }
  289.  
  290. #endregion
  291. }
  292. }

Kinect 开发 —— 语音识别(下)的更多相关文章

  1. Kinect 开发 —— 语音识别(上)

    Kinect的麦克风阵列在Kinect设备的下方.这一阵列由4个独立的水平分布在Kinect下方的麦克风组成.虽然每一个麦克风都捕获相同的音频信号,但是组成阵列可以探测到声音的来源方向.使得能够用来识 ...

  2. Kinect开发文章目录

    整理了一下去年为止到现在写的和翻译的Kinect的相关文章,方便大家查看.另外,最近京东上微软在搞活动, 微软 Kinect for Windows 京东十周年专供礼包 ,如果您想从事Kinect开发 ...

  3. Kinect开发学习笔记之(一)Kinect介绍和应用

    Kinect开发学习笔记之(一)Kinect介绍和应用 zouxy09@qq.com http://blog.csdn.net/zouxy09 一.Kinect简单介绍 Kinectfor Xbox ...

  4. Kinect开发笔记之三Kinect开发环境配置具体解释

            0.前言:        首先说一下我的开发环境,Visual Studio是2013的,系统是win8的64位版本号,SDK是Kinect for windows SDK 1.8版本 ...

  5. 利用微软Speech SDK 5.1开发语音识别系统主要步骤

    利用微软Speech SDK 5.1开发语音识别系统主要步骤 2009-09-17 10:21:09|  分类: 知识点滴|字号 订阅 微软语音识别分两种模式:文本识别模式和命令识别模式.此两种模式的 ...

  6. Kinect开发笔记之二Kinect for Windows 2.0新功能

    这是本博客翻译文档的第一篇文章.笔者已经苦逼的竭尽全力的在翻译了.但无奈英语水平也是非常有限.不正确或者不妥当不准确的地方必定会有,还恳请大家留言或者邮件我以批评指正.我会虚心接受. 谢谢大家.   ...

  7. Kinect 开发 —— 杂一

    Kinect 提供了非托管(C++)和托管(.NET)两种开发方式的SDK,如果您用C++开发的话,需要安装Speech Runtime(V11),Kinect for Windows Runtime ...

  8. Kinect 开发 —— 控制PPT播放

    实现Kinect控制幻灯片播放很简单,主要思路是:使用Kinect捕捉人体动作,然后根据识别出来的动作向系统发出点击向前,向后按键的事件,从而使得幻灯片能够切换. 这里的核心功能在于手势的识别,我们在 ...

  9. Kinect 开发 —— 全息图

    Kinect的另一个有趣的应用是伪全息图(pseudo-hologram).3D图像可以根据人物在Kinect前面的各种位置进行倾斜和移动.如果方法够好,可以营造出3D控件中3D图像的效果,这样可以用 ...

随机推荐

  1. Linux下通过rdesktop连接Windows远程桌面

    rdesktop是linux下支持Windows远程桌面连接的客户端程序,在linux系统下可通过它远程访问Windows桌面,支持多种版本.rdesktop是sourceforge下支持GPL协议的 ...

  2. SSD-tensorflow-2 制作自己的数据集

    VOC2007数据集格式: VOC2007详细介绍在这里,提供给大家有兴趣作了解.而制作自己的数据集只需用到前三个文件夹,所以请事先建好这三个文件夹放入同一文件夹内,同时ImageSets文件夹内包含 ...

  3. SICP 习题 (2.11)解题总结:区间乘法的优化

    SICP 习题 2.11又出现Ben这个人了,如曾经说到的,仅仅要是Ben说的一般都是对的. 来看看Ben说什么.他说:"通过监測区间的端点,有可能将mul-interval分解为9中情况, ...

  4. crm使用soap删除字段

    //C# 代码: //DeleteAttributeRequest request = new DeleteAttributeRequest(); //request.EntityLogicalNam ...

  5. UVa 11085 - Back to the 8-Queens

    题目:给你一个棋盘上的八个皇后.每行一个.如今让他们互相不攻击,每一个皇后仅仅能竖着移动, 一次能够移动到本列的不论什么位置,问最少移动几步.能满足要求. 分析:搜索,八皇后.由于八皇后仅仅有92组解 ...

  6. FZOJ 2176 easy problem ( 树链剖分 )

    pid=2176" target="_blank">题目链接~~> 做题感悟:感觉做多了树链剖分的题目,有很多是树链剖分 + 想法.. 解题思路: 这题非常明 ...

  7. atitit.js&#160;与c#&#160;java交互html5化的原理与总结.doc

    atitit.js 与c# java交互html5化的原理与总结.doc 1. 实现html5化界面的要解决的策略 1 1.1. Js交互 1 1.2. 动态參数个数 1 1.3. 事件监听 2 2. ...

  8. shrio 加密/编码

    在涉及到密码存储问题上,应该加密/生成密码摘要存储,而不是存储明文密码.比如之前的600w csdn账号泄露对用户可能造成很大损失,因此应加密/生成不可逆的摘要方式存储. 5.1 编码/解码 Shir ...

  9. 1.cocos_helloworld

    在class HelloWorld : public cocos2d::Layer中添加函数 void menuclose(cocos2d::Ref *psender); 实现: void Hello ...

  10. Sqoop Import原理和详细流程讲解

    Sqoop Import原理 Sqoop Import详细流程讲解 Sqoop在import时,需要指定split-by参数.Sqoop根据不同的split-by参数值来进行切分,然后将切分出来的区域 ...