Blog

Kinect SDK 1.0 ‚Äď 1 ‚Äď Introduction √† l’API

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

 

Cela fait maintenant plus de deux mois que le SDK 1.0 de Kinect for Windows a √©t√©¬†l√Ęch√©¬†dans la nature! En attendant la sortie de la version 1.5 (annonc√©e pour fin mai), je vous propose de faire un petit tour de la version actuelle, histoire de prendre en main la Kinect !

Pour commencer, assurez-vous de remplir les conditions suivantes:

  • Avoir quelques connaissances en C# (ou VB, √ßa marche aussi, mais les exemples de code que je donnerai seront en C# )
  • Avoir une installation de Visual Studio 2010 (si vous ne l’avez pas, la version Visual Studio 2010 Express gratuite est suffisante)
  • et enfin, the last but not least: avoir une Kinect!

Rapide tour du matériel

Sans trop rentrer dans les d√©tails, la Kinect est pourvue d’une cam√©ra, et d’un couple √©metteur/r√©cepteur d’infrarouges qui vous permettra d’obtenir une vision en profondeur de l’environnement.

La Kinect est √©galement √©quip√©e de 4 micros, et est pos√©e sur un socle motoris√©. Il est possible d’ajuster sa position en la faisant bouger de haut en bas.

Télécharger et installer le SDK

Pour aller plus loin, j’vous invite √† cliquer sur l’image suivante pour t√©l√©charger la derni√®re version du SDK:

Télécharger le Kinect SDK 1.0

Si tout se déroule bien, vous devriez trouver les programmes suivants dans Panneaux de configuration >> Programmes et fonctionnalités:

Installation completed

Notez que la reconnaissance vocale n’est disponible qu’en anglais dans le SDK 1.0, mais le fran√ßais devrait arriver fin mai! ;)

Microsoft a eu la tr√®s bonne id√©e de proposer un ensemble de samples lors de l’installation. Ils vont nous √™tre utiles pour la suite! Si vous les avez manqu√©s, vous pouvez les retrouver dans le menu d√©marrer:

Une fois lanc√©, vous pouvez d√©j√† installer la solution KinectExplorer, qui vous donne acc√®s √† des contr√īles r√©utilisables pour rapidement prendre en main votre Kinect, et aussi pourquoi pas le jeu ShapeGame, histoire de vous d√©tendre!

Un peu de théorie

L’API du Kinect SDK 1.0 ne contient pas √©norm√©ment de classes et est plut√īt intuitive. Vous trouverez de la doc dans le dossier d’installation: ~Programs\Microsoft SDKs\Kinect\v1.0\Documentation\KinectSDK.chm¬†ou sur MSDN : Kinect for Windows SDK¬†et Microsoft.Kinect namespace.

La classe centrale d’un projet utilisant la Kinect, est √©videmment la classe KinectSensor. Une instance de KinectSensor repr√©sente une Kinect (connect√©e ou non) √† votre PC. Cette classe va donc simplement vous permettre de contr√īler votre Kinect et de r√©cup√©rer les informations que vous lui demanderez.

Il y a ensuite principalement 3 classes, h√©ritant toutes de ImageFrame: ColorImageFrame, DepthImageFrame et SkeletonFrame. Chacun de ces objets repr√©sentent ce qu’a vu la Kinect √† un temps T, ¬†sous diff√©rents aspects (et les noms des classes vous laissent supposer lesquels).

Voyons d’abord comment d√©tecter si une Kinect est branch√©e √† votre PC (depuis le SDK 1.0, il est possible de g√©rer jusqu’√† 4 Kinect simultan√©ment) !

Créez un nouveau projet WPF, ajoutez-y une référence à la librairie et éditez la classe MainWindow:

MainWindow.xaml.cs
        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // Walk through KinectSensors to find the first one with a Connected status
            var firstKinect = (from k in KinectSensor.KinectSensors
                               where k.Status == KinectStatus.Connected
                               select k).FirstOrDefault();

            if (firstKinect != null)
                SetNewKinect(firstKinect);

            KinectSensor.KinectSensors.StatusChanged += KinectSensors_StatusChanged;
        }

Avec ce code on va chercher une Kinect d√®s que la page sera charg√©e. Pour √ßa, on utilise la propri√©t√© statique KinectSensors de la classe KinectSensor. Cette propri√©t√© est de type KinectSensorCollection¬†(qui h√©rite en fait de ReadOnlyCollection<KinectSensor>), et permet de parcourir la liste des capteurs disponibles. On cherche ici un KinectSensor avec le Status KinectStatus.Connected, qui indique que la Kinect est branch√©e et pr√™te √† l’emploi!

Si on en trouve une, on va appeler la m√©thode SetNewKinect, et dans tous les cas on va s’abonner √† l’event StatusChanged de la collection de Kinect. Ca nous permettra par la suite de savoir qu’une nouvelle Kinect vient d’√™tre branch√©e, ou d√©branch√©e !

        private void SetNewKinect(KinectSensor newKinect)
        {
            if (kinect != newKinect)
            {
                if (kinect != null)
                    StopKinect(Kinect);

                if (newKinect != null)
                    OpenKinect(newKinect);
            }

            Kinect = newKinect;
        }

Dans la m√©thode SetNewKinect, on se charge d’activer et de stopper les KinectSensor et d’attribuer le capteur courant √† la propri√©t√© Kinect.¬†Pour arr√™ter la Kinect, la m√©thode Stop est suffisante pour lib√©rer toutes les ressources. Si vous appelez la m√©thode Dispose, il faudra d√©brancher et rebrancher la Kinect pour pouvoir √† nouveau l’utiliser!

        private void OpenKinect(KinectSensor newKinect)
        {
            // TODO: Enable needed streams with desired formats and parameters
            newKinect.Start();
        }

        private void StopKinect(KinectSensor oldKinect)
        {
            oldKinect.Stop();
        }

Et pour finir l’event handler qui va comparer la Kinect qui a chang√© de statut avec celle actuellement utilis√©e. Si la nouvelle Kinect a le statut « Connected« , on remplacera l’existante. Et dans le cas o√Ļ c’est la Kinect existant qui a chang√© de statut et qui n’est donc plus connect√©e, on appellera la m√©thode SetNewKinect avec la valeur null. De cette mani√®re, on s’assure que la propri√©t√© Kinect contient √† tout moment soit une Kinect connect√©e, soit null.

        void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e)
        {
            if (e.Sensor != null && e.Status == KinectStatus.Connected)
            {
                SetNewKinect(e.Sensor);
            }
            else if (e.Sensor == Kinect)
            {
                // The current Kinect isn't connected anymore
                SetNewKinect(null);
            }
        }

C’est tout ce qu’il vous faut pour commencer √† utiliser votre Kinect!

Comprendre le KinectStatus

Le tableau suivant reprend l’ensemble des statuts que peuvent avoir un objet de type KinectSensor, et la signification de chacun. Dans une application Kinect, il est important de donner un feedback √† l’utilisateur concernant le statut de sa Kinect, ou bien m√™me pour indiquer que votre application en requiert une!

Statuts possibles pour la Kinect

Maintenant que vous avez compris comment √ßa fonctionne, n’h√©sitez pas √† utiliser le contr√īle KinectSensorChooser du projet WpfViewers disponible dans le SDK 1.0. A la fin de cet article, vous verrez comment vous en servir!

Si vous √™tes un d√©veloppeur et que vous avez install√© le Kinect SDK, vous pouvez utiliser une Kinect pour Xbox plut√īt qu’une Kinect pour PC, mais il est recommand√© d’utiliser une Kinect PC pour profiter pleinement du SDK. On reparlera par la suite des diff√©rences entre les deux capteurs!

Deux approches: event-driven vs. polling

Maintenant qu’on a r√©cup√©r√© notre Kinect, on aimerait pouvoir en faire quelque chose. Pour √ßa il faut utiliser les diff√©rents flux que le capteur met √† notre disposition: couleurs, profondeurs, skeletons. L’API propose deux mani√®res de r√©cup√©rer ces flux, et vous choisrez l’une ou l’autre en fonction du type d’application que vous faites.

Si vous d√©veloppez une application classique, par exemple en WPF ou Winforms, dite « event-driven« , vous laisserez la Kinect vous avertir √† chaque fois que des nouvelles donn√©es seront disponibles. Si par contre vous √™tre dans un jeu, qui tourne d√©j√† dans une boucle, vous pourrez vous m√™me r√©clamer des informations quand vous en avez besoin.

Dans les exemples qui suivront, je vais principalement utiliser la première approche.

Premier projet: contr√īler le Tilt Motor

Pour suivre plus facilement, vous pouvez télécharger les sources: WpfKinect1

Pour √™tre s√Ľr que la Kinect r√©pond correctement, on va tout de suite cr√©er un premier projet. Le but ici est d’afficher le stream de la cam√©ra vid√©o, et les propri√©t√©s du moteur d’inclinaison qu’on va pouvoir modifier dynamiquement.

Cr√©ons un nouveau projet WPF, que l’on appellera¬†WpfKinect, avec toujours une r√©f√©rence √†¬†Microsoft.Kinect.dll. Cette fois-ci, on va √©galement inclure dans la solution le projet¬†WpfViewers¬†que vous avez d√Ľ installer en m√™me temps que le SDK !

Il y a donc maintenant deux projets dans la solution. Dans le projet¬†WpfKinect, ajoutez une r√©f√©rence au projet¬†WpfViewers. Si vous ouvrez l’√©diteur XAML, vous constaterez que la Toolbox contient des contr√īles en plus. Ce sont ceux d√©finis dans le projet WpfViewers et que vous pouvez r√©utiliser comme bon vous semble!

Microsoft.Samples.Kinect.WpfViewers

J’ai l√©g√®rement modifi√© le code XAML de la page MainWindow pour afficher 3 contr√īles:

  • Un KinectColorViewer qui va afficher l’image de la cam√©ra de la Kinect
  • Un TiltMotorController qu’on va cr√©er juste apr√®s pour changer l’angle d’inclinaison de la Kinect.
  • Un KinectSensorChooser qui va grandement nous faciliter les choses pour trouver une Kinect connect√©e!
    <Grid>
        <Grid.ColumnDefinitions >
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <viewers:KinectColorViewer Grid.Column="0" Width="640" Height="480"
                                   Kinect="{Binding ElementName=SensorChooser, Path=Kinect}"/>
        <local:TiltMotorController Grid.Column="1"
                                   HorizontalAlignment="Center" VerticalAlignment="Center"
                                   Kinect="{Binding ElementName=SensorChooser, Path=Kinect}"/>
        <viewers:KinectSensorChooser Grid.Column="1" x:Name="SensorChooser"
                                     KinectSensorChanged="SensorChooser_KinectSensorChanged"
                                     VerticalAlignment="Stretch" Background="White" Margin="10" />
    </Grid>

Au niveau de l’utilisation des contr√īles du projet WpfViewers, c’est assez simple. Le KinectSensorChooser poss√®de une propri√©t√© Kinect de type KinectSensor. Le KinectColorViewer a besoin pour fonctionner de recevoir √©galement une Kinect. Donc ce qu’on va simplement faire, c’est utiliser le binding pour faire en sorte que le color viewer utilise la propri√©t√© Kinect du KinectSensorChooser.

Dans le code-behind on va juste impl√©menter l’event handler SensorChooser_KinectSensorChanged, pour d√©marrer le capteur et activer les flux dont on a besoin, c’est-√†-dire dans ce cas-ci le ColorStream.

        private void SensorChooser_KinectSensorChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (e.OldValue != null)
            {
                ((KinectSensor)e.OldValue).Stop();
            }

            if (e.NewValue != null)
            {
                var newSensor = (KinectSensor)e.NewValue;
                newSensor.ColorStream.Enable();
                newSensor.Start();
            }
        }

Le contr√īle TiltMotorController va √™tre construit de la m√™me fa√ßon, et vous allez donc voir au passage comment cr√©er une propri√©t√© utilisable directement dans le XAML. Ce n’est pas une simple propri√©t√© mais une DependencyProperty.

Pour enregistrer une nouvelle dependency property, on donne les 4 paramètres suivants:

  • Le nom de la propri√©t√© (qui sera utilisable ensuite dans le XAML)
  • Le type de la propri√©t√©
  • Le type parent de la propri√©t√©, donc celui auquel on veut ajouter cette propri√©t√©
  • Et enfin un objet UIPropertyMetadata qui prend comme param√®tre la valeur par d√©faut de la propri√©t√©, et un¬†callback(static) appel√© lorsque la valeur de la propri√©t√© est modifi√©e.
public static readonly DependencyProperty KinectProperty =
            DependencyProperty.Register("Kinect",
            typeof(KinectSensor),
            typeof(TiltMotorController),
            new UIPropertyMetadata(null, new PropertyChangedCallback(KinectChanged)));

Une propri√©t√© va nous permettre d’acc√©der/modifier la valeur de la¬†dependency property.

        public KinectSensor Kinect
        {
            get { return (KinectSensor)GetValue(KinectProperty); }
            set { SetValue(KinectProperty, value); }
        }
Et finalement, le callback, qui doit être une méthode statique, et une méthode qui va ajouter/retirer les event handlers sur les capteurs.
        private static void KinectChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            TiltMotorController tiltMotor = (TiltMotorController)d;
            tiltMotor.OnKinectChanged((KinectSensor)args.OldValue, (KinectSensor)args.NewValue);
        }

        private void OnKinectChanged(KinectSensor oldKinectSensor, KinectSensor newKinectSensor)
        {
            if (oldKinectSensor != null)
            {
                oldKinectSensor.AllFramesReady -= newKinectSensor_AllFramesReady;
            }

            if (newKinectSensor != null && newKinectSensor.Status == KinectStatus.Connected)
            {
                newKinectSensor.AllFramesReady += newKinectSensor_AllFramesReady;
            }
        }

Pour voir le XAML du contr√īle TiltMotorController, j’vous invite √† t√©l√©charger la solution. Mais globalement ce n’est rien de tr√®s compliqu√©: j’affiche un slider, dont la valeur refl√®te la propri√©t√© ElevationAngle (degr√©s) de la Kinect. Deux boutons, Up et Down, vont respectivement incr√©menter et d√©cr√©menter la valeur de l’angle de 5¬į. Si une exception est lanc√©e lorsqu’on tente de modifier la valeur de l’angle, elle est affich√©e dans un TextBlock.

                if (Kinect != null)
                {
                    try
                    {
                        Kinect.ElevationAngle = value;
                    }
                    catch (Exception e)
                    {
                        AngleException = e.Message;
                        OnNotifyProperty("AngleException");
                    }
                }

Pourquoi catcher une √©ventuelle exception? En fait, il n’est pas conseill√© d’utiliser le moteur de la Kinect, tout simplement parce qu’il n’est pas con√ßu pour effectuer des mouvements longs ou r√©p√©t√©s. Pour limiter le risque de mauvaise utilisation, l’API impose quelques limitations:

  • L’angle est modifiable tout au plus une fois par seconde
  • Apr√®s 15 appels cons√©cutifs, un temps d’attente de 20 secondes est obligatoire
Dans le cas du non-respect de l’une de ces conditions, une exception sera lanc√©e.

Si vous ex√©cutez le projet, et que vous prenez votre Kinect en main, vous constaterez que la valeur de l’angle varie! C’est parce que pour la Kinect, l’angle de 0 degr√© correspond au plan horizontal, et pas √† une position fixe dans son r√©f√©rentiel √† elle.

Fin de cette première partie!

Nous ne sommes pas encore allés très loin, mais vous savez maintenant que votre Kinect est bien fonctionnelle, ou bien ça vous a laissé le temps de vous en procurer une! Dans les prochains articles, on verra comment utiliser les différents formats du ColorStream, tracker le squelette et la position des utilisateurs, utiliser le capteur de profondeur et finalement comment ajouter de la reconnaissance vocale dans votre application! ;)

Article original: Kinect SDK 1.0 – 1 – Introduction √† l’API
Version anglaise: http://www.renauddumont.be/en/2012/kinect-sdk-1-0-1-introduction-a-lapi


Ajoutez cet article à vos favoris.