Rebuild : Slides et démos

by Nicolas Calvi 4. octobre 2013 11:29

C'est avec un grand plaisir que j'ai participé hier à la ReBuild de Nantes. J'ai pu présenter deux sessions et c'est donc tout naturellement que je vous proposes les Slides et les démos de ces sessions :

PixelSense, une histoire collaborative

Slides : PixelSense - Une histoire collaborative.pdf (1,77 mb)

Kinect, réflextion et conception

Slides : Kinect - Réflexion et conception.pdf (1,41 mb)

Démos : RebuildDemoKinect.rar (11,05 mb)

N'hésitez pas me contacter si vous avez des questions sur le sujet.

Session Kinect - Slides et démos !

by Nicolas Calvi 14. février 2013 12:41

La session "Kinect en moins de 10 minutes (LAN205)" que j'ai partagé avec mes compères du Kinect Genius Bar, Johanna Rowe et Vincent Guigui, a eu du succès, je remercie au passage tous ceux qui sont venu nous voir.

En attendant la Webcast qui arrivera vers le 18 mars, je vous mets en ligne les slides et le code source des démos.

LAN205 - Kinect en moins de 10 Minutes - Demo.rar (15,53 mb)

LAN205 - Kinect en moins de 10 Minutes - Slides.pdf (1,64 mb)

J'espère que cela vous aura plus !

Kinect SDK : Découverte

by Nicolas Calvi 3. avril 2012 14:21

Enfin ! C’est le 1 février dernier que Microsoft met à disposition du public la première version RTW du Kinect SDK for Windows. Au menu, optimisation, documentation et refonte des APIs. Cet article fait une comparaison avec la version BETA du SDK Kinect for Windows mais revient sur les principales fonctionnalités. Cet article fait suite à mon article paru dans le Programmez! 148 de Janvier 2012. Il est question de se familiariser avec le SDK.

1. Améliorations de l’architecture Kinect

Kinect est un véritable petit bijou de technologie. Outre les fonctionnalités disponibles sur Kinect pour XBOX 360, Kinect for Windows dispose de plusieurs améliorations :

- Existence d’un mode « near » qui permet de détecter des objets à partir de 40 cm de l’appareil.
- Possibilité de brancher jusqu’à 4 Kinect for Windows sur un même PC.
- Amélioration de la détection des squelettes.
- Intégration dans le SDK de la dernière version de Microsoft Speech Platform afin d’utiliser la reconnaissance vocale.

Pour pouvoir profiter des dernières améliorations, il va falloir acquérir un nouveau matériel estampiller « Kinect for Windows ». Ce nouveau Kinect, qui peut être acheté sur le Microsoft Store au prix de 249 euros, est une version amélioré de la « Kinect for Xbox » et permet l’utilisation du fameux mode « near », chose impossible avec une « Kinect for Xbox ».

2. Mode de licence

La plus grande interrogation à ce jour, est le mode de licence de Kinect. Jusqu’à maintenant, toute application créer avec le SDK Beta de Kinect n’était pas destinée à être vendu ou utilisé en entreprise, seul les étudiants, chercheurs et quidam du développement pouvaient s’amuser avec à des buts de prospection d’usage et aussi pour le fun.

Maintenant, il est possible de développer des applications à usage commerciale, mais il y a des conditions à respecter. Ce qu’il faut déjà comprendre, c’est que Microsoft se rémunère sur la vente de « Kinect for Windows », il faudra donc, pour déployer une application en entreprise, posséder un « Kinect for Windows » et non un « Kinect for Xbox ».

Dans les fait, le Kinect SDK permet de développer avec les deux matériels, mais une fois l’application exécutée sur la version « runtime » de Kinect, celui-ci va vérifier si le Kinect connecté est bien un « Kinect for Windows », si ce n’est pas le cas il va refuser de le prendre en charge.

Pour résumer, en développement (par le SDK) toutes les versions de Kinect sont acceptées, en mode runtime seuls les « Kinect for Windows » sont acceptés. D’ailleurs, on peut interpréter cela en se disant que l’utilisation d’un SDK non Microsoft pour utiliser Kinect est autorisé sous réserve que ce soit un matériel « Kinect for Windows » qui soit connecté. Bien sûr, prenez soin de vérifier cela auprès de Microsoft.

3. Utilisation du SDK

Au niveau du SDK, pas de changements de fond dans l’environnement de développement (Windows 7), l’outil de développement (Visual Studio 2010 toute version) et les langages de programmation disponibles (C# et C++) en 32 et 64 bits. C’est plutôt dans la forme que cela change.

Récupérer les Kinect connectés :

Dorénavant l’assembly utilisée pour développer sur Kinect est « Microsoft.Kinect ».

Afin de récupérer les informations relatives aux instances des Kinect connectés à la machine, on utilise maintenant une classe statique nommée simplement « KinectSensor ». Cette classe possède une propriété statique nommée « KinectSensors » permettant de récupérer la collection des Kinect connectés. Il suffit ensuite d’extraire de cette collection le ou les Kinect qui nous intéresse.

using Microsoft.Kinect;

private KinectSensor _kinectSensor;

public MaFenetre()
{
    // Si on trouve un kinect on l'initialise
    if (KinectSensor.KinectSensors.Count > 0)
    {
        this._kinectSensor = KinectSensor.KinectSensors[0];  
        this.InitializeKinect();
    }
}

Afin d’initialiser un Kinect il faut passer par plusieurs étapes. La première est de lancer la méthode Start de l’instance Kinect. On passe ensuite des paramètres pour éliminer le bruit (seulement nécessaire si on fait de la reconnaissance de squelette). On ouvre ensuite les flux qui nous intéressent (à savoir l’image VGA, l’image de profondeur et les squelettes) et on s’abonne à chaque événement de flux (ColorFrameReady, DepthFrameReady et SkeletonFrameReady) pour récupérer l’information.

Une autre alternative est de récupérer les informations de chaque événement en une fois avec l’événement « AllFramesReady » (figure 2). Ce dernier est une nouveauté par rapport aux anciennes versions du SDK qui nous obligeaient à nous abonner à chaque évènement séparément (ce qui est toujours possible en fonction des besoins). Mais parfois on a besoin d’avoir en même temps l’image vidéo et de profondeur, donc au lieu de la stocker pour l’utiliser plus tard, le runtime Kinect nous synchronise tous les éléments et nous les envois ensemble. Outre le fait que cela soit plus pratique, cela permet aussi un gain de traitement.

Il faut juste savoir que l’appel à la fonction « Enable() » est toujours nécessaire pour que les informations soient renseignées dans le « AllFramesReady », cette méthode démarre la capture du flux concerné.

private void InitializeKinect()
{
    // On démarre la scrutation
    this._kinectSensor.Start();

    // SmoothParamater pour éliminer le bruit
    TransformSmoothParameters parameters = new TransformSmoothParameters
    {
        Correction = 1.0f,
        JitterRadius = 0.01f,
        MaxDeviationRadius = 0.01f,
        Prediction = 1.0f,
        Smoothing = 0.9f
    };

    // Ouverture des flux
 this._kinectSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
 this._kinectSensor.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);
    this._kinectSensor.SkeletonStream.Enable(parameters);

    // On se branche sur tous les callbacks (ne pas se brancher sur les autres 
    // si on se branche sur celui-là
    this._kinectSensor.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(this.AllFramesReady);
}

Récupérer les données vidéo et les squelettes :

Afin de récupérer les données vidéo (image VGA et image de profondeur) on utilise l’argument de l’évènement levé quand toutes les frames (VGA, profondeur et squelette) sont disponibles. Les informations contenues dans l’argument vont nous être utiles pour construire notre image de rendu.

Pour obtenir les données de l’image VGA on utilise la méthode « OpenColorImageFrame », cette méthode va rendre disponible les informations coté managé et qui contient (quand l’image n’est pas nulle) un tableau de byte. Il suffit ensuite de copier ce flux dans notre application par la méthode « CopyPixelDataTo », dans notre exemple on copie les informations dans une variable que l’on nomme ici « pixelData ».

On utilise ensuite certaines propriétés de l’image (à savoir sa hauteur, sa longueur et le fameux « pixelData ») pour créer l’image VGA dans un type connu (WriteableBitmap dans notre exemple) et utilisable comme bon nous semble.

// Sert pour mettre à jour l’image
private readonly int _Bgr32BytesPerPixel = (PixelFormats.Bgr32.BitsPerPixel + 7) / 8;

private void AllFramesReady(object sender, AllFramesReadyEventArgs e)
{
    // Gestion de l'image
    using (ColorImageFrame image = e.OpenColorImageFrame())
    {
        if (image != null)
        {
            byte[] pixelData = new byte[image.PixelDataLength];
            image.CopyPixelDataTo(pixelData);
            WriteableBitmap colorFrame = new WriteableBitmap(this._kinectSensor.ColorStream.FrameWidth, this._kinectSensor.ColorStream.FrameHeight, 96, 96, PixelFormats.Bgr32, null);
            colorFrame.WritePixels(new Int32Rect(0, 0, image.Width, image.Height), pixelData, image.Width * this._Bgr32BytesPerPixel, 0);
        }
    }
    // …
}

L’accès aux informations de l’image de profondeur de Kinect est relativement similaire à celui de l’image VGA. En effet, on utilise la méthode « OpenDepthImageFrame » de l’argument de l’évènement, on crée un tableau de type « short » correspondant au « pixelData » de l’image et on construit l’image de profondeur dans un WriteableBitmap.

Il y a néanmoins une petite subtilité qui est qu’il faut transformer un peu l’image pour l’exploiter. La conversion est expliquée dans le précédent article sur Kinect, les seuls changements sont l’apparition de masques pour faciliter le traitement. 

using (DepthImageFrame image = e.OpenDepthImageFrame())
{    
    if (image != null)
    {
        short[] depthImage = new short[image.PixelDataLength];
        image.CopyPixelDataTo(depthImage);

        // Récupération des informations de profondeur
        byte[] computeImage = this.ConvertDepthFrame(depthImage, image.Width, image.Height);

        // Conversion en image exploitable
        this.DepthFrame.WritePixels(new Int32Rect(0, 0, image.Width, image.Height), computeImage, image.Width *  _Bgr32BytesPerPixel, 0);
        // …
    }
}

private byte[] ConvertDepthFrame(short[] depthFrame, int imageWidth, int imageHeight)
{
    byte[] depthFrame32 = new byte[imageWidth * imageHeight * MainViewModel.Bgr32BytesPerPixel];

    for (int i16 = 0, i32 = 0; i16 < depthFrame.Length && i32 < depthFrame32.Length; i16++, i32 += 4)
    {
        // On récupère l'index joueur et la distance
        int player = depthFrame[i16] & DepthImageFrame.PlayerIndexBitmask;
        float realDepth = Convert.ToSingle(depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth);

        // Coder ici la convention de l’image …
    }

    // On retourne la frame
    return (depthFrame32);
}

Le processus pour récupérer les squelettes est similaire dans son principe. On utilise cette fois-ci la méthode  « OpenSkeletonFrame » de l’argument qui nous permet d’en extraire les informations des différents squelettes via la méthode « CopySkeletonDataTo ».

Une fois les squelettes récupérés il suffit de les trier pour obtenir ceux qui sont dans l’état « Tracked » c’est-à-dire quand Kinect arrive à définir le squelette et de faire des opérations sur ces derniers (comme récupérer les différents points du squelette et regarder leurs coordonnées).

// Recherche des squelettes
using (SkeletonFrame frame = e.OpenSkeletonFrame())
{
    if (frame != null && frame.SkeletonArrayLength > 0)
    {
        Skeleton[] skeletons = new Skeleton[frame.SkeletonArrayLength];
        frame.CopySkeletonDataTo(skeletons);

        var result = from p in skeletons
                         where p.TrackingState == SkeletonTrackingState.Tracked
                         select p;

        // Affichage des squelettes
        foreach (Skeleton item in result)
        {
            // Faire les opérations sur les différents squelettes
            // par exemple collecter tous les « Joints » et les afficher
        }
    }
}

En ce qui concerne les changements mineurs, on notera principalement la disparition d’indice de qualité W des SkeletonPoint.

Ainsi, nous avons pu voir les différents changements dus à la sortie officielle du SDK Kinect par rapport aux SDK antérieurs. Une multitude de possibilités s’offre au développeur une fois que les informations captées par Kinect sont transmises à la machine. Laissez parler votre imagination, une nouvelle ère est née !

Je vous laisse aussi télécharger la démo de cet article : KinectDemo.rar (147,64 kb) 

Merci à Patrick-André Marendat pour m'avoir aidé à rédiger cet article :)

Application Kinect !

by Nicolas Calvi 9. mars 2012 19:29

Ca y est, nous avons réalisé une vidéo de notre application Kinect for Windows à destination d'iDTGV, une publicité interactive qui a d'ailleurs fait l'objet d'une session au Techdays 2012 par votre serviteur.

"Cette vidéo présente notre projet Kinect for Windows de "Publicité interactive". La finalité du concept de publicité interactive avec Kinect est de recréer une expérience positive avec la marque. Pour illustrer ce concept nous avons décidé de réaliser un partenariat avec iDTGV. 

Ce projet a été réalisé avec une équipe pluri-disciplinaire (Designer, Graphiste, Developpeur) et a mis en avant les problématiques de développement des gestuelles avec Kinect d'une part, et de rendu visuel (XNA) d'autre part."

Lien Webcast session au Techdays 2012