Kinect 语音识别和骨骼跟踪不能一起工作

Posted

技术标签:

【中文标题】Kinect 语音识别和骨骼跟踪不能一起工作【英文标题】:Kinect speech recognition and skeleton tracking don't work together 【发布时间】:2013-03-07 21:30:39 【问题描述】:

我正在编写一个应用程序,它可以接受多种不同的外部输入(键盘按下、动作手势、语音)并产生类似的输出(例如,在键盘上按“T”将与说出单词“旅行”大声说出来)。因此,我不希望任何输入管理器相互了解。具体来说,我不希望 Kinect 管理器(尽可能多地)了解语音管理器,反之亦然,即使我使用的是 Kinect 的内置麦克风(语音管理器应该与任何麦克风一起使用)。我在语音管理器中使用 System.Speech,而不是 Microsoft.Speech。

我遇到了一个问题,即一旦启用 Kinect 动作识别模块,语音模块就会停止接收输入。我已经尝试了很多东西,比如inverting the skeleton stream and audio stream,以不同的方式捕获音频流等等。我终于缩小了问题的范围:关于我如何初始化我的模块的一些事情与我的应用程序处理的方式不符事件。

在动作捕捉开始之前,该应用程序运行良好。如果我完全排除 Kinect 模块,这就是我的主要方法的外观:

    // Main.cs
    public static void Main()
    

        // Create input managers
        KeyboardMouseManager keymanager = new KeyboardMouseManager();
        SpeechManager speechmanager = new SpeechManager();

        // Start listening for keyboard input
        keymanager.start();    

        // Start listening for speech input
        speechmanager.start()

        try
        
           Application.Run();  
        
        catch (Exception ex)
        
            MessageBox.Show(ex.StackTrace);
        

    

我正在使用Application.Run(),因为我的 GUI 由外部程序处理。此 C# 应用程序的唯一工作是接收输入事件并根据该输入运行外部脚本。

键盘和语音模块都偶尔接收事件。另一方面,Kinect 会不断产生事件。如果我的手势很少发生,那么轮询循环可能是每次轮询之间等待时间的答案。但是,我正在使用 Kinect 来控制鼠标移动……我不能在骨架事件捕获之间等待,因为那样鼠标会很迟钝;我的骨架捕获循环需要尽可能保持不变。这提出了一个大问题,因为现在我不能让我的 Kinect 管理器在同一个线程上(或消息泵?我对差异有点模糊,因此我认为问题出在此处):根据我的理解它,在同一个线程上不允许键盘或语音事件始终如一地通过。相反,我想出了一个解决方案,让我的 Kinect 管理器从System.Windows.Forms 继承,以便它可以与Application.Run() 一起使用。 现在,我的主要方法如下所示:

    // Main.cs
    public static void Main()
    

        // Create input managers
        KeyboardMouseManager keymanager = new KeyboardMouseManager();
        KinectManager kinectManager = new KinectManager();
        SpeechManager speechmanager = new SpeechManager();

        // Start listening for keyboard input
        keymanager.start();

        // Attempt to launch the kinect sensor
        bool kinectLoaded = kinectManager.start();


        // Use the default microphone (if applicable) if kinect isn't hooked up
        // Use the kinect microphone array if the kinect is working
        if (kinectLoaded)
        
           speechmanager.start(kinectManager);
        
        else
        
           speechmanager.start();
        


        try
        
           // THIS IS THE PLACE I THINK I'M DOING SOMETHING WRONG
           Application.Run(kinectManager);  
        
        catch (Exception ex)
        
            MessageBox.Show(ex.StackTrace);
        

由于某种原因,一旦 Kinect 传感器启动,Kinect 麦克风就会失去其“默认值”(如果此观察结果不正确,或者有解决方法,请告诉我)。因此,我需要在语音管理器中创建一个特殊的 start() 方法,如下所示:

    // SpeechManager.cs

    /** For use with the Kinect Microphone **/
    public void start(KinectManager kinect)
    
        // Get the speech recognizer information
        RecognizerInfo recogInfo = SpeechRecognitionEngine.InstalledRecognizers().FirstOrDefault();

        if (null == recogInfo)
        
            Console.WriteLine("Error: No recognizer information found on Kinect");
            return;
        

        SpeechRecognitionEngine recognizer = new SpeechRecognitionEngine(recogInfo.Id);

        // Loads all of the grammars into the recognizer engine
        loadSpeechBindings(recognizer);

        // Set speech event handler
        recognizer.SpeechRecognized += speechRecognized;

        using (var s = kinect.getAudiosource().Start() )
        
            // Set the input to the Kinect audio stream
            recognizer.SetInputToAudioStream(s, new SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null));

            // Recognize asycronous speech events
            recognizer.RecognizeAsync(RecognizeMode.Multiple);
        
    

作为参考,Kinect 管理器中的start() 方法如下所示:

    // KinectManager.cs
    public bool start()
    
        // Code from Microsoft Sample
        kinect = (from sensorToCheck in KinectSensor.KinectSensors where sensorToCheck.Status == KinectStatus.Connected select sensorToCheck).FirstOrDefault();

        // Fail elegantly if no kinect is detected
        if (kinect == null)
        
            connected = false;
            Console.WriteLine("Couldn't find a Kinect");
            return false;
        

        // Start listening
        kinect.Start();

        // Enable listening for all skeletons
        kinect.SkeletonStream.Enable();

        // Obtain the KinectAudioSource to do audio capture
        source = kinect.AudioSource;
        source.EchoCancellationMode = EchoCancellationMode.None; // No AEC for this sample
        source.AutomaticGainControlEnabled = false; // Important to turn this off for speech recognition

        kinect.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(allFramesReady);

        connected = true;
        return true;
    

所以当我禁用动作捕捉时(通过让我的 main() 看起来类似于第一个代码段),语音识别工作正常。当我启用动作捕捉时,动作效果很好,但没有语音被识别。在这两种情况下,键盘事件总是有效的。没有错误,通过跟踪我发现语音管理器中的所有数据都已正确初始化......它似乎就像语音识别事件消失了一样。如何重新组织此代码以便输入模块可以独立工作?我是否使用线程,或者只是 Application.Run() 以不同的方式?

【问题讨论】:

您使用的是哪个 SDK 和哪个 Kinect:XBox 还是 Windows?另外,您使用的是哪个版本的 Speech API? 我使用的是 SDK 版本 1,我在 Windows 上使用的是 kinect。我正在使用 System.Speech 版本 4 【参考方案1】:

Microsoft Kinect SDK 有几个known issues,其中之一是如果您在启动音频处理器后开始跟踪骨架,则不会处理音频。从已知问题:

Audio is not processed if skeleton stream is enabled after starting audio capture

Due to a bug, enabling or disabling the SkeletonStream will stop the AudioSource
stream returned by the Kinect sensor. The following sequence of instructions will
stop the audio stream:
    kinectSensor.Start();
    kinectSensor.AudioSource.Start(); // --> this will create an audio stream
    kinectSensor.SkeletonStream.Enable(); // --> this will stop the audio stream as an undesired side effect

The workaround is to invert the order of the calls or to restart the AudioSource after changing SkeletonStream status.
    Workaround #1 (start audio after skeleton):
    kinectSensor.Start();
    kinectSensor.SkeletonStream.Enable();
    kinectSensor.AudioSource.Start();

    Workaround #2 (restart audio after skeleton):
    kinectSensor.Start();
    kinectSensor.AudioSource.Start(); // --> this will create an audio stream
    kinectSensor.SkeletonStream.Enable(); // --> this will stop the audio stream as an undesired side effect
    kinectSensor.AudioSource.Start(); // --> this will create another audio stream

Resetting the SkeletonStream engine status is an expensive call. It should be made at application startup only, unless the app has specific needs that require turning Skeleton on and off.

我还希望当您说您使用 SDK 的“版本 1”时,您的意思是“版本 1.6”。如果您使用的是 1.5 或 1.6 以外的任何版本,那么您只会因为 1.5 中所做的许多更改而伤害自己。

【讨论】:

感谢您的回答!不过,我确实在问题的开头提到过,我已经尝试过了,但它并没有真正改变任何东西。在深入了解我的 SDK 版本之后,我认为你是对的,我有一个过时的版本。让我尝试更新它,看看会发生什么 抱歉,错过了音频/骨架初始化顺序的提及......这是一篇很长的帖子。 :)

以上是关于Kinect 语音识别和骨骼跟踪不能一起工作的主要内容,如果未能解决你的问题,请参考以下文章

在语音识别中使用 Kinect Skeleton ID

系统语音识别、MS语音平台和Kinect

为 Surface 表开发 Kinect 语音识别应用程序

如何解释语音识别的技术原理?

一段讯飞百度等语音识别API无法识别的语音最终解决办法

如何使用 kinect 根据跟踪的身体运动移动骨骼