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.