26/4/2012 18:57 El Bruno

[#KINECTSDK] Kinect Missile Launcher (IV): Controlando el lanza misiles con Kinect

image

Buenas,

hoy ya vamos a crear una aplicación que nos permita controlar el lanza misiles utilizando gestos de Kinect. Para esto he pensado en los siguientes controles

  • La mano derecha controla la dirección del lanza misiles. Puede ir a la derecha, a la izquierda, arriba o abajo.
  • La mano izquierda controla el disparo del misil, la forma de disparar es levantar la mano encima de la cabeza.
  • Si ambos manos están por debajo de la cintura se detienen los movimientos del lanza misiles

Con esta base, y aprovechando los controles visuales de “Microsoft.Samples.Kinect.WpfViewers” he creado una aplicación WPF con el siguiente código en la ventana principal

   1: using System.Linq;
   2: using System.Windows;
   3: using Microsoft.Kinect;
   4:  
   5: namespace ElBruno.Rocket.Ui
   6: {
   7:     public partial class MainWindow
   8:     {
   9:         private KinectSensor _sensor;
  10:         private Rocket _rocket;
  11:         public MainWindow()
  12:         {
  13:             InitializeComponent();
  14:             Loaded += MainWindowLoaded;
  15:         }
  16:  
  17:         private void MainWindowLoaded(object sender, RoutedEventArgs e)
  18:         {
  19:             InitRocket();
  20:             InitKinectSensor();
  21:         }
  22:  
  23:         private void InitRocket()
  24:         {
  25:             _rocket = new Rocket(@"vid_0a81", @"pid_ff01");
  26:             _rocket.Connect();
  27:         }
  28:  
  29:         private void InitKinectSensor()
  30:         {
  31:             // validate
  32:             if (KinectSensor.KinectSensors.Count == 0) return;
  33:  
  34:             // init Kinect
  35:             var parameters = new TransformSmoothParameters
  36:                                  {
  37:                                      Smoothing = 0.75f,
  38:                                      Correction = 0.1f,
  39:                                      Prediction = 0.0f,
  40:                                      JitterRadius = 0.05f,
  41:                                      MaxDeviationRadius = 0.08f
  42:                                  };
  43:  
  44:             _sensor = KinectSensor.KinectSensors[0];
  45:             _sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
  46:             _sensor.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);
  47:             _sensor.SkeletonStream.Enable(parameters);
  48:             _sensor.Start();
  49:             colorViewer.Kinect = _sensor;
  50:             skeletonViewer.Kinect = _sensor;
  51:             _sensor.SkeletonFrameReady += SensorSkeletonFrameReady;
  52:         }
  53:  
  54:         private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
  55:         {
  56:             Skeleton[] skeletons = null;
  57:             using (var frame = e.OpenSkeletonFrame())
  58:             {
  59:                 if (frame != null)
  60:                 {
  61:                     skeletons = new Skeleton[frame.SkeletonArrayLength];
  62:                     frame.CopySkeletonDataTo(skeletons);
  63:                 }
  64:             }
  65:  
  66:             if (skeletons == null) return;
  67:  
  68:             foreach (var kinectRocketGestures in (
  69:                 from skeleton in skeletons
  70:                 where skeleton.TrackingState == SkeletonTrackingState.Tracked
  71:                 let headJoint = skeleton.Joints[JointType.Head]
  72:                 where headJoint.TrackingState != JointTrackingState.NotTracked
  73:                 select skeleton).Select(skeleton => new KinectRocketGestures(skeleton, _rocket)))
  74:             {
  75:                 var gesture = kinectRocketGestures.ValidateGestures();
  76:                 textBlockInformation.Text = gesture;
  77:             }
  78:         }
  79:     }
  80: }
Es importante tener en cuenta que esta ventana no posee casi nada de lógica interesante, solo inicia los sensores del Kinect y del lanza misiles y luego se suscribe a las notificaciones de actualización de skeleton.
En esta notificación (línea 54), se valida que el tracking del skeleton sea correcto y luego utilizamos una clase KinectRocketGestures que es la que hace un poco la magia entre Kinect y el lanza misiles.
El código de esta clase es el siguiente
   1: using Microsoft.Kinect;
   2:  
   3: namespace ElBruno.Rocket.Ui
   4: {
   5:     class KinectRocketGestures
   6:     {
   7:         private readonly Skeleton _skeleton;
   8:         private readonly Rocket _rocket;
   9:  
  10:         public KinectRocketGestures(Skeleton skeleton, Rocket rocket)
  11:         {
  12:             _skeleton = skeleton;
  13:             _rocket = rocket;
  14:         }
  15:  
  16:         public string ValidateGestures()
  17:         {
  18:             var gesture = @"Not defined";
  19:             // STOP
  20:             // Right hand and Left hand hanging at the side
  21:             if (_skeleton.Joints[JointType.HandRight].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y &&
  22:                 _skeleton.Joints[JointType.HandLeft].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y)
  23:             {
  24:                 _rocket.StopAll();
  25:                 _rocket.StopFiring();
  26:                 _rocket.StopMovements();
  27:                 gesture = @"STOP";
  28:                 return gesture;
  29:             }
  30:  
  31:             // FIRE
  32:             if (_skeleton.Joints[JointType.HandLeft].Position.Y > _skeleton.Joints[JointType.Head].Position.Y)
  33:             {
  34:                 gesture = @"FIRE";
  35:                 _rocket.FireOnce();
  36:             }
  37:  
  38:             // MOVE RIGHT OR LEFT
  39:             // Right hand in front of right shoulder
  40:             // Right hand below shoulder height but above hip height
  41:             if (
  42:                 (_skeleton.Joints[JointType.HandRight].Position.Z < _skeleton.Joints[JointType.ElbowRight].Position.Z &&
  43:                 _skeleton.Joints[JointType.HandLeft].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y)
  44:                 &&
  45:                 (_skeleton.Joints[JointType.HandRight].Position.Y < _skeleton.Joints[JointType.Head].Position.Y &&
  46:                 _skeleton.Joints[JointType.HandRight].Position.Y > _skeleton.Joints[JointType.HipCenter].Position.Y)
  47:                 )
  48:             {
  49:                 // Right hand right of right shoulder
  50:                 if (_skeleton.Joints[JointType.HandRight].Position.X > _skeleton.Joints[JointType.ShoulderRight].Position.X)
  51:                 {
  52:                     gesture = @"MOVE RIGHT";
  53:                     _rocket.MoveRight();
  54:                 }
  55:                 // Right hand left of left Shoulder
  56:                 if (_skeleton.Joints[JointType.HandRight].Position.X < _skeleton.Joints[JointType.ShoulderLeft].Position.X)
  57:                 {
  58:                     gesture = @"MOVE LEFT";
  59:                     _rocket.MoveLeft();
  60:                 }
  61:             }
  62:  
  63:             // MOVE UP OR DOWN
  64:             // Right hand in front of body with Left hand hanging at the side
  65:             // Right hand between shoulders
  66:             if (
  67:                 (_skeleton.Joints[JointType.HandRight].Position.Z < _skeleton.Joints[JointType.ShoulderCenter].Position.Z &&
  68:                 _skeleton.Joints[JointType.HandLeft].Position.Y < _skeleton.Joints[JointType.HipCenter].Position.Y)
  69:                 &&
  70:                 (_skeleton.Joints[JointType.HandRight].Position.X < _skeleton.Joints[JointType.ShoulderRight].Position.X &&
  71:                 _skeleton.Joints[JointType.HandRight].Position.X > _skeleton.Joints[JointType.ShoulderLeft].Position.X)
  72:                 )
  73:             {
  74:                 // Right hand above the shoulders
  75:                 if (_skeleton.Joints[JointType.HandRight].Position.Y > _skeleton.Joints[JointType.ShoulderCenter].Position.Y)
  76:                 {
  77:                     gesture = @"MOVE UP";
  78:                     _rocket.MoveUp();
  79:                 }
  80:                 // Right hand below the chest/gut
  81:                 if (_skeleton.Joints[JointType.HandRight].Position.Y < _skeleton.Joints[JointType.Spine].Position.Y)
  82:                 {
  83:                     gesture = @"MOVE DOWN";
  84:                     _rocket.MoveDown();
  85:                 }
  86:                 return gesture;
  87:             }
  88:         }
  89:     }
  90: }
 

Y listo! Un poco de validación de posiciones de la mano derecha y la mano izquierda y ya tenemos el control del lanza misiles utilizando Kinect.

Ahora me voy rápido al evento de MadridDotNet y en el próximo post pongo un video y el código de ejemplo de la aplicación.

Saludos @ La Finca

El Bruno

image image image
Archivado en: ,,
Comparte este post: