Blog

Kinect SDK 1.0 – 5 – Reconnaissance vocale

Posté le
 1. Introduction Ă  l’API
 2. Utilisation du ColorImageStream
 3. Tracker le squelette avec le SkeletonStream
 4. Kinect en profondeur avec le DepthStream
 5. Reconnaissance vocale

 

Voici le dernier article de cette série consacrée au Kinect SDK 1.0. Dans les précédents articles on a vu comment afficher une vidéo avec le ColorImageStream, comment tracker les utilisateurs avec le SkeletonStream, comment faire une vidéo 3D avec le DepthImageStream.

Pour terminer et ajouter un petit plus Ă  vos applications en termes de Natural User Interface, on va voir comment utiliser la reconnaissance vocale!

Pensez expérience utilisateur

Quand vous dĂ©veloppez une application utilisant la Kinect, essayez de vous mettre Ă  la place des utilisateurs. Quelle est l’utilisation que vous en faites? Est-ce que les utilisateurs devront prendre des postures spĂ©cifiques? Ou bien rĂ©aliser un certain mouvement pour dĂ©clencher une action? Est-ce que cette tĂąche sera rĂ©pĂ©titive?

Rappelez-vous que les gestures (mouvements) sont difficiles Ă  dĂ©tecter avec certitude dĂ» Ă  leur diffĂ©rentes interprĂ©tations par les utilisateurs. Rappelez-vous Ă©galement que l’Ă©ventail de mouvement est limitĂ©! Vous pouvez facilement diffĂ©rencier un « salut » de la main droite, d’un de la main gauche. Une main en bas, ou en haut.

Demandez-vous aussi, comment gérer le fait de devoir déclencher plusieurs actions simultanément?

Si vous deviez arriver au point de faire des mouvements trop complexes, ou difficiles Ă  exĂ©cuter, les utilisateurs risqueraient vite d’ĂȘtre fatiguĂ©s, ou lassĂ©s de votre application. Et dĂšs lors, ils en auront une mauvaise expĂ©rience.

Dans ce contexte, l’utilisation de la reconnaissance vocale semble ĂȘtre une bonne idĂ©e!

SDK 1.0 et reconnaissance vocale

En installant le SDK 1.0, vous avez installĂ© par la mĂȘme occasion le Microsoft Kinect Speech Recognition Language Pack (en-Us). Et en effet pour le moment ce pack n’est disponible qu’en anglais. Toutefois, le français est annoncĂ© dans la release 1.5 au cĂŽtĂ© d’autres langues telles que l’Italien, le Japonais, et l’Espagnol.

MĂȘme si le français n’est pas encore lĂ , rien n’empĂȘche de dĂ©jĂ  y jeter un oeil! Ainsi vous serez prĂȘt pour la suite.

De plus il faut savoir que la reconnaissance vocale n’est pas quelque chose de liĂ© Ă  la Kinect. Vous pourriez le faire avec n’importe quel autre micro!

Hands-on

Comme toujours, je vous propose de télécharger les sources directement pour suivre plus facilement:

WpfKinect - 5 - Speech Recognition

Pour cet exemple, on va reprendre un projet dans lequel des sphĂšres Ă©taient dessinĂ©es pour reprĂ©senter les joueurs: un cercle pour chaque main, et un plus grand pour la tĂȘte. On n’affiche que les deux joueurs trackĂ©s.

A ce programme de base, on va ajouter la possibilitĂ© de changer les formes affichĂ©es (des cercles ou des carrĂ©s), ainsi que la couleur des joueurs indĂ©pendamment l’un de l’autre.

Ainsi, le but c’est de pouvoir dire (en anglais bien sĂ»r :) ) « Utiliser des carrĂ©s rouges pour le joueur 1″ et de voir l’image se mettre Ă  jour en consĂ©quence.

1/ Initialiser le Recognizer

Pour commencer il va falloir ajouter une rĂ©fĂ©rence Ă  la librairie Microsoft.Speech.dll. A ne pas confondre avec System.Speech.dll, qui ne vous donnera pas accĂšs au recognizer de la Kinect. Les deux librairies sont trĂšs proches l’une de l’autre et sont destinĂ©es Ă  ne faire qu’une prochainement.

La doc du SDK propose une mĂ©thode helper pour retrouver le recognizer de la Kinect. On a besoin de cette mĂ©thode parce que vous avez dĂ©jĂ  d’autres SpeechRecognitionEngine, mais nous on veut celui du SDK Kinect.

Cette mĂ©thode, elle fait quoi: elle crĂ©e une fonction qui prends en paramĂštre un RecognizerInfo et qui retourne un boolĂ©en. Le RecognizerInfo c’est un objet qui va dĂ©crier un outils de reconnaissance vocale installĂ© sur votre machine. Cet objet a notamment un attribut de type Dictionary qui contient tout un tas d’informations dĂ©crivant le recognizer comme par exemple les cultures et langues supportĂ©es, la version, le nom, ou tout autre propriĂ©tĂ© spĂ©cifique Ă  ce recognizer.

Cette fonction va donc retourner true si la propriĂ©tĂ© Kinect du dictionnary AdditionalInfo contient true, et si la culture est « en-US » (la seule disponible pour le moment).

Et on va ensuite utiliser une requĂȘte Linq dans laquelle on va faire appel Ă  cette fonction. Ainsi, on va rĂ©cupĂ©rer la liste de tous les recognizers installĂ©s, et on prendra le premier parmi ceux rĂ©pondant aux critĂšres de la fonction.

        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();
        }

On va ajouter une mĂ©thode pour instancier le SpeechRecognizerEngine. Si on ne trouve pas de RecognizerInfo, on affiche un message d’erreur. Pareil si on arrive pas Ă  instancier un SpeechRecognitionEngine Ă  partir du RecognizerInfo rĂ©cupĂ©rĂ©.

        private void InitializeSpeechRecognition()
        {
            RecognizerInfo ri = GetKinectRecognizer();

            if (ri == null)
            {
                MessageBox.Show(
                    @"There was a problem initializing Speech Recognition.
Ensure you have the Microsoft Speech SDK installed.",
                    "Failed to load Speech SDK",
                    MessageBoxButton.OK,
                    MessageBoxImage.Error);
                return;
            }

            try
            {
                speechRecognizer = new SpeechRecognitionEngine(ri.Id);
            }
            catch
            {
                MessageBox.Show(
                    @"There was a problem initializing Speech Recognition.
Ensure you have the Microsoft Speech SDK installed and configured.",
                    "Failed to load Speech SDK",
                    MessageBoxButton.OK,
                    MessageBoxImage.Error);
            }
            if (speechRecognizer == null)
                return;

            // Ajouter la suite ici!
        }
2/ Préparer les mots-clés

Pour nous aider dans la suite, on va associer un ensemble de termes sous forme de chaĂźne de caractĂšre Ă  des valeurs:

        #region Phrase mapping

        private Dictionary<string, Shape> Shapes = new Dictionary<string, Shape>
        {
            { "Circle", Shape.Circle },
            { "Square", Shape.Square },
        };

        private Dictionary<string, SolidColorBrush> BgrColors = new Dictionary<string, SolidColorBrush>
        {
            { "Yellow", Brushes.Yellow },
            { "Blue", Brushes.Blue },
            { "Red", Brushes.Red },
        };

        private Dictionary<string, int> PlayerIndexes = new Dictionary<string, int>
        {
            { "One", 0 },
            { "Two", 1 },
        };

        #endregion

Notez que l’Ă©numĂ©ration Shape a Ă©tĂ© crĂ©Ă©e pour l’occasion. Ce n’est pas nĂ©cessaire, mais ça permet d’y voir plus clair et d’ajouter facilement de nouvelles possibilitĂ©s.

    public enum Shape
    {
        Circle,
        Square
    }
3/ Créer la sémantique

A la suite du code dans la mĂ©thode InitializeSpeechRecognition, on va construire la phrase telle qu’elle devrait ĂȘtre dĂ©clarĂ©e par l’utilisateur. On va par exemple crĂ©er des objets Choices, contenant l’ensemble des valeurs que l’on pourrait s’attendre Ă  recevoir Ă  une position dans la phrase.

A la fin, on construit concrĂštement la phrase Ă  partir de valeurs fixes, et de choix: ainsi, la phrase commencera toujours par « Use » et pourra ensuite ĂȘtre suivie de n’importe laquelle des couleurs, ensuite de n’importe quelle forme parmi les possibilitĂ©s donnĂ©es Ă©videmment, etc…

            // Create choices containing values of the lists
            var shapes = new Choices();
            foreach (string value in Shapes.Keys)
                shapes.Add(value);

            var colors = new Choices();
            foreach (string value in BgrColors.Keys)
                colors.Add(value);

            var playerIndexes = new Choices();
            foreach (string value in PlayerIndexes.Keys)
                playerIndexes.Add(value);

            // Describes how the phraze should look like
            var gb = new GrammarBuilder();
            //Specify the culture to match the recognizer in case we are running in a different culture.
            gb.Culture = ri.Culture;
            // It should start with "Use"
            gb.Append("Use");
            // And then we should say any of the colors value
            gb.Append(colors);
            // Then one of the two possible shapes
            gb.Append(shapes);
            // then again the words "for player"
            gb.Append("for player");
            // and finally the player that we want to update
            gb.Append(playerIndexes);

            // Create the actual Grammar instance, and then load it into the speech recognizer.
            var g = new Grammar(gb);

            speechRecognizer.LoadGrammar(g);

Au final, on peut construire des objets trĂšs complexes. L’ensemble de l’objet GrammarBuilder aurait pu ĂȘtre ajoutĂ© Ă  un nouvelle objet Choices en face d’un second objet GrammarBuilder tout aussi complexe, ou d’un simple autre mot.

4/ Lancer la reconnaissance

Toujours Ă  la suite du code prĂ©cĂ©dent, on va s’abonner aux Ă©vĂšnements de notre speech recognizer:

            speechRecognizer.SpeechRecognized += speechRecognizer_SpeechRecognized;
            speechRecognizer.SpeechHypothesized += speechRecognizer_SpeechHypothesized;
            speechRecognizer.SpeechRecognitionRejected += speechRecognizer_SpeechRecognitionRejected;

Et pour finir on va attribuer la source audio (celle de notre Kinect), démarrer cette source, et lancer effectivement la reconnaissance!

            var audioSource = this.Kinect.AudioSource;
            audioSource.BeamAngleMode = BeamAngleMode.Adaptive;
            var kinectStream = audioSource.Start();

            speechRecognizer.SetInputToAudioStream(
                    kinectStream, new SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null));
            speechRecognizer.RecognizeAsync(RecognizeMode.Multiple);

L’Ă©numĂ©ration RecognizeMode indique que la reconnaissance doit s’arrĂȘter directement aprĂšs un premier Ă©lĂ©ment reconnu (Single), ou qu’elle continue jusqu’Ă  ce qu’on l’arrĂȘte (Multiple).

5/ Traiter les résultats

Finalement, on va dĂ©cortiquer ce qu’on pense avoir entendu. Ces deux premiers eventhandlers ne nous intĂ©ressent pas vraiment. Le premier, rejected, indique simplement qu’une phrase n’a pas Ă©tĂ© reconnue (dans le sens oĂč elle ne match pas avec une phrase attendue) avec assez d’assurance. Le second, Hypothesized, indique qu’un mot ou groupe de mots a Ă©tĂ© reconnu et qu’il correspond Ă  plusieurs phrases possibles.

        void speechRecognizer_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
        {
            Console.WriteLine("Rejected: " + e.Result.Text);
        }

        void speechRecognizer_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        {
            Console.WriteLine("Hypothesized: " + e.Result.Text);
        }

L’event qui va nous intĂ©resser est le SpeechRecognized. Il va nous donner un rĂ©sultat, caractĂ©risĂ© par une propriĂ©tĂ© Confidence. Cette propriĂ©tĂ© indique combien ce rĂ©sultat semble ĂȘtre la bon rĂ©sultat comparĂ©s Ă  d’autres. Les autres rĂ©sultats possibles peuvent ĂȘtre consultĂ©s via la propriĂ©tĂ© Alternatives, qui est une collection de RecognizedPhrase.

La phrase reconnue en elle-mĂȘme est stockĂ©e dans la propriĂ©tĂ© Text sous forme d’une chaĂźne de caractĂšre ou bien dans la propriĂ©tĂ© Words, sous la forme d’une collection de RecognizedWordUnit. Chacun de ces mots possĂšde Ă©galement une propriĂ©tĂ© Confidence.

Dans l’exemple ci-dessous, on va analyser la phrase et modifier les settings d’un joueur en fonction de son contenu.

        void speechRecognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            // Confidence indicates the likelihood that a phrase is recognized correctly
            // compared to alternatives. 0.8 confidence doesn't mean 80M chance of being correct.
            if (e.Result.Confidence < 0.50)
            {
                Console.WriteLine("Rejected: " + e.Result.Text + ", " + e.Result.Confidence);
                if (e.Result.Alternates.Count > 0)
                {
                    // Print the alternatives
                    Console.WriteLine("Alternates available: " + e.Result.Alternates.Count);
                    foreach (RecognizedPhrase alternate in e.Result.Alternates)
                    {
                        Console.WriteLine("Alternate: " + alternate.Text + ", " + alternate.Confidence);
                    }
                }
                return;
            }
            Console.WriteLine("Recognized: " + e.Result.Text + ", " + e.Result.Confidence);

            var index = PlayerIndexes[e.Result.Words[5].Text];

            var playerConfig = playerConfigs[index];

            if (playerConfig != null)
            {
                playerConfig.Brush = BgrColors[e.Result.Words[1].Text];

                playerConfig.Shape = Shapes[e.Result.Words[2].Text];
            }
        }

Article original: Kinect SDK 1.0 – 5 – Reconnaissance vocale
Version anglaise: http://www.renauddumont.be/en/2012/kinect-sdk-1-0-5-reconnaissance-vocale


Ajoutez cet article Ă  vos favoris.