.Net

Kinect y PowerPoint (I) – Controla PowerPoint con gestos

5

Estás cansado de las típicas presentaciones en PowerPoint? Vamos a ver una forma de hacer tus presentaciones mucho más atractivas, más vistosas y atrayentes con lo que captarás un mayor interés en tus asistentes.

Desde SolidQ se nos ocurrió la idea de mejorar las presentaciones, ¿y cómo las mejoramos? Pues utilizando Kinect y mediante gestos controlar tus presentaciones de PowerPoint!!

Antes que nada, cómo funciona Kinect? Vamos a ver unos conceptos básicos sobre el funcionamiento de Kinect.

Es un dispositivo que combina una cámara RGB (2) , un sensor de profundidad (1 y 3) y un array de micrófonos en la parte inferior. La cámara RGB es para el reconocimiento de los tres colores básicos y es la que nos da las imágenes, la cámara RGB tiene una resolución de 640×480 píxeles lo que todavía no nos permite que nos detecte los dedos, pero esperamos que en versiones futuras de aumente esta resolución y tengamos muchas más posibilidades. El sensor de profundidad que permite ver una habitación en 3D, emite unos rayos infrarrojos que marca líneas de profundidad, esto permite calcular el tiempo que tarda en rebotar el haz de luz y volver al dispositivo para calcular la distancia al objeto identificado. El array de micrófonos detecta las voces y las aísla del ruido ambiental, el array está sincronizado con la consola para eliminar el sonido de los juegos.

 

image

 

El software de Kinect está basado en tecnología de Inteligencia Artificial, lo que permite analizar, procesar y aprender por sí misma como está constituido el cuerpo humano y la forma de moverse. Cuando nos situamos enfrente de Kinect, lo que hace es emitir millones de haces de luz y detecta las partes humanoides separándolas del fondo.

image

 

El proceso de identificación del esqueleto (Skeleton) tiene varias fases, primero obtiene datos del mapa de profundidad mediante los rayos infrarrojos, identifica el suelo y separa los objetos del fondo (calibración de Kinect). Después identifica si hay uno o dos jugadores (por ahora reconoce máximo 2). Una vez identificado el cuerpo humano clasifica las diferentes partes del cuerpo para obtener las partes del cuerpo, Joints o articulaciones, y finalmente mediante la unión de los Joints crea el Skeleton.

image

 

El Skeleton se forma en base a 32 puntos del cuerpo humano (tobillos, rodillas, caderas, estomago, hombros, codos, manos, etc). Todo este proceso se conoce como Skeletal tracking, es el algoritmo por el cual se consigue identificar las diferentes partes del cuerpo.

image

 

Ahora ya tenemos una idea mucho más clara como funciona Kinect, vamos ahora ver cómo vamos a controlar las presentaciones de PowerPoint mediante gestos utilizando Kinect.

Lo primero, bajarse los drivers de Kinect, ya en beta 2. El código siguiente está desarrollado utilizando ya la beta 2 del SDK oficial de Kinect.

Creamos un proyecto WPF. Agregamos la referencia a la librería de Kinect que se encuentra en:

C:\Program Files\Microsoft SDKs\Kinect\v1.0 Beta2\Assemblies\Microsoft.Research.Kinect.dll

En la ventana principal, en el código xaml, añadimos una componente para poder ver nuestra imagen a través de la cámara RGB de Kinect.

<Viewbox Stretch="Uniform">

    <StackPanel>

        <Grid>

            <Image Name="videoImage"

                   Width="640"

                   Height="480"

                   VerticalAlignment="Bottom">

            </Image>

        </Grid>

    </StackPanel>

</Viewbox>

En el constructor de nuestra clase inicializamos el componente y cargamos el método Loaded.
 
public MainWindow()

{

    InitializeComponent();

    this.Loaded += new RoutedEventHandler(MainWindow_Loaded);

}

 

Y en el método Loaded añadimos la opción de usar Skeletal Tracking, la profundidad (depth)  y el evento SkeletonFrameReady, este método es el principal de nuestro proyecto Kinect, y se estará ejecutando continuamente en busca de nuevos gestos y movimiento del usuario.
void MainWindow_Loaded(object sender, RoutedEventArgs e)

{    

    if (Runtime.Kinects.Count == 0)        

        this.Title = "No kinect connected";    

    else    

    {        

        runtime = Runtime.Kinects[0];        

        runtime.Initialize(Microsoft.Research.Kinect.Nui.RuntimeOptions.UseColor | RuntimeOptions.UseSkeletalTracking | RuntimeOptions.UseDepth);    

        runtime.VideoFrameReady += runtime_VideoFrameReady;        

        runtime.SkeletonFrameReady += runtime_SkeletonFrameReady;            

        //Aqui ajustamos la resolución        

        runtime.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);        

        runtime.NuiCamera.ElevationAngle = 0;            

        //Método para activar el reconocimiento de voz        

        StartSpeechRecognition();

    }

}

En el método VideoFrameready, mostramos nuestro video sobre el componente de video que nos creamos con el código xaml:

void runtime_VideoFrameReady(object sender, Microsoft.Research.Kinect.Nui.ImageFrameReadyEventArgs e)

{    

    PlanarImage image = e.ImageFrame.Image;    

    BitmapSource source = BitmapSource.Create(image.Width, image.Height, 96, 96,PixelFormats.Bgr32, null, image.Bits, image.Width * image.BytesPerPixel);    

    videoImage.Source = source;

}

Como hemos dicho el método SkeletonFrameReady, es el que va a estar captando los movimiento y gestos del usuario, por lo que este método es el principal, crearemos los Joints que queramos utilizar y llamaremos a un método externo “GestoAvanceAtras” quien analizará los gestos.

void runtime_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)

{    

    SkeletonFrame skeletonSet = e.SkeletonFrame;    

    SkeletonData data;    

    try    

    {        

        data = data = (from s in skeletonSet.Skeletons  

        where s.TrackingState == SkeletonTrackingState.Tracked 

        select s).FirstOrDefault();        

        var head = data.Joints[JointID.Head];        

        var rightHand = data.Joints[JointID.HandRight];        

        var leftHand = data.Joints[JointID.HandLeft];        

        var rightShoulder = data.Joints[JointID.ShoulderRight];        

        var leftShoulder = data.Joints[JointID.ShoulderLeft];        

        GestoAvanceAtras(head, rightHand, leftHand, leftShoulder, rightShoulder);    

    }    

    catch (NullReferenceException error)    

    {        

        Console.WriteLine(error.Message);    

    }

}

Vamos a ver el gesto Swipe, o desplazamiento horizontal. Vamos a tener:

Avanzar en diapositivas: mano derecha, desplazamiento de derecha a izquierda.

image

Retroceder en diapositivas: mano izquierda, desplazamiento de izquierda a derecha.

image

En el código anterior vimos como llamábamos al método GestoAvanceAtras, vamos a ver el código más abajo de dicho método. Antes de eso, vamos a declararnos unas variables que nos servirán para recoger la posición de la mano izquierda, y de la mano derecha. Y unas variables que utilizaremos para el método de Swipe, con las que controlaremos el tiempo mínimo y máximo del gesto, y también la diferencia de altura que puede tener el movimiento, es decir, con esto controlamos que el movimiento sea horizontal.

public struct Vector3

{    

    public float X;   

    public float Y;    

    public float Z;    

    public DateTime date;

 }

 public enum Gesture

 {    

     None,    

     Swipe

 }

 List<Vector3> positionListRight = new List<Vector3>();

 List<Vector3> positionListLeft = new List<Vector3>();

 List<Gesture> gestureAcceptedList = new List<Gesture>();

 const float SwipeMinimalLength = 0.4f; //longitud máxima del movimiento swipe

 const float SwipeMaximalHeight = 0.1f; //altura máxima del movimiento desde inicio hasta fin

 const int SwipeMinimalDuration = 200; //en ms

 const int SwipeMaximalDuration = 500; //ms

 DateTime lastGestureDate = DateTime.Now;

 int MinimalPeriodBetweenGestures = 0; //ms transcurridos entre dos gestos

 boolean gestoAdelanteActivo = false;

 boolean gestoAtrasActivo = false;

Ahora vamos a ver el método GestoAvanceAtras. Mediante dos flags controlamos si queremos avanzar hacia delante o atrás, dependiendo del valor de dichas variables, gestoAdelanteActivo y gestoAtrasActivo.

private void GestoAvanceAtras(Joint head, Joint rightHand, Joint leftHand, Joint leftshoulder, Joint rightShoulder)

{   

    if (!gestoAtrasActivo && !gestoAdelanteActivo)   

    {       

        positionListRight.Add(new Vector3()       

        {           

            X = rightHand.Position.X,           

            Y = rightHand.Position.Y,           

            Z = rightHand.Position.Z,           

            date = DateTime.Now       

        });              

        if (SwipeAdvance())       

        {           

            gestoAdelanteActivo= true;          

            System.Windows.Forms.SendKeys.SendWait("{Right}");      

        }

        if (positionListRight.Count() > 20)       

        {

            positionListRight.RemoveAt(0);       

        }   

    }   

    else   

    {       

        gestoAdelanteActivo = false;   

    }  

    if (!gestoAtrasActivo && !gestoAdelanteActivo)   

    {       

        positionListLeft.Add(new Vector3()       

        {           

        X = leftHand.Position.X,           

        Y = leftHand.Position.Y,           

        Z = leftHand.Position.Z,           

        date = DateTime.Now       

        });       

        if (SwipeBack())       

        {           

            gestoAtrasActivo= true;           

            System.Windows.Forms.SendKeys.SendWait("{Left}");      

        }       

        if (positionListLeft.Count() > 20)       

        {           

            positionListLeft.RemoveAt(0);       

        }   

    }   

    else   

    {       

        gestoAtrasActivo = false;   

    }         

}

Y por último, el método SwipeAdvance() y SwipeBack() con muy similares. Recorremos los vectores que tenemos con las posiciones de las manos, bien el array con los movimientos de la mano derecha como el array con los movimientos de la mano izquierda. Por otra parte también medimos la duración del gesto, y el recorrido para ver si es el gesto que coincide con el que queremos.

bool SwipeAdvance()

{    

    int start = 0;    

    for (int index = 0; index < positionListRight.Count - 1; index++)    

    {        

        if ((Math.Abs(positionListRight[0].Y - positionListRight[index].Y) > SwipeMaximalHeight) || (positionListRight[index + 1].X - positionListRight[index].X > -0.01f))        

        {           

            start = index;        

        }        

        if ((Math.Abs(positionListRight[index].X - positionListRight[start].X) > SwipeMinimalLength))        

        {            

            double totalMilliseconds = (positionListRight[index].date - positionListRight[start].date).TotalMilliseconds;            

            if (totalMilliseconds >= SwipeMinimalDuration && totalMilliseconds <= SwipeMaximalDuration)            

            {                

                if (DateTime.Now.Subtract(lastGestureDate).TotalMilliseconds > MinimalPeriodBetweenGestures)                

                {                    

                    gestureAcceptedList.Add(Gesture.Swipe);                    

                    lastGestureDate = DateTime.Now;                    

                    positionListRight.Clear();                    

                    return true;                

                }            

            }        

        }    

    }    

    return false;

}

El SwipeBack es trivial y muy parecido a SwipeAdvance, os lo propongo como reto! He de agradecer al equipo de MSDN, ya que estos movimientos los cogí como inspiración del artículo de MSDN Reto Kinect, podéis encontrar más información aquí.

En nuevos post escribiré más gestos y más posibilidades para controlar PowerPoint, y también por comandos de voz!

Espero que os guste Sonrisa

Yolanda

MSP’s por el Tech·Ed 2010!

0

La semana del 8 al 12 de Noviembre varios MSP’s (Microsoft Student Partner) españoles tuvimos el privilegio de asistir al Tech·Ed en Berlín, Alemania. Evento organizado a nivel europeo donde se centran un gran número de desarrolladores y profesionales de IT para compartir y adquirir conocimientos en lo último en tecnología.

clip_image002

Muchos de los students partners de Europa asistimos al summit de MSP’s, donde nos contaron todas novedades para este año, y pudimos conocer y hablar directamente con otros estudiantes de toda Europa. Entre los debates que hubieron destacaron, nuevo portal de MSP’s, intercambiar opiniones e ideas de cómo nos organizamos en nuestros países, como mejorar los students tech clubs, la relación con la universidad, etc. Actividad que sirvió de mucho para conocer y poner cara a todos las personas que sólo conocíamos online.

Asistimos también a la Keynote, charla para todos los asistentes que contó con la deslumbrante cifra de más de 6000 personas! Se hizo mención especial a Windows Phone 7, Windows Azure, Windows Server. Y el día inaugural no pudo terminar mejor que con una fiesta de bienvenida donde tuvimos la primera toma de contacto con los asistentes.

El TechEd tiene como característica el gran de número de charlas que se imparten, hay alrededor de 10 salas donde se dan las charlas de forma paralela. Voy a nombrar algunas de las charlas a las que pudimos asistir y nos resultó de gran interés.

Por la parte de IT Pro, destacar temas como Dynamic Memory, RemoteFX, Hyper-V, Deployment, Virtualización, Plataforma Windows Azure, etc. Tuvimos la oportunidad de hablar con David Nudelman durante casi 1 hora, donde nos explicó personalmente sobre Microsoft Deployment Toolkit, una herramienta que puede resultar muy útil para realizar y desplegar imágenes de los distintos sistemas operativos.

Se pudo disfrutar de charlas de la mano de Mark Russinovich sobre la memoria física y virtual de Windows, con un lleno prácticamente absoluto en una de las salas grandes del evento. Otra charla del mismo ponente fue “Inside Windows Azure” donde detalló un gran número de características sobre como funciona y está implementado Azure.

Y por la parte de Developers, destacar temas como desarrollo para Windows Phone 7, Silverlight, C# en el futuro, Sharepoint, Paralell

Sobre C#, desde aquí os podéis descargar un paquete para añadir nueva sintaxis al lenguaje. Con Silverligth vimos cómo llevar a cabo un proyecto para Windows Phone, utilizar sevicios web en Windows Phone y paralelizar tu aplicación. Y sobre Sharepoint había un gran abanico de charlas, integración con Azure, Sharepoint Server o administrar Sharepoint desde un entorno web.

Todas las charlas se publicarán en TechED online, y estarán disponibles para todo aquel que las quiera ver.

Entre todo el mar de conocimiento adquirido también ha habido tiempo para relajarnos. Entre charla y charla podíamos disfrutar de una variedad de dulces y cafés, pasearnos por los diferentes stands y ver las soluciones que ofrecen las empresas, y llevarnos algunos regalos que siempre hacen ilusión o jugar y pasar un buen rato con Kinect de Xbox.

Microsoft también tenía toda una sala con stands donde ofrecían sus productos y servicios, y podías conocer de a mano y preguntarles a expertos de Windows Phone, Windows Server, Deployment, Bing, Visual Studio, Sharepoint, Exchange, Windows Azure…

Y si entre tanto te daba tiempo siempre podías realizar un hands on lab de IE9 o Windows Phone, donde poner en práctica los conocimientos!

Y para culminar el evento asistimos a una fiesta de Windows Phone 7 en una cervecería en el centro de la ciudad, y aparte de disfrutar muchísimo pudimos ver en directo como al director de Windows Phone 7 le cortaban el pelo debido a una apuesta que perdió relacionada con el lanzamiento del producto.

Otra cena organizada fue para los MSP’s (Microsoft Students Partners) donde pudimos hablar más tranquilamente con alguno de ellos, y divertirnos cantando canciones creadas por nosotros mismos para Windows Phone.

En resumen, una experiencia estupenda a nivel profesional como personal, te llena de ganas seguir aprendiendo dentro de esta profesión donde se desarrollan perfiles tan inquietantes y pasionales por la tecnología!

Y para finalizar una foto de los Microsoft Students Partners españoles que asistimos al evento: Daniel Cáceres Maña, Javier Albert Seguí, Yolanda Olmedo Rodríguez, Andrés Pérez Gil, Jose Ángel Fernandez Rodrigues, Jesús Bosch Aiguadé y Alberto Marcos González.

clip_image004

Y aqui, estamos con Elisa García, responsable de programas académicos en MS España

clip_image006

Un saludo,

Yolanda Olmedo

[WPF] User Control:que son y para que se utilizan

2

Estoy peleándome bastante con WPF últimamente, asique os iré contando todo lo que aprenda en este tema, sin más, comenzamos!

Los controles de usuario en WPF, como su nombre indica son controles que puedes crear y personalizar a tu propio gusto, con la gran ventaja de luego poder utilizar el control es otros formularios, sin tener que volver a escribir el código y simplificando el trabajo.

Y os preguntareis, que es un control?? Un control es cualquier cosa, un botón, un textBox, un grid, un checkbox, un list, cualquier cosa!!! Y con WPF teneis la ventaja de poder crear vuestros propios controles a vuestro gusto y según vuestras necesidades.

Un uso que se puede dar a los controles, es por ejemplo, crearos un control que por ejemplo sea la cabecera de vuestra aplicación. Vamos a suponer que teneis que hacer una aplicación y que en varias de vuestras pantallas aparecerá el mismo botón y por ejemplo un logo. Pues bien, esto lo podemos hacer con un UserControl, sólo teneis que crearlo, dotarlo de funcionalidad (el boton en este caso), y luego sólo teneis que arrastrarlo a vuestras ventanas para hacer uso de él.

Tened en cuenta que una ventaja de esto, es que si al user control le teneis que meter funcionalidad, una ventaja es que el codigo sólo lo teneis que implementar en el user control, lo cual os evita réplicas de código y ahorro de trabajo.

Como ejemplo nos vamos a crear un control de usuario desde Expression Blend 3. Vamos a suponer que nuestro control de usuario tiene una imagen y 2 botones, y dicho control lo usaremos en futuras ventanas que creemos de nuestra aplicación.

El código XAML con nuestra imagen y los 2 botones sería el siguiente:

   1: <UserControl

   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   4:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   5:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   6:     mc:Ignorable="d"

   7:     x:Class="wpf_demo2.UserControl2"

   8:     x:Name="UserControl"

   9:     d:DesignWidth="640" d:DesignHeight="480">

  10:  

  11:     <Grid x:Name="LayoutRoot">

  12:         <Button x:Name="btn_Inicio" Margin="200,0,264,8" VerticalAlignment="Bottom" Height="40" Content="Inicio"/>

  13:         <Button x:Name="btn_Info" HorizontalAlignment="Right" Margin="0,0,48,8" VerticalAlignment="Bottom" Width="168" Height="40" Content="Informacion"/>

  14:         <Image HorizontalAlignment="Left" Margin="24,0,0,8" VerticalAlignment="Bottom" Width="112" Height="112" Source="MSP.jpg" Stretch="Fill"/>

  15:     </Grid>

  16: </UserControl>

 

Quedando vuestro control con esta apariencia:

image

 

Ahora cada vez que useis vuestro control que habeis creado, sólo teneis que arrastrarlo desde el panel de herramientas, bien en código xaml, añandiendo lo siguiente, siendo UserContro1 el nombre de mi usercontrol que he creado.

<local:UserControl1 d:LayoutOverrides=”Width” d:IsLocked=”True”/>

Voy a resaltar, que como he dicho, podeis dotar a vuestros botones contenidos en el UserControl, de funcionalidad. Me queda decir que teneis que tener en cuenta que cuando useis el control de usuario en cualquier ventana, el control de usuario está contenido en la ventana, esto es importante a la hora de programar, porque si quereis navegar entre las ventanas.

Os pongo un ejemplo. Tenemos el UserControl1 creado anteriormente, dicho control de usuario lo utilizamos en una ventana nueva de nuestra aplicación. Y el botón de inicio lo hemos programado para que nos vuelva a la página de inicio, bien el código del botón Inicio sería este:

 

   1: private void Button_Click(object sender, System.Windows.RoutedEventArgs e)

   2:         {

   3:             Ventana1 ventana1 = new Ventana1();

   4:             ventana1.Show();

   5:             

   6:             Window contenedora = new Window();

   7:             contenedora= (Window)((System.Windows.Controls.Grid)this.Parent).Parent;

   8:             contenedora.Close();

   9:             

  10:         }

 

Con esto sólo quiero destacar, que el botón que queremos programar está contenido dentro de un usercontrol, y dicho control de usuario está contenido cuando lo utilizamos está contenido dentro de una ventana, es por esto, que para cerrar la ventana le tienes que dar la orden al padre para que se cierre.

 

Bueno espero haber aclarado un poco sobre los controles de usuario y espero que les sea útil.

 

Saludos!

 

Yolanda Olmedo Rodríguez

[Evento] VS/VB Spanish Tour 2008

0

En los proximos dias se van a realizar unos eventos en algunas ciudades de españa, a quien le pille cerca y pueda que se acerquen porque pintan muy bien.

Son eventos técnicos, impartidos en inglés, donde se verá lo mas relevanta del IDE de Visual Studio 2005.

17/11/2008 Tarragona

17/11/2008 Barcelona

18/11/2008 Valencia

19/11/2008 Alicante

20/11/2008 Madrid

La pagina de registro y mas información:

http://www.microsoft.com/spanish/msdn/spain/eventos/tour.mspx

Ir arriba