image

Buenas,

en el post anterior comenté alguna de las características principales para comenzar a trabajar con el kit de reconocimiento de gestos que se incluye con el Kinect SDK.

Hoy veremos como utilizar esta funcionalidad en un proyecto WPF. Para esto seguiremos los siguientes pasos:

1. Crearemos un nuevo proyecto WPF. En mi caso lo he llamado [ElBruno.FaceTracking02] y ademas he agregado la referencia a [Microsoft.Kinect].

2. Desde la carpeta de instalación del Kinect SDK Developer Toolkit, agregaremos las referencias a los ensamblados de Face Tracking. La ubicación es similar a:

C:\Program Files\Microsoft SDKs\Kinect\Developer Toolkit v1.5.2\Samples\bin

y se deben agregar las referencias a

  • Microsoft.Kinect.Tookit
  • Microsoft.Kinect.Tookit.FaceTracking

image

3. Cambiamos la configuración del proyecto para que compile en modo x86. En las propiedades del proyecto, seleccionamos la seccion “Build” y en Platform Target seleccionamos “x86”, y compilamos el proyecto.

4. Este paso es un poco “curioso” pero en el próximo post pondré una forma más elegante de hacerlo. Desde la carpeta

C:\Program Files\Microsoft SDKs\Kinect\Developer Toolkit v1.5.2\Redist\x86

copiamos los ensamblados

  • FaceTrackData.dll
  • FaceTrackLib.dll

hacia el directorio de compilación de nuestro proyecto.

image

5. Agregamos un nuevo UserControl en nuestro proyecto llamado [FaceTrackingViewer] y una clase llamada [SkeletonFaceTracker]. Como tienen bastante código dentro, lo mejor es bajar el zip de ejemplo y copiarlo completo.

6. La clase [SkeletonFaceTracker], el la encargada de utilizando los ensamblados del Toolkit, de reconcer y luego pintar los puntos de la cara. Para esto se suscribe al evento [OnFrameReady] del sensor Kinect y en el mismo utiliza el Toolkit para obtener los puntos de la cara. Mejor ver un poco el código que es bastante autoexplicativo:

   1: internal void OnFrameReady(KinectSensor kinectSensor, ColorImageFormat colorImageFormat, 

   2:     byte[] colorImage, DepthImageFormat depthImageFormat, 

   3:     short[] depthImage, Skeleton skeletonOfInterest)

   4: {

   5:     _skeletonTrackingState = skeletonOfInterest.TrackingState;

   6:     if (_skeletonTrackingState != SkeletonTrackingState.Tracked)

   7:     {

   8:         return;

   9:     }

  10:  

  11:     if (_faceTracker == null)

  12:     {

  13:         try

  14:         {

  15:             _faceTracker = new FaceTracker(kinectSensor);

  16:         }

  17:         catch (InvalidOperationException)

  18:         {

  19:             Debug.WriteLine("AllFramesReady - creating a new FaceTracker threw an InvalidOperationException");

  20:             _faceTracker = null;

  21:         }

  22:     }

  23:  

  24:     if (_faceTracker == null) return;

  25:     var frame = _faceTracker.Track(colorImageFormat, colorImage, depthImageFormat, depthImage, skeletonOfInterest);

  26:     LastFaceTrackSucceeded = frame.TrackSuccessful;

  27:     if (!LastFaceTrackSucceeded) return;

  28:     if (_faceTriangles == null)

  29:     {

  30:         _faceTriangles = frame.GetTriangles();

  31:     }

  32:     _facePoints = frame.GetProjected3DShape();

  33: }

7. Esta clase posee otra función que es la que se encarga de dibujar la máscara sobre un canvas, donde están los puntos de la cara. Apartir de la colección de puntos, se crea un array de triángulos y se los pinta sobre un contexto de trabajo.

   1: public void DrawFaceModel(DrawingContext drawingContext)

   2: {

   3:     if (!LastFaceTrackSucceeded || _skeletonTrackingState != SkeletonTrackingState.Tracked)

   4:     {

   5:         _startFaceRecognition = DateTime.MinValue;

   6:         return;

   7:     }

   8:  

   9:     var faceModelPts = _facePoints.Select(t => new Point(t.X + 0.5f, t.Y + 0.5f)).ToList();

  10:  

  11:     var faceModel = _faceTriangles.Select(t => new FaceModelTriangle

  12:     {

  13:         P1 = faceModelPts[t.First],

  14:         P2 = faceModelPts[t.Second],

  15:         P3 = faceModelPts[t.Third]

  16:     }).ToList();

  17:  

  18:     var faceModelGroup = new GeometryGroup();

  19:     for (var i = 0; i < faceModel.Count; i++)

  20:     {

  21:         var faceTriangle = new GeometryGroup();

  22:         faceTriangle.Children.Add(new LineGeometry(faceModel[i].P1, faceModel[i].P2));

  23:         faceTriangle.Children.Add(new LineGeometry(faceModel[i].P2, faceModel[i].P3));

  24:         faceTriangle.Children.Add(new LineGeometry(faceModel[i].P3, faceModel[i].P1));

  25:         faceModelGroup.Children.Add(faceTriangle);

  26:     }

  27:  

  28:     drawingContext.DrawGeometry(Brushes.BlueViolet, new Pen(Brushes.Red, 1.0), faceModelGroup);

  29:     if (_startFaceRecognition == DateTime.MinValue)

  30:     {

  31:         _startFaceRecognition = DateTime.Now;

  32:     }

  33:     else

  34:     {

  35:         if (DateTime.Now.Subtract(_startFaceRecognition).TotalSeconds > 5)

  36:         {

  37:             Application.Current.Dispatcher.BeginInvoke(new Action(() =>

  38:             {

  39:                 System.Threading.Thread.Sleep(300);

  40:                 _startFaceRecognition = DateTime.MinValue;

  41:             }));

  42:         }

  43:     }

  44: }

8. Ahora pasamos al visor, que es el que “pinta” esto sobre una superficie [FaceTrackingViewer]. Dentro de la funcion [OnAllFramesReady] donde se procesan los datos del sensor Kinect, se identifica cada uno de los skeletons en un estado [SkeletonTrackingState.Tracked]. Una vez identificado, se crea una nueva instancia de la clase SkeletonFaceTracker y se ejecutan los pasos anteriores para identificar una cara/face. Cada instancia de SkeletonFaceTracker se almacena en una colección.

   1: foreach (Skeleton skeleton in this.skeletonData)

   2: {

   3:     if (skeleton.TrackingState == SkeletonTrackingState.Tracked

   4:         || skeleton.TrackingState == SkeletonTrackingState.PositionOnly)

   5:     {

   6:         if (!this.trackedSkeletons.ContainsKey(skeleton.TrackingId))

   7:         {

   8:             this.trackedSkeletons.Add(skeleton.TrackingId, new SkeletonFaceTracker() { });

   9:         }

  10:  

  11:         SkeletonFaceTracker skeletonFaceTracker;

  12:         if (this.trackedSkeletons.TryGetValue(skeleton.TrackingId, out skeletonFaceTracker))

  13:         {

  14:             if (this.Kinect != null)

  15:             {

  16:                 skeletonFaceTracker.OnFrameReady(this.Kinect, colorImageFormat, 

  17:                                     colorImage, depthImageFormat, depthImage, skeleton);

  18:                 skeletonFaceTracker.LastTrackedFrame = skeletonFrame.FrameNumber;

  19:             }

  20:         }

  21:     }

  22:  

  23: }

9. Finalmente en la función OnRender() del control, se “pinta” cada una de las caras.

   1: protected override void OnRender(DrawingContext drawingContext)

   2: {

   3:     base.OnRender(drawingContext);

   4:     foreach (var faceInformation in this.trackedSkeletons.Values)

   5:     {

   6:         faceInformation.DrawFaceModel(drawingContext);

   7:     }

   8: }

10. El ejemplo completo incluye un poco de código en la ventana principal para detectar el sensor kinect y trabajar con el mismo. Y otro par de detalles que comentaré en un next post.

El ejemplo se puede descargar desde http://sdrv.ms/MZY0Eq

 

Saludos @ La Finca

El Bruno

image image image

10 responses to “[#KINECT] HowTo: Utilizar Face Recognition con #KinectSdk (II)”

  1. loquesaledemicabeza Avatar
    loquesaledemicabeza

    Veo cortados los trozos de código Bruno… No se si le pasará a alguien más!
    Un saludo y buen post!

    Like

  2. […] [#KINECT] HowTo: Utilizar Face Recognition con #KinectSdk (II)https://elbruno.com/2012/08/07/kinect-howto-utilizar-face-recognition-con-kinectsdk-ii/ […]

    Like

  3. Hola Bruno!
    Al iniciar me da el siguiente error:
    Información adicional: No se puede cargar el archivo o ensamblado ‘Microsoft.Kinect.Toolkit.FaceTracking, Version=1.6.0.0, Culture=neutral, PublicKeyToken=null’ ni una de sus dependencias. Se ha intentado cargar un programa con un formato incorrecto.
    Ya cambié la configuración del proyecto para que compile en modo x86 y copié los dll
    Que puedo hacer?

    Like

    1. Diego buenas,
      eso es porque el ejemplo estaba compilado para el SDK 1.5. Lo mejor es que veas el ejemplo completo que viene en el Developer Toolkit, allí ya está todo compilado para 1.6 😀
      Saludos

      Like

  4. Hola Bruno! Estoy retomando el desarrollo en Kinect y tengo algunas dudas. Estoy tratando de medir la distancia entre ciertos puntos de la cara obtenidos con el FaceTracking. El inconveniente es que tomé medidas de diferentes personas, y todos devuelven resultados muy parecidos. La pregunta es, como podría hallar un parámetro único para cada rostro? Y así poder reconocer a una personas efectivamente.

    Like

    1. Puf que problema, yo creo que lo mejor que podrías hacer es una especie de Array con distancias entre los 6 puntos más significativos de la cara, creo que con 6 mediciones los valores deberían ser representativos. Si todavía son muy parecidos, pues a tomar más puntos … luego me cuentas que es muy interesante este acercamiento para identificar rostros !!!

      Saludos

      Like

  5. Buenos días Bruno,
    Me parece fantastico las posibilidades que ofrece kinect y el face tracking. No obstante no encuentro respuesta a mi pregunta un tanto simple viendo la potencia de la herramienta.
    Como puedo colocar una mascar 3D “estática” y simple cuando se detecte una cara???
    Me gustaría comenzar con un simple bigote, barba y sombrero. Esto lo puedo realizar con otros proveedores como T-inmersion donde sus modelos son 3d estáticos en un formato específico como*.obj.
    En este mundo kinect … que tipo de formato 3d puedo colocar como máscara?
    Muchas gracias por tu atencion.

    Like

    1. Buenas comodin

      pues la verdad que no sabría decirte como poner una máscara estática 3D en una app WPF. No soy un experto en WPF y mucho menos en modelados 3D.
      El Toolkit tiene varios ejemplos y uno de ellos agrega una proyección de la cara de la persona, lo puedes ver en http://kinectforwindowsorg, dentro de las descargas del Toolkit. El ejemplo es FaceTracking 3D-WPF (http://msdn.microsoft.com/en-us/library/jj131043) y tal vez pueda servirte como punto de partida.

      Saludos
      /Bruno

      Like

      1. comodin2002 Avatar
        comodin2002

        Gracias Elbruno,
        Es curioso pero encuentro mucho dificultad en tener una respuesta a mi pregunta. En Realidad Aumentada que estoy acostumbrado en sdk’s como Metaio o Dfusion los objetos 3D son estáticos y una vez trackeado los puntos claves de la cara superpone dicho elemento 3d.
        Aqui con la Kinect se dá un paso más allá y ahora resulta que la mascara es “dinámica”. Tan solo necesito saber poner un objeto 3d en pantalla en el lugar de la cara. Sabrías orientarme?
        Muchas gracias por tu ayuda

        Like

Leave a reply to Diego Cancel reply

Discover more from El Bruno

Subscribe now to keep reading and get access to the full archive.

Continue reading