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

时间:2013-03-07 21:30:39

标签: c# multithreading event-handling kinect-sdk

我正在编写一个应用程序,它可以采用几种不同的外部输入(键盘按下,动作手势,语音)并产生类似的输出(例如,按下键盘上的“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()?

1 个答案:

答案 0 :(得分: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.

我也希望当你说你正在使用&#34;版本1&#34; SDK的意思是&#34;版本1.6&#34;。如果您使用的是1.5或1.6以外的任何东西,那么由于1.5中的许多变化,您只会伤害自己。