语音识别Kinect

Kinect 的麦克风阵列在 Kinect 设备的下方。 这一阵列由 4 个独立的水平分布在 Kinect 下方的麦
克风组成。虽然每一个麦克风都捕获相同的音频信号,但是组成阵列可以探测到声音的来源方向。使
得能够用来识别从某一个特定的方向传来的声音。 麦克风阵列捕获的音频数据流经过复杂的音频增强
效果算法处理来移除不相关的背景噪音。 所有这些复杂操作在 Kinect 硬件和 Kinect SDK 之间进行处
理,这使得能够在一个大的空间范围内,即使人离麦克风一定的距离也能够进行语音命令的识别。
在 Kinect 第一次作为 Xbox360 的外设发布时,骨骼追踪和语音识别是 Kinect SDK 最受开发者
欢迎的特性,但是相比骨骼追踪,语音识别中麦克风阵列的强大功能有一点被忽视了。一部分原因归
于 Kinect 中的令人兴奋的骨骼追踪系统,另一部分原因在于 Xbox 游戏操控面板以及 Kinect 体感游
戏没有充分发挥 Kinect 音频处理的优点。
作为一个开始使用 Kinect 进行应用开发的开发者,Kinect 上的麦克风阵列的出现使得基于 Kinect
应用程序的功能更加强大。虽然 Kinect 的视觉分析令人印象深刻,但是仍然不能很好的对马达进行
控制。当我们从一种人机交互界面切换到另一种人机交互界面:如从命令行交互应用程序到标签页交
互界面,再到鼠标图形用户界面或者触摸交互界面时,每一种交互界面都提供了各种最基本的更加容
易实现的操作,这个操作就是选择。进一步,可以说,每一种交互界面都改进了我们对对象进行选择
的能力。奇怪的是,Kinect 破坏了这一趋势。
这些问题,可以通过将语音识别指令和骨骼追踪系统结合起来产生一个复合的姿势来相对简单
的解决:保持某一动作,然后通过语音执行。菜单的设计也可以通过首先展示菜单项,然后让用户说
出菜单项的名称来进行选择-很多 Xbox 中的游戏已经使用了这种方式。可以预见,无论是程序开发
者还是游戏公司,这种复合的解决方案在未来会越来越多的应用到新的交互方式中,而不用再像以前
那样使用指然后点(point and click)这种方式来选择。
麦克风阵列
安装完 Microsoft Kinect SDK 之后,语音识别的组件会自动安装。Kinect 的麦克风阵列工作在
一些语音识别的类库之上,这些类库是从 Vista 系统之时就有的。他们包括语音捕获 DirectX 多媒体
对象(DirectX Media Object,DMO)以及语音识别 API(Speech Recognition API,SAPI)。
在 C#中,Kinect SDK 提供了对语音捕获 DMO 的封装。语音捕获 DMO 最初是被设计用来给麦
克风阵列提供 API 来支持一些功能如回声消除(acoustic echo cancellation,AEC),自动增益控制
(automatic gain control,AGC)和噪声抑制(noise suppression)。这些功能在 SDK 的音频控制类中
可以找到。 Kinect SDK 中音频处理对语音捕获 DMO 进行了简单封装,并专门针对 Kinect 传感器
进行了性能优化。为了能够使用 Kinect SDK 进行语音识别,自动安装的类库包括:Speech Platform
API, Speech Platform SDK 和 Kinect for Windows Runtime Language Pack。
语音识别 API 能够简化操作系统自带的语音识别所需的类库。例如,如果你想通过普通的麦克风
而不是 Kinect 麦克风阵列添加一些语音指令到桌面应用程序中去,可以使用也可以不使用 Kinect
SDK。
Kinect for windows 运行语言包是一系列的语言模型,用来在 Kinect SDK 和语音识别 API 组件
之间进行互操作。 就像Kinect骨骼识别需要大量的计算模型来提供决策树信息来分析节点位置那样,
语音识别 API 也需要复杂的模型来辅助解释从 Kinect 麦克风阵列接收到的语言模型。Kinect 语言包
提供了这些模型来优化语音指令的识别。
MSR Kinect Audio
Kinect 中处理音频主要是通过 KinectAudioSource 这个对象来完成的。KinectAudioSource 类
的主要作用是从麦克风阵列中提取原始的或者经过处理的音频流。 音频流可能会经过一系列的算法来
处理以提高音频质量,这些处理包括:降噪、自动增益控制和回声消除。KinectAudioSource 能够进
行一些配置使得 Kinect 麦克风阵列可以以不同的模式进行工作。也能够用来探测从那个方向来的哪
种音频信息最先达到麦克风以及用来强制麦克风阵列接受指定方向的音频信息。
本节尽量不会去介绍一些音频处理技术方面的较低层次的技术。但是为了使用
KinectAudioSource,了解语音捕获以及语音传输中的一些术语可能会对熟悉KinectAudioSource中
的一些属性和方法有所帮助。
  回声消除(acoustic echo cancellation, AEC) 当用户的声音从麦克风返回时,就会产生回声。
最简单的例子就是用户在打电话时能够听到自己的声音,这些声音有一些延迟,会在对方那
里重复一段时间。回声消除通过提取发声者的声音模式,然后根据这一模式从麦克风接收到
的音频中挑选出特定的音频来消除回声。
  回声抑制(acoustic echo suppression, AES) 它是指通过一系列的算法来进一步消除 AEC
处理后所遗留的回声。
  自动增益控制(acoustic gain control, AGS) 它涉及到一些算法用来使用户的声音的振幅与
时间保持一致。例如当用户靠近或者或远离麦克风时,声音会出现变得响亮或更柔和,AGC
通过算法使得这一过程变得更加明显。
  波束成形(beamforming) 指的是模拟定向麦克风的算法技术。和只有一个麦克风不同,波
速成形技术用于麦克风阵列中 (如 Kinect 传感器上的麦克风阵列)使得麦克风阵列产生和
使用多个固定麦克风的效果相同。
  中心削波(center clipping) 用来移除在单向传输中经 AEC 处理后残留的小的回声。
  帧尺寸(Frame Size) AEC 算法处理 PCM 音频样本是是一帧一帧处理的。帧尺寸是样本中音
频帧的大小。
  获取增益边界(Gain Bounding) 该技术确保麦克风有正确的增益级别。如果增益过高,获取
到的信号可能过于饱和,会被剪切掉。这种剪切有非线性的效果,会使得 AEC 算法失败。如
果增益过低,信噪比会比较低,也会使得 AEC 算法失败或者执行的不好。
  噪声填充(Noise Filling) 向中心削波移除了残留的回波信号后的部分信号中添加少量的噪
音。和留下空白的沉默信号相比,这能够获得更好的用户体验。
  噪声抑制 (NS) 用于从麦克风接收到的音频信号中剔除非言语声音。通过删除背景噪音,实
际讲话者的声音能够被麦克风更清楚更明确的捕获到。
  Optibeam Kinect 传感器从四个麦克风中能够获得 11 个波束。 这 11 个波束是逻辑结构,
而四个通道是物理结构。Optibeam 是一种系统模式用来进行波束成形。
  信噪比(Signal-to-Noise Ratio,SNR) 信号噪声比用来度量语音信号和总体背景噪声的比例,
信噪比越高越好。
  单通道(Single Channel) Kinect 传感器有四个麦克风,因此支持 4 个通道,单通道是一种系
统模式用来关闭波束成形。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using Microsoft.Kinect; using Microsoft.Speech.AudioFormat; using Microsoft.Speech.Recognition; namespace KinectSpeech { class Program { static void Main(string[] args) { KinectSensor KinectSensor = (from k in KinectSensor.KinectSensors where k.Status == KinectStatus.Connected select k).FirstOrDefault(); if (KinectSensor == null) { Console.WriteLine("No Kinect Connected\n" + "Press any key to continue.\n"); Console.ReadKey(true); return; } KinectSensor.Start(); KinectAudioSource audioSource = KinectSensor.AudioSource; audioSource.EchoCancellationMode = EchoCancellationMode.None; audioSource.AutomaticGainControlEnabled = false; RecognizerInfo recognizerInfo = GetKinectRecognizer(); using (var speechRecognitionEngine = new SpeechRecognitionEngine(recognizerInfo.Id)) { var colors = new Choices(); colors.Add("help"); colors.Add("green"); colors.Add("blue"); var grammatBuilder = new GrammarBuilder { Culture = recognizerInfo.Culture }; grammatBuilder.Append(colors); var g = new Grammar(grammatBuilder); speechRecognitionEngine.LoadGrammar(g); speechRecognitionEngine.SpeechRecognized += SreSpeechRecognized; speechRecognitionEngine.SpeechHypothesized += SreSpeechHypothesized; speechRecognitionEngine.SpeechRecognitionRejected += SreSpeechRecognitionRejected; using (Stream s = audioSource.Start()) { speechRecognitionEngine.SetInputToAudioStream( s, new SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null)); Console.WriteLine( "Recognizing speech. Say: 'help', 'green' or 'blue'. Press ENTER to stop"); speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple); Console.ReadLine(); Console.WriteLine("Stopping recognizer ..."); speechRecognitionEngine.RecognizeAsyncStop(); } } } private static RecognizerInfo GetKinectRecognizer() { Func<RecognizerInfo, bool> matchingFunc = r => { string value; r.AdditionalInfo.TryGetValue("Kinect", out value); return "True".Equals(value, StringComparison.InvariantCultureIgnoreCase) && "en-US".Equals(r.Culture.Name, StringComparison.InvariantCultureIgnoreCase); }; return SpeechRecognitionEngine.InstalledRecognizers().Where(matchingFunc). FirstOrDefault(); } private static void SreSpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e) { Console.WriteLine("\nSpeech Rejected"); if (e.Result != null) { DumpRecordedAudio(e.Result.Audio); } } private static void SreSpeechHypothesized(object sender, SpeechHypothesizedEventArgs e) { Console.Write("\rSpeech Hypothesized: \t{0}", e.Result.Text); } private static void SreSpeechRecognized(object sender, SpeechRecognizedEventArgs e) { if (e.Result.Confidence >= 0.7) { Console.WriteLine("\nSpeech Recognized: \t{0}\tConfidence:\t{1}", e.Result.Text, e.Result.Confidence); } else { Console.WriteLine("\nSpeech Recognized but confidence was too low: \t{0}", e.Result.Confidence); DumpRecordedAudio(e.Result.Audio); } } private static void DumpRecordedAudio(RecognizedAudio audio) { if (audio == null) return; int fileId = 0; string filename; while (File.Exists((filename = "RetainedAudio_" + fileId + ".wav"))) fileId++; Console.WriteLine("\nWriting file: {0}", filename); using (var file = new FileStream(filename, System.IO.FileMode.CreateNew)) audio.WriteToWaveStream(file); } } }
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页