Este artículo proviene de un motor de traducción automática.
Kinect
Comunicaciones multimodales con Kinect
Descargar el código de ejemplo
En la edición de abril (msdn.microsoft.com/magazine/hh882450) le introdujo a "Lily", un asistente virtual para ayudar a los trabajadores de oficina en sus tareas diarias.He demostrado cómo utilizar el Kinect de Microsoft para Windows SDK para crear diálogo consciente del contexto, permitiendo Lily escuchar y responder adecuadamente con respecto a las intenciones del usuario.
Ahora llevaré a través del siguiente paso en la consecución de una interfaz de usuario natural aprovechando el dispositivo Kinect esqueléticos de seguimiento para facilitar la interacción con el usuario a través de gestos.Luego podrá unir los dos conceptos y demostrar la comunicación multimodal por tener salida de Lily depende no sólo qué gesto hizo, sino también qué comando hablado fue emitido.Mediante la combinación de estos dos modos de comunicación, el usuario viene lejos con una experiencia mucho más rica y obtiene un paso más cerca de omnipresente informática.La presentación de Lily es en forma de una aplicación de Windows Presentation Foundation (WPF).
Inicializar Kinect
El primer paso para utilizar el dispositivo Kinect es construir un tiempo de ejecución, configuración de diversos parámetros.Figura 1 muestra la configuración eligió para Lily.
Figura 1 Kinect Runtime construcción
// Initialize Kinect
nui = Runtime.Kinects[0];// new Runtime();
nui.Initialize(RuntimeOptions.UseDepthAndPlayerIndex |
RuntimeOptions.UseDepth | RuntimeOptions.UseColor |
RuntimeOptions.UseSkeletalTracking);
nuiInitialized = true; nui.SkeletonEngine.TransformSmooth = true;
nui.SkeletonEngine.SmoothParameters = new TransformSmoothParameters
{
Smoothing = 0.75f,
Correction = 0.0f,
Prediction = 0.0f,
JitterRadius = 0.05f,
MaxDeviationRadius = 0.04f
};
nui.VideoStream.Open(ImageStreamType.Video, 2,
ImageResolution.Resolution640x480, ImageType.Color);
nui.DepthStream.Open(ImageStreamType.Depth, 2,
ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex);
Al configurar un dispositivo Kinect, un número de opciones está disponible. En primer lugar, observe la primera línea de código en figura 1. La beta del SDK de Kinect para Windows 2 tiene un constructor diferente para el tiempo de ejecución. Haciendo referencia a un índice (Runtime.Kinects[0];), es simple conectar múltiples unidades de Kinect a la aplicación. En esta aplicación he limitado a un único dispositivo Kinect, por lo que por definición el tiempo de ejecución debe estar en posición [0]. Puede recorrer en iteración la colección de Runtime.Kinects para manejar múltiples unidades de Kinect si está disponible. A continuación, se deba contar el dispositivo Kinect qué capacidades se van a utilizar. Esto se hace pasando las capacidades deseadas en el método Initialize. Hay cuatro valores a elegir:
- UseColor permite a la aplicación procesar la información de imagen de color.
- UseDepth permite a la aplicación hacer uso de la información de imagen de profundidad.
- UseDepthAndPlayerIndex permite a la aplicación hacer uso de la información de la imagen de profundidad, así como el índice generado por el motor de seguimiento de esqueleto.
- UseSkeletalTracking permite que la aplicación utilice el esqueleto de los datos de seguimiento.
Pasando estos valores indica la API qué subsistemas en el dispositivo Kinect va a utilizarse para que las partes adecuadas de la tubería multifase de ejecución pueden ser iniciadas. Es importante señalar que no puede acceder a funciones más adelante en la aplicación que no se declararon durante la inicialización. Por ejemplo, si la única opción seleccionada fue RuntimeOptions.UseColor y posteriormente usando la información de profundidad fue requerido, no esté disponible. Por lo tanto, he pasado en todos los valores disponibles, indicando que tengo la intención de utilizar todas las capacidades del dispositivo Kinect.
Seguimiento de los usuarios
Antes de examinar la siguiente sección del código, echemos un vistazo a lo que el dispositivo Kinect realmente nos está dando. Cuando se utiliza el esqueleto capacidad de seguimiento, el dispositivo Kinect puede controlar a hasta dos seres humanos activos interacción con el sistema. Logra crear una colección de 20 articulaciones y asociar un ID a cada uno. Figura 2 muestra qué articulaciones están siendo modeladas.
.jpg)
Figura 2 el 20 juntas se modelan en Kinect
Figura 3 es una imagen de las articulaciones siendo capturado a dos usuarios distintos.
.jpg)
Figura 3 dos esqueletos activo
Para que un esqueleto para convertirse en activo, el dispositivo Kinect debe ser capaz de ver el usuario desde la cabeza a los pies. Una vez que un esqueleto está activo, si una articulación está fuera de la vista, el dispositivo Kinect intentará interpolar donde es esa parte del esqueleto. Si vas a construir aplicaciones habilitadas para Kinect, insto firmemente a crear una sencilla aplicación para ver las secuencias esqueleto e interactuar con el dispositivo Kinect. Asegúrese de tener varios usuarios participar y establecer escenarios donde vienen obstáculos entre los usuarios y el dispositivo Kinect, escenarios que imitan lo que experimentará la aplicación una vez desplegados. Esto le dará una excelente comprensión de cómo funciona el seguimiento esqueleto y lo que es capaz de, así como qué limitaciones le desee dirección. Rápidamente verás es increíble cómo de la tecnología y cómo creativo puede ser en la interpolación.
En algunos casos (como el representado por el proyecto Lily) la velocidad y la agitación de esta interpolación puede distraer e improductivos. Por lo tanto, la API expone la capacidad para controlar el nivel de suavizado. Refiriéndose a la figura 1 nuevamente, utilizar primero el SkeletonEngine en el tiempo de ejecución para la TransformSmooth se establece en true. Esto indica el dispositivo Kinect que desea que afectan a la suavidad de los datos que se procesa. A continuación, establezca la SmoothParameters. Aquí es una breve descripción de cada uno de los TransformSmoothParameters:
- Corrección controla la cantidad de corrección con valores entre 0 y 1.0 y un valor predeterminado de.5.
- JitterRadius controla el radio de la reducción de la variación. El valor pasado representa el radio deseado en metros. El valor predeterminado se establece en 0.05, que se traduce en 5 cm. Cualquier variación que va más allá de esta radio es abrazaderas al radio.
- Controles de MaxDeviationRadius el radio máximo (en metros) que corrige posiciones puede desviarse de los datos sin procesar. El valor predeterminado es 0,04.
- Predicción controla el número de fotogramas previstos.
- Suavizado controla la cantidad de suavizado con un rango de 0 a 1,0. La documentación hace un punto específico que suavizado tiene un impacto sobre la latencia; aumento de suavizado de latencia de aumentos. El valor predeterminado es 0,5. El valor 0 hace que los datos sin procesar a devolverse.
Vídeo y secuencias de profundidad
Querrá experimentar con estos ajustes en su propia aplicación, dependiendo de los requisitos que están cumpliendo. Lo último que necesitaba para esta aplicación es abrir el VideoStream y el DepthStream. Esto facilita la visualización de las imágenes de vídeo procedentes de la cámara de color y las imágenes de fondo procedente de la cámara de profundidad, respectivamente. Más tarde a mostrarle cómo esto se conecta a la aplicación de WPF.
El método abierto requiere cuatro parámetros. El primero es streamType. Representa el tipo de secuencia que se abre (por ejemplo, vídeo). El segundo parámetro es Tamaño_agrupación. Esto representa el número de fotogramas que el tiempo de ejecución es de búfer. El valor máximo es 4. El tercer parámetro es la resolución, que representa la resolución de las imágenes deseadas. Los valores incluyen 80 x 60, 320 x 240 y 640 x 480, 1280 x 1024 para satisfacer sus necesidades. Y el último parámetro indica el tipo de imagen (por ejemplo, Color) deseado.
Eventos de Kinect
Con el tiempo de ejecución se ha inicializado correctamente, es hora de conectar los eventos hizo disposición desde el tiempo de ejecución de la aplicación. Lily, se utilizan los dos primeros eventos que serán manejados simplemente para dar al usuario final una vista gráfica de las imágenes de color y la profundidad. En primer lugar, veamos el método que está manejando el evento Runtime.VideoFrameReady. Este evento pasa un ImageFrameReadyEventArgs como su argumento de evento. El método nui_VideoFrameReady es donde Lily controla el evento, como se muestra en el siguiente código:
void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)
{
// Pull out the video frame from the eventargs and
// load it into our image object.
PlanarImage image = e.ImageFrame.Image;
BitmapSource source =
BitmapSource.Create(image.Width, image.Height, 96, 96,
PixelFormats.Bgr32, null, image.Bits,
image.Width * image.BytesPerPixel);
colorImage.Source = source;
}
La API de Kinect para Windows simplifica este método. El ImageFrameReadyEventArgs contiene un ImageFrame.Image. Convertir en un BitmapSource y pasar luego BitmapSource a un control de imagen en la aplicación de WPF. El fotograma procedentes de cámara de color del dispositivo Kinect así se muestra en la aplicación, como lo ves en figura 3.
El evento DepthFrameReady, que está siendo manejado por nui_DepthFrameReady, es similar, pero necesita un poco más de trabajo para obtener una presentación útil. Puede mirar este método en la descarga de código, que es lo mismo que el artículo del mes pasado (archive.msdn.microsoft.com/mag201204Kinect). No crear este método yo mismo, pero encontró que utiliza un número de ejemplos en línea.
El controlador de eventos que realmente comienza a ponerse interesante es el método nui_SkeletonFrameReady. Este método controla el evento SkeletonFrameReady y se pasa en SkeletonFrameReadyEventArgs, como se muestra en figura 4.
Figura 4 nui_SkeletonFrameReady
void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
renderSkeleton(sender, e);
if (!trackHands)
return;// If the user doesn't want to use the buttons, simply return.
if (e.SkeletonFrame.Skeletons.Count() == 0)
return;// No skeletons, don't bother processing.
SkeletonFrame skeletonSet = e.SkeletonFrame;
SkeletonData firstPerson = (from s in skeletonSet.Skeletons
where s.TrackingState ==
SkeletonTrackingState.Tracked
orderby s.UserIndex descending
select s).FirstOrDefault();
if (firstPerson == null)
return;// If no one is being tracked, no sense in continuing.
JointsCollection joints = firstPerson.Joints;
Joint righthand = joints[JointID.HandRight];
Joint lefthand = joints[JointID.HandLeft];
// Use the height of the hand to figure out which is being used.
Joint joinCursorHand = (righthand.Position.Y > lefthand.Position.Y)
?
righthand
: lefthand;
float posX = joinCursorHand.ScaleTo((int)SystemParameters.PrimaryScreenWidth,
(int)SystemParameters.PrimaryScreenHeight).Position.X;
float posY = joinCursorHand.ScaleTo((int)SystemParameters.PrimaryScreenWidth,
(int)SystemParameters.PrimaryScreenHeight).Position.Y;
Joint scaledCursorJoint = new Joint
{
TrackingState = JointTrackingState.Tracked,
Position = new Microsoft.Research.Kinect.Nui.Vector
{
X = posX,
Y = posY,
Z = joinCursorHand.Position.Z
}
};
OnButtonLocationChanged(kinectButton, buttons,
(int)scaledCursorJoint.Position.X,
(int)scaledCursorJoint.Position.Y);
}
Una cosa que me pareció necesario para poner en esta aplicación fue ese primer condicional en figura 4. Cuando el usuario no desea que la aplicación para realizar un seguimiento de sus movimientos de mano, hay comandos hablados que establece la variable trackHands, que a su vez determina si se realiza un seguimiento de las manos. Si trackHands se establece en false, simplemente devuelve el código de este método. Si Lily realiza un seguimiento de manos del usuario al que no es el comportamiento deseado, se convierte rápidamente en tedioso y agotador.
Del mismo modo, si no se está realizando un seguimiento esqueletos (no hay usuarios, o que están fuera del alcance de la vista del dispositivo Kinect) entonces no tiene ningún sentido seguir evaluar los datos, por lo que devuelve el código fuera del método. Sin embargo, si hay es un esqueleto y el usuario quiere manos seguimiento y, a continuación, el código sigue a evaluar. El proyecto HoverButton (bit.ly/nUA2RC) viene con código de ejemplo. La mayor parte de este método proviene de esos ejemplos. Una de las cosas interesantes sucediendo en este método es que el código se comprueba para ver qué mano del usuario es físicamente superior. Entonces hace la suposición de que la mano más alta es la que se utiliza para seleccionar potencialmente un botón. El código, a continuación, va a determinar si un botón está siendo sobrevoló y representa una "mano" en la pantalla en el lugar que es representante de la pantalla con respecto a la ubicación de la mano del usuario. En otras palabras, como el usuario mueve su mano, una mano gráfica se mueve alrededor de la pantalla como moda. Esto da al usuario una interfaz natural, no obligada por el cable del ratón. El usuario es el controlador.
El siguiente punto de interés es cuando el sistema determina que uno de los HoverButtons se hace clic. Lily tiene un total de ocho botones en la pantalla. Cada uno tiene un controlador de eventos de on_click por cable. En este punto, se deba cubrir tres clases especiales: ButtonActionEvaluator, LilyContext y MultiModalReactions.
La acción de hacer clic en un botón tiene un evento correspondiente asociado, pero Lily toma esta acción única y comprueba si puede ser acoplado a un comando de audio correspondiente para evaluar como una comunicación multimodal que llevaría a un mayor nivel de significado. Por ejemplo, haciendo clic en uno de los HoverButtons representa la intención de seleccionar un proyecto. Con esa información, la única acción requerida por el sistema es tomar nota de que el contexto, con respecto al proyecto que se está trabajando, ha cambiado. Ninguna otra acción es deseada. Sin embargo, si el usuario previamente hizo una solicitud para "abrir el plan del proyecto" insatisfecha o posteriormente hace la misma petición, la aplicación debe poner estas dos piezas dispares de datos juntos para crear un orden superior de significado (la comunicación procedente de dos modos separados hace esta comunicación multimodal) y responder en consecuencia. Para hacer esto todos ocurren de manera transparente, se implementó el siguiente diseño.
La clase ButtonActionEvaluator se implementa como un conjunto unitario e implementa la interfaz INotifyPropertyChanged. Esta clase también expone un evento PropertyChanged que es manejado por la clase LilyContext (también un singleton). El siguiente código probablemente requiere un poco de explicar, aunque parece bastante inocua:
void buttonActionEvaluator_PropertyChanged(
object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (MultiModalReactions.ActOnMultiModalInput(
buttonActionEvaluator.EvaluateCriteria()) ==
PendingActionResult.ClearPendingAction)
buttonActionEvaluator.ActionPending =
PendingAction.NoneOutstanding;
}
Evaluar el estado de Lily
En primer lugar, el código anterior llama al método EvaluateCriteria de la clase buttonActionEvaluator. Este método simplemente devuelve una representación numérica para el estado definido por las propiedades ActionPending y SelectedButton. Este es el meollo de cómo la aplicación es capaz de inferir significado mediante el uso de la comunicación multimodal. En las aplicaciones tradicionales, se evalúa la acción deseada mirando el estado de un solo evento o una propiedad (por ejemplo, button1.clicked). Pero con Lily, el Estado que se está evaluando (desde la perspectiva multimodal) es la combinación de dos propiedades independientes lo contrario. En otras palabras, cada propiedad tiene un significado y requiere acciones independientemente, pero cuando evalúan juntos, toman a un nivel nuevo y más alto significado.
Que una representación numérica del estado combinado se pasa al método ActOnMultiModalInput en el MultiModalclase de reacciones. Este método implementa una declaración de gran interruptor que controla todas las permutaciones posibles. (Ésta es una implementación rudimentaria que se utilizó para ilustrar el punto. Iteraciones de futuro de Lily reemplazará esta implementación con técnicas más avanzadas como máquina de aprendizaje para mejorar la experiencia global y la usabilidad y máquinas de Estado.) Si este método da como resultado la intención del usuario estar satisfecho (por ejemplo, el usuario pretende para que el sistema abrir el plan del proyecto para proyecto Lily), el tipo devuelto es PendingActionResult.ClearPendingAction. Esto deja el contexto del sistema aún en el marco de referencia de proyecto Lily, pero no hay ninguna acción a la espera de ser ejecutado en la cola. Si la intención del usuario es aún insatisfecha, se devuelve la PendingActionResult.LeavePendingActionInPlace, diciendo que el sistema de cualquier acción no ha satisfecho la intención del usuario y a por lo tanto, no queda claro la acción pendiente.
En el primer artículo mostré cómo crear gramáticas que son específicas de un determinado dominio o contexto. La unidad de Kinect, aprovechando el motor de reconocimiento de voz, utiliza estas gramáticas, carga y descarga a satisfacer las necesidades del usuario. Esto creó una aplicación que no requiere que el usuario apegarse a una interacción con secuencias de comandos. El usuario puede ir en cualquier dirección ella deseos y cambiar direcciones sin tener que volver a configurar la aplicación. Esto crea una forma natural de establecimiento de diálogo entre el usuario humano y aplicación informática.
Mayor nivel de significado
En este artículo he demostrado cómo acoplar las acciones resultantes de gramáticas de contexto conscientes a gesticular física de un usuario en la forma de seleccionar botones por uno situándose la mano encima de un botón. Cada evento (speechDetected y buttonClicked) se puede tratar de forma individual e independiente. Pero además, se pueden correlacionar los dos eventos del sistema, lograr un mayor nivel de significado a los acontecimientos y actuando en consecuencia.
Yo espero que estés tan entusiasmados con las capacidades que Kinect pone en nuestras manos como soy. Creo que Microsoft nos llevó hasta el borde donde interfaces informáticas humanas pueden dar saltos adelante. Como testimonio de esto, como desarrollé Lily, hubo veces cuando estuve probando diferentes componentes y secciones de código. Como la aplicación madurado y pude realmente "hablar" con Lily, quiero encontrar algo mal, cambiar a mi segundo monitor y empezar a buscar algo en la documentación o en otros lugares. Pero seguirá interactuar verbalmente con Lily, pidiéndole a ejecutar tareas o incluso a cerrar. Encontré que cuando Lily estaba disponible, me convertí en perturbado debido a la cantidad de habilitación que Lily representado era importante — teniendo tareas menores fuera de mis manos a través de comunicaciones verbales simples.
Y incorporar pequeños "trucos" del mecanismo de diálogo (por ejemplo, respuestas al azar pero contextualmente y sintácticamente correctos) la adopción de la aplicación intuitiva y satisfactoria. Kinect hace verdaderamente su cuerpo el controlador. Cuando vas con está limitado sólo por su imaginación. ¿Qué dirá Kinect?
Leland Holmquest es un consultor de estrategia empresarial de Microsoft. Anteriormente trabajó para el Dahlgren de centro de Guerra Naval de superficie. Está trabajando en su doctorado en tecnología de la información en la Universidad de George Mason.
Gracias al siguiente experto técnico para revisar este artículo: Mark Schwesinger