Loupe

[Kinect 2] Utiliser la Camera Infrarouge

Cette semaine, l’article suivant portera sur l’utilisation de la caméra infrarouge. Le principe décrit reste similaire au principe de l’article précédent avec l’utilisation de la caméra couleur : http://blogs.infinitesquare.com/b/touvre/archives/kinect-2-utiliser-la-color-camera.

La caméra infrarouge est très utile pour effectuer des calculs et appliquer des algorithmes car, contrairement à la caméra couleur, elle est indépendante de la luminosité. Ainsi les frames obtenus contiennent moins de données parasites, quelle que soit l’exposition ou l’emplacement de la Kinect. Elle servira donc pour des scénarios de reconnaissances faciales ou de détection d’expression par exemple. Cette caméra possède elle aussi un framerate de 30 fps, le code de l’article précédent peut donc servir de base pour afficher le flux de la camera.

La méthode très simple

La structure du code restant la même, il est possible de conserver un MediaElement et de remplacer MediaEncodingSubtypes.Bgra8 par MediaEncodingSubtypes.Yuy2 et TypedEventHandler<ColorFrameReader, ColorFrameArrivedEventArgs> nextFrameArrived = null; par TypedEventHandler<InfraredFrameReader, InfraredFrameArrivedEventArgs> nextFrameArrived = null;. Enfin CopyConvertedFrameDataToBuffer par CopyFrameDataToBuffer.

L’image obtenue ainsi sera verte et rose, de piètre qualité pour l’œil humain. En effet, le format utilisé n’est pas du tout adapté.

Aller un peu plus loin

Pour l’encodage des samples video, le format Rgb24 sera très bien adapté :

var encoding = VideoEncodingProperties.CreateUncompressed(MediaEncodingSubtypes.Rgb24, (uint)frameDesc.Width, (uint)frameDesc.Height);

Il faudra appliquer un peu de traitement aux données de la frame avant de fournir le MediaSample. Pour cela, il faut comprendre comment est constituée la frame : chaque pixel est un entier non signé sur deux octets correspondant à l’intensité de la donnée captée.

Dans le cas actuel, il est possible de retranscrire l’intensité de chaque pixel par un niveau de gris (ce scénario est souvent utilisé pour l’infrarouge) mais cela pourrait très bien être un niveau de rouge, de vert ou autre… Il faudra donc créer pour chaque nouvelle frame retournée par la Kinect, une frame que le MediaElement pourra traiter via un MediaSample. Le format de frame choisi étant Rgb24, voici un résumé de ce qu’il faut faire pour créer la nouvelle frame :

  • Récupérer pour chaque pixel de la frame Kinect l’intensité du signal
  • Convertir l’intensité en un pixel de la frame du MediaElement : un octet (ou byte) pour chaque couleur, soit 3 octects
  • Créer le sample final

Voici une implémentation des buffers servant à stocker les données des frames de la Kinect et du MediaElement :

var bufferSource = new ushort[(int)(frameDesc.LengthInPixels)];
var streamConverted = new MemoryStream((int)(frameDesc.LengthInPixels) * 4);
var bufferIsEmpty = true;

Le traitement consistera donc à convertir une frame de bufferSource vers streamConverter :

if (frame != null)
{
    frame.CopyFrameDataToArray(bufferSource);
    bufferIsEmpty = false;
    streamConverted.Seek(0, SeekOrigin.Begin);
    for (var i = 0; i < bufferSource.Length; ++i)
    {
        byte intensity = (byte)(bufferSource[i] >> 8);
        streamConverted.WriteByte(intensity); //red
        streamConverted.WriteByte(intensity); //green
        streamConverted.WriteByte(intensity); //blue
        streamConverted.WriteByte(byte.MinValue);
    }
}

Les données de la frame vidéo en mémoire, il suffit de définir le sample en créant un Buffer pointant directement sur la mémoire allouée pour le streamConverted :

DefineSample(a.Request, streamConverted.GetWindowsRuntimeBuffer(), timeOffset, sampleDuration);

Ici, nous avons choisi de n’écrire que l’octet de poid fort, considérant que la perte de l’octet de poids faible était acceptable. Une autre méthode possible pour obtenir l’intensité :

byte intensity = (byte)(bufferSource[i] * byte.MaxValue / ushort.MaxValue);

Voilà ! En adaptant un peu l’exemple de l’article précédent, on arrive assez facilement à afficher un rendu de la caméra infrarouge. Bien entendu, l’image est en noir et blanc, mais il est tout à fait possible de jouer sur une autre couleur. La transformation de la frame de la Kinect n’est bien entendu pas effectuée de la façon la plus optimisée possible, mais elle illustre bien ce qu’il faut faire. Dans l’idéal, il faudrait faire ce traitement en code natif à l’aide d’un shader afin de laisser la carte graphique se charger du traitement. Selon le contexte de rendu, on aura peut-être aussi accès à d’autres formats d’encodage vidéo pouvant directement agir avec les frames de la Kinect, sans que l’on ait besoin de la transformer.

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus