January 2011 - Artículos

Webcast MSDN: Conquistando el mundo con Kinect y C#Buenas,

Los amigos de SecondNug siguen poniendo desafíos de los complicados, esta vez la cita es el próximo martes 1 de Marzo, donde participaré en un evento para mostrar algunas de las capacidades actuales que tenemos para programar con C# nuestro Kinect.

El formato es WebCast así que veremos si las demos, salen bien; ya que hay que mostrar el código fuente, el input de la cámara del kinect, etc. y claro, agregaremos un poco de Microsoft Robotics para completar la sesión friki, con lanzamisiles incluido y si puedo algún robot Risa

Las demos las haré con C# 4.0 y Visual Studio 2010, así que después solo necesitas el Kinect y un Visual Studio Express para poder reproducirlas

Registro: https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032476184&Culture=es-AR

Saludos @ Córdoba.com.ar

El Bruno

   

image

Buenas,

el próximo miércoles 2 de febrero, nuestros amigos los MVPs de SharePoint compatirán una mesa redonda para hablar de temas relacionados con el desarrollo de aplicaciones y SharePoint. Si no los conoces, aquí tienes los nombres

Gustavo Velez. MVP SharePoint Server
Juan Carlos González. MVP SharePoint Server
David Martos. MVP SharePoint Server
Alberto Diaz. MVP SharePoint Server

y la verdad es que además del evento en vivo, podrás participar online del mismo. Yo aprovecharé los 10000 kms de distancia que me separan de Madrid para conectarme online y ver como es esto del mejor software del año para subir y bajar archivos.

 

Saludos @ Córdoba.com.ar

El Bruno

   

Referencia: http://madriddotnet.wordpress.com/2011/01/17/evento-desarrollo-en-sharepoint-para-desarrolladores-mortales-de-net/

image47dd1de4

Buenas,

hace un tiempo escribí un post con un ejemplo sobre como utilizar Moles para realizar pruebas unitarias de Tasks en MSBuild. Hoy como veo que Luis está por empezar a escribir una serie de posts de Moles y SharePoint, pues voy a terminar este post que tengo en los drafts desde hace un tiempo. Primero lo primero, Luis ya ha explicado qué es un Mock, qué es un Stub, desde donde se descarga Moles, etc.; así que vamos al trapo.

Esta clase me la he encontrado hace muy poco en un proyecto heredado, como pueden ver la utilidad de la misma es monstruosa, pero bueno la he limpiado un poco para que nos sirva para el post:

   1: using System;
   2: using System.Diagnostics;
   3:  
   4: namespace ElBruno
   5: {
   6:     public class Log
   7:     {
   8:         public void Write(string message)
   9:         {
  10:             if(string.IsNullOrWhiteSpace(message))
  11:                 throw  new ArgumentException("invalid message");
  12:             var traceListener = new ConsoleTraceListener();
  13:             traceListener.WriteLine(message);
  14:         }
  15:     }
  16: }

Esta clase es muy útil y si tenemos bien configurados los Listeners en la configuración de la aplicación, pues funcionará muy bien, pero el problema surge si queremos probar la misma. Ojo, que este caso es casi un “probar por probar” que solo sirve para subir la cobertura de código, si quieres ver un poco una forma inteligente de comprender como trabajar con la cobertura de código, pues @Rodrigo lo explica muy bien en este post.

Pues bien, supongamos que tenemos configurado los Trace Listeners para que escriban en un archivo de texto, si comenzamos a implementar el siguiente test, pues a partir de la línea 7 comenzaremos a plantearnos opciones para leer el archivo  de texto.

   1: [TestMethod]
   2: public void TestWriteLogWithSimpleString()
   3: {
   4:     const string message = "Valentino";
   5:     var log = new Log();
   6:     log.Write(message);
   7:     // ¿¿??¿¿??
   8: }
   9: [TestMethod, ExpectedException(typeof(ArgumentException))]
  10: public void TestWriteLogWithEmptyStringThrowArgumentException()
  11: {
  12:     const string message = "";
  13:     var log = new Log();
  14:     log.Write(message);
  15: }

Si luego cambiamos la configuración del Listener para que escriba en una cola de mensajes, en la consola, etc; pues la cosa se nos complica ya que nos alejamos de un test simple y rápido. Aquí es donde entra en juego nuestro amigo Moles, ya que con el mismo podemos crear un Mock que reemplace al Trace Listener original e implemente uno propio para nuestras pruebas.

Lo primero que deberemos hacer, es en el proyecto de pruebas en Visual Studio 2010, seleccionar el ensamblado sobre el que queremos trabajar, desplegar el menú contextual y seleccionar la opción [Add Moles Assembly]. En este caso y como no le tenemos miedo a nada estamos trabajando con Listeners, pues tenemos que generar un Moles del ensamblado System. Este proceso tarda unos segundos, y una ves finalizado el mismo, podremos ver un nuevo ensamblado en nuestra lista de referencia [System.Moles] que es el que permite trabajar con Mocks de System.

image

Ok, el primer paso está dado, ya hemos generado nuestros Moles ahora tenemos que trabajar con los mismos. Y es en este punto, donde comenzaremos a ver que el trabajar con pruebas unitarias, además de darnos un contrato de trabajo cerrado sobre las funcionalidades de nuestras aplicaciones, nos ayuda a implementar un diseño ágil que no acople elementos.

Por ejemplo, en nuestra clase Log tenemos que implementar un mecanismo que nos permita decidir el Listener con el que queremos trabajar. Puede ser el propio de System, o el creado por Moles para nuestros tests. Esto se logra desde los tiempos de mi abuela definiendo en el constructor los argumentos de trabajo (aquí tengo que recordarte los principios SOLID de diseño de objetos para que tampoco crees clases con constructores con 50 parámetros). Para este ejemplo rápido, nuestra clase puede quedar similar al siguiente código:

   1: using System;
   2: using System.Diagnostics;
   3:  
   4: namespace ElBruno
   5: {
   6:     public class Log
   7:     {
   8:         private readonly TraceListener _traceListener;
   9:         public Log()
  10:         {
  11:             _traceListener = new ConsoleTraceListener();
  12:         }
  13:         public Log(TraceListener traceListener)
  14:         {
  15:             _traceListener = traceListener;
  16:         }
  17:         public void Write(string message)
  18:         {
  19:             if(string.IsNullOrWhiteSpace(message))
  20:                 throw  new ArgumentException("invalid message");
  21:             _traceListener.WriteLine(message);
  22:         }
  23:     }
  24: }

 

Si volvemos a nuestro test podremos ver que en el mismo ya tenemos la capacidad de trabajar con los namespaces MOLES dentro de System. Además para cada tipo se ha creado uno nuevo con un prefijo “M” que es el tipo que intercepta y crea MOLES, por ejemplo:

image

Otro punto a tener en cuenta es que para cada uno de los métodos y sobrecargas que existen en la clase original, Moles crea una propiedad específica con la sobrecarga que nos permite implementar un delegado para la utilización de la misma.

image

 

Jo, lo he leído y suena a chino, mejor vamos al código que es lo que mejor se entiende:

   1: [TestMethod]
   2: public void TestWriteLogWithSimpleString()
   3: {
   4:     const string message = "Valentino";
   5:     var defaultTraceListener = new MDefaultTraceListener();
   6:     defaultTraceListener.BehaveAsDefaultValue();
   7:     defaultTraceListener.WriteString = (s) =>
   8:                          {
   9:                              Assert.AreEqual(message, s);
  10:                          };
  11:     var log = new Log(defaultTraceListener);
  12:     log.Write(message);
  13: }

 

Listo !!! no hace falta que explique el código, pero si quieres hay van un par de puntos a tener en cuenta:

  • En la línea 5 se crea el Listener implementado por MOLES
  • En la línea 6, se define que el comportamiento será el por defecto para este Listener salvo que se indique lo contrario
  • En la línea 7 se define el comportamiento de la función Write() y en la misma se evalúa el test para darle sentido al mismo
  • En la línea 11 se utiliza la clase de Log, pero con el constructor específico donde se le pasa la instancia de TraceListener

Más simple imposible … ahora quedo a la espera de los de SharePoint !!!

 

Saludos @ Rio IV

El Bruno

   

image47dd1de4

Buenas,

hoy le voy a dar un poco de promoción a una extensión gratis para Visual Studio 2010 que permite analizar las relaciones de un WorkItem gráficamente utilizando DGML. La misma se puede descargar desde la Visual Studio Gallery, en http://visualstudiogallery.msdn.microsoft.com/en-us/a35b6010-750b-47f6-a7a5-41f0fa7294d2

Una vez instalada, en el menú [Team] tendremos una nueva opción [Work Item Visualizer] que nos permitirá ingresar el número de un WorkItem y a partir de allí comenzar a pintarlo.

image

 

Si has leido mis posts de DGML o asistes al curso de Herramientas para Arquitectos, seguramente verás que esta extensión no es muy complicada de crear, pero eso si; si trabajas con TFS, es un must have a la hora de analizar relaciones.

image

Saludos @ Here

El Bruno

   

imageBuenas,

estaba por escribir un poco sobre el porqué de la necesidad de tener una katana/guillotina en un equipo de desarrollo para adoctrinar a las personas que rompen una Build, pero después de recibir 450^2 correos sobre los drivers de Kinect, aquí van algunos facts:

  • No existen drivers oficiales de Microsoft para Windows para Kinect.
  • Los posts que hablan de drivers oficiales nunca aclaran que son los de PrimeSense (inclusive alguno de los blogs de MSDN, pone esto en el título, una vergüenza en no aclarar)
  • Si existiesen drivers de Microsoft, en el proceso de detección de drivers, Windows Update sería el primero en recomendártelos
  • Existen otros drivers además de OpenNI, como por ejemplo los de CodeLaboratories.com (http://codelaboratories.com/nui)
  • Si has instalado un set de drivers y luego no los puedes quitar, desinstalar, etc. entra con mucho cuidado en [C:\Windows\System32\DriverStore\FileRepository] y empieza a jugar con fuego

Pero claro, hay de todo en la viña del señor, y por ejemplo aquí hay 2 noticias que pueden marearte:

Resumiendo:

  • PrimeSense, que es la empresa que se ha encargado de crear la rutinas internas del Kinect para la detección de bodies, gestures, etc. ; libera los drivers en OpenNI para Windows, Mac y Linux.
  • Estos drivers NO SON DE MICROSOFT, son de PrimeSense y recién ahora están estables.
  • Si te descargas un set de drivers y no te funcionan, pues preparate para jugar con fuego
  • No todos los drivers soportan toda las características que provee Kinect como dispositivo: acelerómetro, motor, webcams, infrarojos, micrófono.

Si tienes dudas yo no tengo problemas en responder un correo. Ahora bien, dependiendo del tono del correo, tampoco tengo problemas en borrar el mismo o agregarte rápidamente a la carpeta de SPAM Risa

 

Saludos @ Rio IV.com.ar

El Bruno

   

Publicado 16/1/2011 19:15 por El Bruno | 6 comment(s)
Archivado en: ,

image47dd1de4

Buenas,

como no me traje el kinect, pero si mucho material para seguir escribiendo el libro, pues hoy toca un post light antes de destripar un poco de Moles. En este caso comentar la mención de Visual Studio 2010 como mejor herramienta del año por InfoWorld en la categoría [Best IDE (non-Java)].

Personalmente pienso que Visual Studio 2010 es una excelente herramienta, y lamentablemente no he tenido el tiempo de probar aotras herramientas a fondo para compararla. Tampoco pienso que una persona que solo sabe hacer demos de hola mundo en varios lenguajes y varios IDEs tenga capacidad para evaluar los mismos, ya que cuando trabajas a fondo con una herramienta es cuando podes comenzar a evaluar la misma.

Disclaimer: aquí seguro que entra alguno diciendo que el IDE es lento, que consume muchos recursos, etc. Pues la solución es 8GB de RAM, un disco rápido y una buena placa gráfica, sino … pues picar código PHP en el notepad.

Pero bueno, si te dan un premio siempre es bueno recibirlo, y si la categoría es NON-JAVA mejor aún Lengua fuera

 

Saludos @ Rio IV

El Bruno

   

Fuente: http://www.infoworld.com/d/infoworld/infoworlds-2011-technology-the-year-award-winners-285&current=15

image

imageBuenas,

hoy es día de poca inspiración, así que toca una recopilación de los posts que explican como trabajar con Kinect y C#. Hasta ahora he cubierto las acciones más básicas para realizar utilizando Managed Nite de PrimeSense, como detectar un círculo o la posición de una mano.

Si quieres ver el código fuente de todas las aplicaciones en una única solución, te lo puedes descargar desde

Y recuerda que las 2 bases para los drivers se basan en

Saludos @ Home

El Bruno

   

image

Buenas,

después de ver cómo capturar diferentes gestos con C# utilizando Kinect (Wave, Circle, Push, Swipe), hoy vamos a utilizar la clase XnMSelectableSlider2D para detectar la posición de una mano una vez iniciada una sesión en Kinect. Como siempre el código es bastante auto descriptivo, ya que una vez instanciada la clase, el evento Slider2DItemHovered() nos brinda un parámetro con la posición X e Y de la mano en cuestión (línea 48).

En este evento y para que la demo no sea tan aburrida, además de mostrar la posición en la consola de pruebas, decidí utilizar la función SetCursorPos de la dll user32.dll para mover el cursor siguiendo los movimientos de la mano. Para esto importé la dll (línea 11) y luego la utilizo en el evento Slider2DItemHovered() para mover el cursor.

Un detalle que podrán ver en el video de demo, los valores del eje X son válidos para mover el cursor horizontalmente, pero para el eje Y, cuando subes o bajas la mano, los valores son inversos, con lo que el mouse no hace lo que debería. Arreglar esto son 5 minutos, pero no quiero “ensuciar” el código … además aquí está la oportunidad de trabajar un poco con este caso Risa

Y por último, la clase XnMSelectableSlider2D en su constructor recibe un valor para X e Y, con el que arma la escala para los valores que se brindan en el evento Slider2DItemHovered(); yo le he pasado la resolución de mi Screen para tener valores coherentes, pero lo recomendable es adaptar estos valores a cada caso.

Este es el código del ejemplo:

   1: using System;
   2: using System.Runtime.InteropServices;
   3: using System.Threading;
   4: using System.Windows;
   5: using ManagedNite;
   6:  
   7: namespace HandTracking
   8: {
   9:     class Program
  10:     {
  11:         [DllImport("user32.dll", SetLastError = true)]
  12:         [return: MarshalAs(UnmanagedType.Bool)]
  13:         public static extern bool SetCursorPos(int x, int y);
  14:  
  15:         private static XnMOpenNIContext _context;
  16:         private static XnMSessionManager _sessionManager;
  17:         private static XnMSelectableSlider2D _slider2D;
  18:         private static Thread _readerThread;
  19:         private static bool _shouldRun;
  20:  
  21:         static void Main()
  22:         {
  23:             Console.WriteLine("Iniciando acceso a Kinect ...");
  24:             _shouldRun = true;
  25:  
  26:             InitSensorInteraction();
  27:             InitThreadReader();
  28:  
  29:             Console.WriteLine("Kinect online. Saluda para comenzar");
  30:             Console.ReadLine();
  31:             _shouldRun = false;
  32:         }
  33:  
  34:  
  35:         #region Sensor Interaction
  36:         private static void InitSensorInteraction()
  37:         {
  38:             _context = new XnMOpenNIContext();
  39:             _context.Init();
  40:  
  41:             _sessionManager = new XnMSessionManager(_context, "Wave", "RaiseHand");
  42:             _slider2D = new XnMSelectableSlider2D((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight);
  43:             _slider2D.ItemHovered += Slider2DItemHovered;
  44:             
  45:             _sessionManager.AddListener(_slider2D);
  46:         }
  47:  
  48:         static void Slider2DItemHovered(object sender, SelectableSlider2DHoverEventArgs e)
  49:         {
  50:             Console.WriteLine("X: " + e.X + " Y: " + e.Y);
  51:             SetCursorPos(e.X, e.Y);
  52:         }
  53:  
  54:         #endregion
  55:  
  56:         #region Update Thread
  57:         private static void InitThreadReader()
  58:         {
  59:             _readerThread = new Thread(ReaderThread);
  60:             _readerThread.Start();
  61:         }
  62:         private static void ReaderThread()
  63:         {
  64:             while (_shouldRun)
  65:             {
  66:                 var rc = _context.Update();
  67:                 if (rc == 0)
  68:                     _sessionManager.Update(_context);
  69:             }
  70:         }
  71:         #endregion
  72:     }
  73: }

El código lo pueden descargar desde

Saludos @ Home

El Bruno

   

image

Buenas,

si has visto Minority Report, seguramente te habrás dado cuenta que unas de las acciones más usuales que podemos hacer con la mano es un SWIPE (que es algo así como darle una cachetada/bofetada al aire). Pues bien, utilizando OpenNI y ManagedNite podemos capturar este tipo de acciones con la clase XnMSwipeDetector. La misma nos permite capturar una acción de SWIPE, y además ver la dirección de la misma (Left, Right, Top, Down) y otros valores como el ángulo y la velocidad del SWIPE. El siguiente video muestra un ejemplo de la captura del Kinect y de la captura de acciones de SWIPE.

Disclaimer: si no queres que te queden los ojos como las cámaras del kinect, te recomiendo ver el video FullScreen en alta definición.

 

El siguiente código es el ejemplo de la aplicación de consola. En la misma podemos ver como desde las líneas 44 a 67 se capturan los eventos del tipo SWIPE y se muestra la información de los mismos. Un detalle a tener en cuenta es que si bien existe un evento llamado GeneralSwipe, en el que se capturan todos los tipos de Swipe, el mismo no brinda información sobre la velocidad y el ángulo del SWIPE, para acceder a esta información es necesario capturar los 4 tipos diferentes de SWIPE en sus eventos correspondientes.

   1: using System;
   2: using System.Threading;
   3: using ManagedNite;
   4:  
   5: namespace DetectingSwipe
   6: {
   7:     class Program
   8:     {
   9:         private static XnMOpenNIContext _context;
  10:         private static XnMSessionManager _sessionManager;
  11:         private static XnMSwipeDetector _swipeDetector;
  12:         private static Thread _readerThread;
  13:         private static bool _shouldRun;
  14:  
  15:         static void Main()
  16:         {
  17:             Console.WriteLine("Iniciando acceso a Kinect ...");
  18:             _shouldRun = true;
  19:  
  20:             InitSensorInteraction();
  21:             InitThreadReader();
  22:  
  23:             Console.WriteLine("Kinect online. Saluda para comenzar");
  24:             Console.ReadLine();
  25:             _shouldRun = false;
  26:         }
  27:  
  28:         #region Sensor Interaction
  29:         private static void InitSensorInteraction()
  30:         {
  31:             _context = new XnMOpenNIContext();
  32:             _context.Init();
  33:  
  34:             _sessionManager = new XnMSessionManager(_context, "Wave", "RaiseHand");
  35:             _swipeDetector = new XnMSwipeDetector();
  36:             _swipeDetector.SwipeDown +=SwipeDetectorSwipeDown;
  37:             _swipeDetector.SwipeLeft += SwipeDetectorSwipeLeft;
  38:             _swipeDetector.SwipeRight += SwipeDetectorSwipeRight;
  39:             _swipeDetector.SwipeUp += SwipeDetectorSwipeUp;
  40:             _swipeDetector.GeneralSwipe += SwipeDetectorGeneralSwipe;
  41:             _sessionManager.AddListener(_swipeDetector);
  42:         }
  43:  
  44:         static void SwipeDetectorGeneralSwipe(object sender, SwipeDetectorGeneralEventArgs e)
  45:         {
  46:             Console.WriteLine("General Swipe. Direction: {0} Angle: {1} Velocity: {2}", e.SelectDirection, e.Angle, e.Velocity);
  47:         }
  48:  
  49:         static void SwipeDetectorSwipeUp(object sender, SwipeDetectorEventArgs e)
  50:         {
  51:             Console.WriteLine("SwipeUp. Angle: {0} Velocity: {1}", e.Angle, e.Velocity);
  52:         }
  53:  
  54:         static void SwipeDetectorSwipeRight(object sender, SwipeDetectorEventArgs e)
  55:         {
  56:             Console.WriteLine("SwipeRight. Angle: {0} Velocity: {1}", e.Angle, e.Velocity);
  57:         }
  58:  
  59:         static void SwipeDetectorSwipeLeft(object sender, SwipeDetectorEventArgs e)
  60:         {
  61:             Console.WriteLine("SwipeLeft. Angle: {0} Velocity: {1}", e.Angle, e.Velocity);
  62:         }
  63:  
  64:         static void SwipeDetectorSwipeDown(object sender, SwipeDetectorEventArgs e)
  65:         {
  66:             Console.WriteLine("SwipeDown. Angle: {0} Velocity: {1}", e.Angle, e.Velocity);
  67:         }
  68:  
  69:  
  70:         #endregion
  71:  
  72:         #region Update Thread
  73:         private static void InitThreadReader()
  74:         {
  75:             _readerThread = new Thread(ReaderThread);
  76:             _readerThread.Start();
  77:         }
  78:         private static void ReaderThread()
  79:         {
  80:             while (_shouldRun)
  81:             {
  82:                 var rc = _context.Update();
  83:                 if (rc == 0)
  84:                     _sessionManager.Update(_context);
  85:             }
  86:         }
  87:         #endregion
  88:     }
  89: }

 

Como siempre el código de la aplicación se puede descargar desde –> http://cid-bef06dffdb192125.office.live.com/self.aspx/Code%20Samples/2011%2001%2009%20Kinect%20DetectingSwipe.zip

 

Saludos @ Home

El Bruno

   

image

Buenas,

hoy también toca un post cortito que estamos en reyes y ya falta menos para poner la demo completa este fin de semana. Hoy veremos como utilizando la clase XnMCircleDetector podremos detectar cuando una vez detectada una mano en Kinect, la misma hace un círculo. Entre los valores que podemos analizar del círculo, los más útiles son la ubicación del punto central del círculo y el radio del mismo.

Como siempre, el código de ejemplo:

   1: using System;
   2: using System.Threading;
   3: using ManagedNite;
   4:  
   5: namespace DetectingPush
   6: {
   7:     class Program
   8:     {
   9:         private static XnMOpenNIContext _context;
  10:         private static XnMSessionManager _sessionManager;
  11:         private static XnMCircleDetector _circleDetector;
  12:         private static Thread _readerThread;
  13:         private static bool _shouldRun;
  14:  
  15:         static void Main()
  16:         {
  17:             Console.WriteLine("Iniciando acceso a Kinect ...");
  18:             _shouldRun = true;
  19:  
  20:             InitSensorInteraction();
  21:             InitThreadReader();
  22:  
  23:             Console.WriteLine("Kinect online. Saluda para comenzar");
  24:             Console.ReadLine();
  25:             _shouldRun = false;
  26:         }
  27:  
  28:         #region Sensor Interaction
  29:         private static void InitSensorInteraction()
  30:         {
  31:             _context = new XnMOpenNIContext();
  32:             _context.Init();
  33:  
  34:             _sessionManager = new XnMSessionManager(_context, "Wave", "RaiseHand");
  35:             _circleDetector = new XnMCircleDetector();
  36:             _circleDetector.Circle += CircleDetectorCircle;
  37:             _sessionManager.AddListener(_circleDetector);
  38:         }
  39:  
  40:         static void CircleDetectorCircle(object sender, CircleEventArgs e)
  41:         {
  42:             Console.WriteLine("Circle Center: {0}", GetPointData(e.CircleCenter));
  43:             Console.WriteLine("CircleRadius: {0}", e.CircleRadius);
  44:             Console.WriteLine("Confident: {0}", e.Confident);
  45:             Console.WriteLine("Value: {0}", e.Value);
  46:         }
  47:  
  48:         private static string GetPointData(XnMPoint point)
  49:         {
  50:             return string.Format("X: {0} Y: {1} Z: {2}", point.X, point.Y, point.Z);
  51:         }
  52:  
  53:         #endregion
  54:  
  55:         #region Update Thread
  56:         private static void InitThreadReader()
  57:         {
  58:             _readerThread = new Thread(ReaderThread);
  59:             _readerThread.Start();
  60:         }
  61:         private static void ReaderThread()
  62:         {
  63:             while (_shouldRun)
  64:             {
  65:                 var rc = _context.Update();
  66:                 if (rc == 0)
  67:                     _sessionManager.Update(_context);
  68:             }
  69:         }
  70:         #endregion
  71:     }
  72: }

 

Y el proyecto para descargar desde aquí: http://cid-bef06dffdb192125.office.live.com/self.aspx/Code%20Samples/2011%2001%2006%20Kinect%20DetectingCircle.zip

 

Saludos @ Home

El Bruno

   

image

Buenas,

si hace dos días leiste mi post sobre como deterctar un WAVE en Kinect, este post te resultará fácil de leer; si no lo has leido … pues ya le estás dando click al post viejuno aquí.

Como puedes ver en el siguiente ejemplo de código, para detectar acciones de Push, es posible utilizar un objeto del tipo XnMPushDetector, el mismo dispara un evento Push (línea 40) que no indica que se ha producido una acción de PUSH y además un par de datos relativos al mismos, como por ejemplo el ángulo y la velocidad del PUSH.

 

   1: using System;
   2: using System.Threading;
   3: using ManagedNite;
   4:  
   5: namespace DetectingPush
   6: {
   7:     class Program
   8:     {
   9:         private static XnMOpenNIContext _context;
  10:         private static XnMSessionManager _sessionManager;
  11:         private static XnMPushDetector _pushDetector;
  12:         private static Thread _readerThread;
  13:         private static bool _shouldRun;
  14:  
  15:         static void Main()
  16:         {
  17:             Console.WriteLine("Iniciando acceso a Kinect ...");
  18:             _shouldRun = true;
  19:  
  20:             InitSensorInteraction();
  21:             InitThreadReader();
  22:  
  23:             Console.WriteLine("Kinect online. Saluda para comenzar");
  24:             Console.ReadLine();
  25:             _shouldRun = false;
  26:         }
  27:  
  28:         #region Sensor Interaction
  29:         private static void InitSensorInteraction()
  30:         {
  31:             _context = new XnMOpenNIContext();
  32:             _context.Init();
  33:  
  34:             _sessionManager = new XnMSessionManager(_context, "Wave", "RaiseHand");
  35:             _pushDetector = new XnMPushDetector();
  36:             _pushDetector.Push += PushDetectorPush;
  37:             _sessionManager.AddListener(_pushDetector);
  38:         }
  39:  
  40:         static void PushDetectorPush(object sender, PushDetectorEventArgs e)
  41:         {
  42:             Console.WriteLine("Angle: {0}", e.Angle);
  43:             Console.WriteLine("Velocity: {0}", e.Velocity);
  44:         }
  45:  
  46:         #endregion
  47:  
  48:         #region Update Thread
  49:         private static void InitThreadReader()
  50:         {
  51:             _readerThread = new Thread(ReaderThread);
  52:             _readerThread.Start();
  53:         }
  54:         private static void ReaderThread()
  55:         {
  56:             while (_shouldRun)
  57:             {
  58:                 var rc = _context.Update();
  59:                 if (rc == 0)
  60:                     _sessionManager.Update(_context);
  61:             }
  62:         }
  63:         #endregion
  64:     }
  65: }

Además, la clase XnMPushDetector permite configurar la acción de PUSH a detectar, indicando el intervalo mínimo de acción, el ángulo, etc. En el próximo post, veremos una acción más antes de pasar a un ejemplo mas completo, con seguimiento de mano y acciones asociadas.

 

El ejemplo de código se puede descargar desde aquí http://cid-bef06dffdb192125.office.live.com/self.aspx/Code%20Samples/2011%2001%2005%20Kinect%20DetectingPush.zip

 

Saludos @ Home

El Bruno

   

image47dd1de4

Buenas,

hace bastante tiempo comenté un truco la configuración necesaria para poder utilizar TFSBuild para ejecutar pruebas unitarias en proyectos del tipo AddIn de Outlook. Hoy, 2 años después mi recomendación sigue siendo la misma:

No incluyas lógica compleja en tu proyecto de AddIn. Separa la misma en proyectos separados y cada uno con su set de pruebas … etc. Vamos que sigue siendo SOLID al 100%.

Ahora bien, si por algún motivo extraño de la vida, te encuentras en un escenario donde las clases con la “lógica compleja” deben estar dentro del proyecto del AddIn y la prueba unitaria de las mismas es un tanto compleja (por ejemplo para AddIns de Office 2003 con Visual Studio 2008), pues existe un truco que no recomiendo, pero que cumple su objetivo.

Lo mejor es mostrarlo con un proyecto de ejemplo, como en la siguiente imagen donde podemos ver un proyecto de AddIn para Outlook con una clase llamada [GuidValidator] que obviamente nos permite validar un Guid.

Nota: pa los criticones, si no les gustan los nombres de las clases, pues … a leer otra cosa !!!

image

 

El código para validar el guid tampoco es que sea muy complicado:

   1: using System.Text.RegularExpressions;
   2:  
   3: namespace OutlookAddIn1
   4: {
   5:     class GuidValidator
   6:     {
   7:         public static bool Validate(string textToValidate)
   8:         {
   9:             var isGuid = new Regex(
  10:               @"^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$", 
  11:               RegexOptions.Compiled);
  12:             return isGuid.IsMatch(textToValidate);
  13:         }
  14:     }
  15: }

 

Pero claro, probar unitariamente algo tan simple como una expresión regular utilizando todo el contexto de un AddIn de Outlook, es muy pesado. La solución nos la pueden dar los siguientes pasos.

1. Agregar un nuevo proyecto del tipo ClassLibrary a la solución. En mi caso lo llamaré [AddInToTest]

2. Eliminar la clase que viene por defecto en el proyecto.

3. En las propiedades del proyecto cambiar el namespace por defecto del proyecto ClassLibrary para que coincida con el namespace por defecto del proyecto del AddIn

4. Agregar como link la clase [GuidValidator] ubicada en el proyecto del AddIn

5. Agregar los tests unitarios de la clase [GuidValidator] en un proyecto de test separado

La estructura de la solución queda similar a la siguiente.

image

En la misma es posible ver que si bien la clase [GuidValidator] pertenece al proyecto [OutlookAddIn1], la misma se utiliza como archivo externo en el proyecto [AddInToTest] y se implementan las pruebas en el proyecto de test [AddIn.Tests].

El truco es bastante simple, poco elegante, pero funciona. Si quieres descargar el código de ejemplo para darle un vistazo lo puedes hacer desde aquí

http://cid-bef06dffdb192125.office.live.com/self.aspx/Code%20Samples/2011%2001%2004%20Hack%20to%20unit%20testing%20Outlook%20AddIns.zip

 

 

Saludos @ Home

El Bruno

   

image

Buenas,

después del primer post sobre como hacer un Hola Mundo para Kinect con C#, hoy toca trabajar con la gesture más conocida –> WAVE, que no es otra que el saludo a Kinect. Para este tutorial crearemos una aplicación de consola como en el primer post, pero con algunos cambios sobre el mismo.

Tutorial

1. Crear una aplicación de Consola que permita trabajar con Kinect, para esto es necesario repetir los pasos del 1 al 6 del primer post. En este caso la aplicación se llamará DetectingWave.

2. En la misma agregaremos el siguiente código:

   1: using System;
   2: using System.Threading;
   3: using ManagedNite;
   4:  
   5: namespace DetectingWave
   6: {
   7:     class Program
   8:     {
   9:         private static XnMOpenNIContext _context;
  10:         private static XnMSessionManager _sessionManager;
  11:         private static XnMWaveDetector _waveDetector;
  12:         private static Thread _readerThread;
  13:         private static bool _shouldRun;
  14:  
  15:         static void Main()
  16:         {
  17:             Console.WriteLine("Iniciando acceso a Kinect ...");
  18:             _shouldRun = true;
  19:  
  20:             InitSensorInteraction();
  21:             InitThreadReader();
  22:  
  23:             Console.WriteLine("Kinect online. Saluda para comenzar");
  24:             Console.ReadLine();
  25:             _shouldRun = false:
  26:         }
  27:  
  28:         #region Sensor Interaction
  29:         private static void InitSensorInteraction()
  30:         {
  31:             _context = new XnMOpenNIContext();
  32:             _context.Init();
  33:  
  34:             _sessionManager = new XnMSessionManager(_context, "Wave", "RaiseHand");
  35:             _waveDetector = new XnMWaveDetector();
  36:             _waveDetector.Wave += WaveDetectorWave;
  37:             _sessionManager.AddListener(_waveDetector);
  38:         }
  39:  
  40:         private static void WaveDetectorWave(object sender, EventArgs e)
  41:         {
  42:             Console.WriteLine("WAVE detected");
  43:         }
  44:         #endregion
  45:  
  46:         #region Update Thread
  47:         private static void InitThreadReader()
  48:         {
  49:             _readerThread = new Thread(ReaderThread);
  50:             _readerThread.Start();
  51:         }
  52:         private static void ReaderThread()
  53:         {
  54:             while (_shouldRun)
  55:             {
  56:                 var rc = _context.Update();
  57:                 if (rc == 0)
  58:                     _sessionManager.Update(_context);
  59:             }
  60:         }
  61:         #endregion
  62:     }
  63: }

 

3. En este ejemplo para la detección de un WAVE, utilizando una clase especial llamada XnMWaveDetector (línea 35)

4. La misma se agrega como un listener a la session de trabajo con Kinect (línea 37)

5. Cuando se inicia la session y se detecta un WAVE se lanza el evento definido en la línea 40.

 

Como pueden ver es muy fácil, ya que las APIs exponen esta funcionalidad de una forma muy natural.

El código de este ejemplo lo pueden descargar desde http://cid-bef06dffdb192125.office.live.com/self.aspx/Code%20Samples/2011%2001%2003%20Kinect%20DetectingWave.zip

 

 

Saludos @ Home

El Bruno

   

image

Buenas,

ayer me llegó el correo renovándome como MVP por 4to año. Este año nos han cambiado de categoría, ya que no existe más MVP Team System, sino que es MVP ALM. Independientemente de la categoría, yo seguiré

Y ahora los Disclaimers:

1. Sorry por la mala calidad del video, tengo que conseguirme una cámara buena para poder filmar un escenario con personas + Kinect + proyector ya que lo que filma la sony sale bastante mal … pero a que mola controlar un ordenador con “las manos”. Risa

2. Perdón por el “poco pulso” para poder tener una filmación, tuve que bajar la intensidad de las luces y eso al Kinect le gusta más bien poco Risa

 

En los próximos días, subiré el código fuente y explicaré como funciona la aplicación.

 

Saludos @ Home

El Bruno

   

PD: Home page

image

 

Thanks for the support on OpenNI forums: http://groups.google.com/group/openni-dev