Leap Motion (III): analizamos la API

Con esta entrada cerramos el análisis de Leap Motion que hemos estado haciendo en este blog. Primero te explicamos las características técnicas del dispositivo y, después, su principio de funcionamiento. Hoy vamos a hablar de la parte que más información nos dan en la página oficial, la SDK (versión 2.2.5.26752). Para ello vamos a ver sus partes fundamentales e intentaremos analizarlas ayudándonos de figuras.

Nosotros vamos a analizar la API desde el punto de vista del lenguaje de programación Java, pero debes saber que Leap Motion se puede programar en los siguientes lenguajes de programación y plataformas de desarrollo:

IMG1

Desde la API se puede obtener todo tipo de información tridimensional referente a antebrazos, manos, herramientas, dedos e incluso a los “huesos” de los dedos que se tratan como objetos. Además, desde la versión 2.1. se puede acceder a la información de las imágenes en formato RAW que recoge el dispositivo.

Visión general

El dispositivo utiliza el sistema de coordenadas cartesianas, en donde, desde la posición del usuario, el eje Y tiene valores positivos hacia arriba, el X hacia la derecha y el Z hacia el usuario.

IMG2

La API mide magnitudes físicas con las siguientes unidades:

IMG3

A continuación, vamos a analizar los componentes principales de esta versión. Para ello iremos viendo los objetos principales que el dispositivo puede rastrear, junto con el modelo anatómico que se usa para identificar cada uno, y también analizaremos las clases principales que se describen en la API.

Componentes principales

El principal objeto es Controller(), que se encarga de hacer de interfaz entre la aplicación que desarrollemos y el dispositivo. A continuación podemos ver los métodos que contiene:

IMG4

El que más nos interesa de esta clase es el método frame(), a través del cual podemos acceder al objeto Frame que deseemos; por defecto, al último que ha llegado desde el dispositivo. Además, como se puede observar en uno de los métodos constructores, se puede asociar un objeto de tipo Listener al objeto Controller para poder estar pendientes de los eventos que se produzcan en dicho Controller.

En la siguiente imagen vemos cuáles son los eventos que se producen en el Controller y pueden ser atendidos por el objeto Listener:

IMG5

Como podemos ver, hay diferentes eventos asociados al estado del objeto Controller que al final se traducen en eventos asociados al dispositivo hardware.

Otro método interesante —al igual que en el caso de Controller— es el onFrame(), evento que se produce cada vez que el dispositivo captura una imagen. Este es el evento principal, ya que dentro de este se pueden implementar todas las acciones que queremos hacer sobre los objetos que más adelante veremos (manos, dedos, gestos, etc.).

Así pues, hay dos modos de acceder a un objeto Frame:

  1. Desde el objeto Controller, a través del metodo frame()
  2. Desde el objeto Listener, a través de los eventos que se van disparando

Usar un modo u otro dependerá de si queremos analizar o no todos los frames que lleguen desde Controller. Si queremos analizarlos todos, accederemos a la información del objeto Frame a través de Listener; pero si, por el contrario, queremos analizar un objeto Frame cada cierto tiempo, se accederíamos desde el objeto Controller.

A continuación, podemos ver un diagrama de la relación entre el objeto Frame y los que se puede acceder a través de él:

IMG6

Como vemos, el objeto Frame es la raíz de todos los datos de los objetos que analiza Leap Motion. Frame nos da la posibilidad de acceder a todas las clases List, a partir de las cuales se puede acceder a una lista de objetos del mismo tipo y que aparecen en cada Frame.

La parte que nos interesa en ShowLeap es la que depende de HandList. Esta clase es una lista de objetos de tipo Hand que, a su vez, contiene objetos de tipo Arm, Finger, Pointable y Tool para cada objeto Hand.

Dentro del objeto Hand, podemos acceder a una lista de objetos Finger para cada Hand, en la que podemos acceder a información de cada objeto Finger que aparece en el frame y que forma parte del objeto Hand. A su vez, cada objeto de tipo Finger contiene objetos de tipo Bone. Además, como podemos observar, los objetos Finger y Bone son de tipo Pointable.

A continuación podemos ver un esquema de las partes que componen el objeto Hand con su representación anatómica:

IMG7

A continuación podemos ver la información principal que se puede extraer de cada objeto que depende de Hand:

Información principal incluida en el objeto Hand

  • posición y velocidad de la palma
  • dirección y vectores normales
  • base ortonormal

Información incluida en el objeto Finger

  • posición y velocidad de la punta
  • vector de dirección
  • base ortonormal
  • anchura y longitud

Información incluida en el objeto Bone

  • posición de la articulación
  • base ortonormal
  • anchura y longitud

Información incluida en el objeto Arm

  • posiciones de muñeca y codo
  • vector de dirección
  • base ortonormal
  • anchura y longitud

Información incluida en el objeto Pointable Tool

  • posición y velocidad de la punta
  • vector de dirección
  • base ortonormal
  • anchura y longitud

La siguiente clase a analizar es HandList, que es la encargada de almacenar los objetos Hand:

IMG8

Como se puede observar, a través de esta clase se puede extraer un objeto de tipo Hand mediante el método get(). Además, se puede saber cual es el objeto Hand que está más cerca del dispositivo, más a la izquierda o más a la derecha.

Como ya se ha dicho, HandList provee una lista de objetos Hand que aparecen en el Frame que se está analizando. Vamos a ver el objeto Hand:

IMG9

Como podemos ver, a través de esta clase se puede extraer muchísima información referente al objeto Hand. También se puede acceder a los objetos Finger y Arm que dependen de cada objeto Hand en concreto. Es decir, podemos extraer objetos de tipo dedo y antebrazo de cada mano que aparece en la imagen.

Este objeto puede extraer información basándose en el modelo anatómico de la mano, que fue mejorado en la versión 2.0 y ahora se basa en el esqueleto:

IMG10

Como podemos ver, ahora el modelo de la mano se basa en una estructura de puntos y líneas que describen mejor a un objeto de tipo mano. Con este nuevo modelo aparece el objeto Bones, que ha ayudado a que el dispositivo tenga mejor precisión a la hora de determinar la posición y el gesto de la mano, ya que gracias a la definición de estos puntos si el dispositivo no ve alguno de ellos puede determinar por ejemplo donde está el dedo que no ve o en qué posición está la mano.

En la API también se puede acceder a la información de cada dedo. Para ello se hace uso del objeto Finger, objeto que hay que extraer de la clase FingerList:

IMG11

Como vemos, esta clase es muy parecida a HandList, ya que es una clase que contiene objetos de tipo Finger. Además, también se puede extraer información del objeto Finger más cercano al dispositivo, ya sea a la derecha o a la izquierda. Por lo tanto, dentro de la clase FingerList aparecen los objetos Finger:

IMG12

Este objeto, en el modelo, equivaldría a la siguiente figura:

IMG9 IMG13

Como se puede ver, también se pueden extraer de cada objeto Finger diferentes objetos Bone. Estos objetos representan los puntos que definen al dedo en el modelo y que, en la anatomía definida en la API, estarían representados de la siguiente manera:

IMG14

Como vemos, cada objeto Bone puede ser de un tipo que será el que determine su identificador.

A continuación podemos ver mejor como es interpretado esto por la API:

IMG15

A continuación, podemos ver el objeto Bone:

IMG16

Como se puede observar en el diagrama de la clase, se puede extraer bastante información de cada objeto de tipo Bone. Gracias a este nuevo modelo matemático, se puede determinar mejor la posición de cada objeto y las direcciones, y esto dio lugar a la aparición de un nuevo objeto, el objeto Arm:

IMG17

Además, la API también nos provee de una serie de objetos que ayudan a poder extraer los datos que necesitemos, como por ejemplo el objeto Vector.

Conclusión

Como vemos, el dispositivo Leap Motion cuenta con una API muy extensa y optimizada para la extracción de datos característicos de las partes que forman una mano. Por lo tanto, es un dispositivo óptimo para nuestro proyecto, en el que vamos a analizar el comportamiento de las manos al realizar diferentes signos.

Leap Motion (II): principio de funcionamiento

¿Recordáis que en la entrada anterior vimos las partes de las que consta el sensor Leap Motion? Pues hoy nos toca analizar su funcionamiento. ¡Allá vamos!

Una de las razones por las que hemos elegido Leap Motion como sensor para nuestro traductor de lengua de signos es porque, para identificar correctamente los gestos, necesitamos obtener la máxima información posible de la configuración y del movimiento realizado por las manos. Tener información tridimensional es imprescindible para nuestro proyecto.

Existen diferentes técnicas para obtener parámetros de profundidad mediante un sistema de visión (por ejemplo, Kinect obtiene imágenes a color e imágenes de profundidad proyectando un mallado de puntos de los que analiza la distancia a partir de la distorsión del mallado). Con esta información se pueden obtener variables suficientes para poder determinar un gesto realizado. Nosotros vamos a centrarnos en el funcionamiento de Leap Motion; como siempre, ¡paso a paso!

Cómo funciona el controlador Leap Motion

El dispositivo ilumina la zona de cobertura mediante una luz infrarroja emitida a través de sus tres LEDs, con una longitud de onda de 850 nm. Esta zona de cobertura está limitada por el ángulo de visión de los sensores (esto también lo vimos en la entrada anterior) y por la corriente máxima que puede entregar la conexión USB.

IMG 1-Blog de ShowLeap-Leap Motion-Principio de funcionamientoCuando un objeto —en nuestro caso, las manos— es iluminado, se produce una reflexión de luz que llega al dispositivo e incide sobre las lentes de las dos cámaras. Estas lentes, de tipo biconvexas, concentran los rayos en el sensor de cada cámara; y los datos recogidos por los sensores se almacenan en una matriz (imagen digitalizada) en la memoria del controlador USB, en donde se realizan los ajustes de resolución adecuados mediante el microcontrolador del dispositivo.

Una vez ajustada la resolución, los datos de los sensores se envían directamente al driver instalado en el ordenador. Estos datos representan un valor de intensidad luminosa por cada píxel de la imagen capturada y se guardan en un buffer. El valor de intensidad luminosa se cuantifica a 8 bits para generar una imagen RAW en escala de grises —por tanto, hay un total de 256 posibles valores de luminosidad. Y nos falta otro dato: cada imagen tiene un tamaño de 640 x 120 px, con lo que en total hay 76.800 píxeles por imagen. ¿Y aún así es rápido el dispositivo? Pues si, porque las imágenes no son tratadas en el propio dispositivo; ¡este solo recoge y envía datos! 😉

Una vez que las imágenes de las dos cámaras llegan al driver son analizadas para identificar las manos y los dedos a partir de un modelo matemático de caracterización anatómico. Además, se obtiene la profundidad mediante un algoritmo que os explicamos  a continuación. Primero, mirad esto:

IMG 2-Blog de ShowLeap-Leap Motion-Principio de funcionamiento

Estas son las dos imágenes que llegan al driver del Leap Motion (se puede acceder a ellas a partir de la versión 2.1 de la API).

Pero antes de aplicar el algoritmo de identificación y el de profundidad hay que tener en cuenta que las lentes del dispositivo producen una distorsión en la imagen óptica , deformando el objeto observado. Vayamos por partes: ¿sabes que existen diferentes tipos de distorsión, dependiendo del tipo de lente que se use?

IMG 3-Blog de ShowLeap-Leap Motion-Principio de funcionamiento

Pues en Leap Motion se produce lo que conocemos como distorsión compleja: una mezcla entre la distorsión barril y la distorsión cojín.

IMG 4-Blog de ShowLeap-Leap Motion-Principio de funcionamiento

Para mejorar esta distorsión, Leap Motion tiene una opción de calibrado mediante la cual se obtiene un mapa de mallado de puntos de calibrado que se superpone a la imagen captada por cada sensor.

IMG 5-Blog de ShowLeap-Leap Motion-Principio de funcionamiento

Por lo tanto, cada buffer de datos de imagen que se envía al driver va acompañado de otro buffer que contiene los datos de distorsión. Estos datos son una rejilla de 64 x 64 puntos con dos valores de 32 bits cada uno. Cada uno de estos puntos representa un rayo proyectado en la cámara. El valor de un punto del mallado define la luminosidad de un píxel en la imagen y se pueden obtener los datos de luminosidad de todos los píxeles mediante interpolación.

Así pues, se puede obtener el valor de brillo para cualquier rayo proyectado. Los valores de la cuadrícula que caen fuera del rango [0…1] no corresponden a un valor de datos de la imagen y, por tanto, debemos ignorar estos puntos. Vamos a tratar de que se entienda mejor con un ejemplo:

IMG 6-Blog de ShowLeap-Leap Motion-Principio de funcionamiento

La imagen nos muestra una reconstrucción de los datos de una imagen con la distorsión corregida. El valor de brillo de cada píxel de la imagen se originó a partir de un rayo de luz que entró en la cámara desde una dirección específica. La imagen se reconstruye mediante el cálculo de las pistas horizontales y verticales representados por cada píxel y se puede encontrar el valor de brillo verdadero de los datos de la imagen utilizando el mapa de calibración. Las partes rojas de la imagen representan las áreas dentro de la prestación para la que ningún valor de brillo está disponible (el campo de visión real es de menos de 150 grados).

Una vez que han llegado las imágenes, las hemos corregido debidamente y el driver ha identificado las manos y los dedos, podemos determinar la posición de estas en el sistema de coordenadas cartesianas de Leap Motion a través de técnicas de visión estereoscópica. Porque, como ya hemos visto, Leap Motion es un sistema de captación de imágenes basado en la visión binocular y por ello podemos obtener distancias.

Básicamente, un sistema estereoscópico funciona del siguiente modo: gracias a la separación de las dos cámaras en el eje X se obtienen dos imágenes con pequeñas diferencias (disparidad).

IMG 7-Blog de ShowLeap-Leap Motion-Principio de funcionamiento

Como se puede observar en la imagen anterior, las dos cámaras —representadas por Oi y Od— están en el mismo plano Z, sobre la línea base. Si trazamos una línea epipolar entre las dos imágenes Ii e Id, dado que Oi y Od están en el mismo plano Z y las dos cámaras tienen la misma distancia focal, podemos ver la proyección del punto P en las dos imágenes. Por tanto, se puede obtener un valor de disparidad para cada par de puntos emparejados Pi(xi,yi) y Pd(xd,yd) dado por d = XI-XD.

IMG 8-Blog de ShowLeap-Leap Motion-Principio de funcionamiento

Considerando igual la distancia focal f en las dos cámaras y conociendo la distancia entre cámaras b:

IMG 9-Blog de ShowLeap-Leap Motion-Principio de funcionamiento

Como vemos, a partir del sistema anterior podemos obtener las coordenadas del punto P.

Y ahora sin tantos tecnicismos… ¿Cómo funciona Leap Motion? 🙂

Para terminar este post te nombramos los pasos básicos que realiza Leap Motion para entregar variables descriptivas de una configuración de mano y de un gesto:

  1. Obtiene las imágenes desde los sensores de las cámaras del dispositivo.
  2. Aplica una corrección de la distorsión que producen los sensores.
  3. Aplica un modelo para determinar la configuración de cada mano y ejecuta un algoritmo de visión estereoscópica entre cada par de imágenes para obtener la posición en el plano tridimensional.

 

Créditos del post
Imágenes:
- Página oficial de Leap Motion
- TFM «Técnicas de visión estereoscópica para determinar la estructura tridimensional de la escena». Autor: Martín Montalvo Martínez / Director: Gonzalo Pajares Martinsanz

 

Leap Motion (I): características técnicas

En esta entrada os vamos a hablar de las características técnicas del dispositivo que utilizamos para nuestro traductor de lengua de signos: Leap Motion. En esta primera parte vamos a analizar los componentes que forman el hardware y, próximamente, veremos también el principio de funcionamiento y la API. ¡Atentos, que empezamos!

Leap Motion (I) - Características técnicas

Dimensiones

Este dispositivo tiene unas dimensiones muy reducidas en comparación con otros interfaces gestuales que hay actualmente en el mercado: tan solo mide 75 mm de largo, 25 mm de ancho y 11 mm de alto.

Leap Motion - Características técnicas

Partes del dispositivo

Leap Motion - Características técnicas

Como se puede ver en la imagen anterior, Leap Motion cuenta con dos cámaras, tres LEDs y un microcontrolador. A continuación vamos a ver cada parte con un poco más de detalle:

Leap Motion - Características técnicas

Cámaras

Las cámaras son una de las partes más importantes del dispositivo, dado que son las encargadas de capturar las imágenes y su buen funcionamiento condicionará el correcto funcionamiento del resto de sistema.

Cada una de estas cámaras cuenta con un sensor monocromático, sensible a la luz infrarroja, con una longitud de onda de 850 nm. Estos sensores pueden trabajar a una velocidad de hasta 200 fps, dependiendo del rendimiento del ordenador/tablet al que conectemos el dispositivo. Además, cada sensor es de tipo CMOS. ¿Por qué este tipo de sensor?

  • La digitalización de los píxeles en un sensor CMOS se produce dentro de cada celda, por lo que no es necesario un chip externo como ocurriría en el caso de utilizar sensores CCD. Esto se traduce en mayor velocidad para capturar imágenes y en menor espacio para albergar los sensores.
  • Estos sensores son más económicos que los sensores CCD.
  • En este tipo de sensor no se produce el fenómeno blooming, al contrario que en los sensores CCD. Este fenómeno se produce cuando una celda se satura de luz y hace que las celdas de alrededor también se saturen.
  • La lectura simultánea de celdas en los CMOS es mayor que en los CCD.
  • El consumo eléctrico de los CMOS es menor que el de los CCD.
Iluminación infrarroja

Los LEDs se encargan de iluminar la zona de cobertura por inundación. Trabajan en el espectro de luz infrarroja a una longitud de onda de 850 nm que, como es lógico, es la misma a la que son sensibles los sensores ópticos. Varían su consumo eléctrico —y por tanto la iluminación— dependiendo de la luz que haya en la zona de cobertura para asegurar una misma resolución de imagen.Leap Motion - Características técnicas

Como se puede observar en la imagen anterior, los LEDs están separados por pequeñas barreras de plástico. De esta manera se asegura que la iluminación sea uniforme en toda la zona de cobertura. Además, se protege a los sensores ópticos de una posible saturación de luz, dado que de esta manera la luz infrarroja no les ilumina directamente.

El microcontrolador

Captura de pantalla 2015-04-20 a las 12.42.46Se trata de un circuito integrado  que se suele utilizar para hacer la función de BIOS (MXIC MX25L3206E–32M-bit CMOS SERIAL FLASH). En este caso contiene el programa que controla todo el dispositivo —para, entre otras cosas, regular la iluminación— y se encarga de recoger la información de los sensores para luego enviarla al driver o controlador instalado en el ordenador/tablet.

Leap Motion - Características técnicas

Controlador USB

Leap Motion - Características técnicas

Leap Motion cuenta con un controlador USB para que el ordenador pueda reconocer el dispositivo. Este controlador es de alta velocidad y puede soportar USB 3.0.

Envío y recepción de datos

Leap Motion - Características técnicas

Los datos se envían y se reciben al controlador del ordenador a través de dos puertos serie: UART_RX y UART_TX.

Zona de cobertura

Leap Motion - Características técnicas

En la figura anterior se puede observar la zona de cobertura del dispositivo. Como se puede ver, esta zona es una semiesfera de 61 cm de radio.

Esta zona depende del ángulo de visión de las lentes de las cámaras y de la intensidad máxima que puede entregar la conexión USB a los LEDs. A su vez, el ángulo de visión depende de la distancia focal y del tamaño del sensor de la siguiente forma:

Captura de pantalla 2015-04-20 a las 12.43.40

(donde d es la diagonal del sensor y f la distancia focal)

Tanto el ángulo de visión horizontal de Leap Motion como el vertical son de 150,92º. Estos ángulos delimitan la zona de interacción.

Leap Motion - Características técnicas

En la API del dispositivo (que la veremos en la próxima entrada) se define una zona de trabajo llamada “Interaction Box”  por un volumen de 110.55 mm de altura x 110.55 mm de anchura x 69.43 mm de profundidad, que varía sus dimensiones dependiendo de donde se encuentre el objeto a rastrear. Esta es la zona en la que se marca el centro del sistema de coordenadas cartesiano de Leap Motion. Desde el driver del dispositivo se puede configurar la altura a la que se encontrará el centro de esta zona de interacción. Esta altura puede estar entre 7 y 25 cm desde el dispositivo.

ShowLeap cumple un año. ¡Despegamos!

ShowLeap cumple su primer año, un año de mucho trabajo para hacer realidad un proyecto muy ambicioso.

Durante todo este tiempo hemos conocido a muchas personas que nos han dado su apoyo y hemos conseguido crear un equipo comprometido con el proyecto. Ha sido un año duro, ya que teníamos que trabajar en el desarrollo de nuestro producto al mismo tiempo que buscábamos financiación para el proyecto. Hemos participado en diferentes concursos y programas en los que hemos llegado hasta las últimas fases, sin llegar a conseguir financiación; pero la verdad es que hemos aprendido mucho, y aprovechamos este post para agradecer a todas las personas y entidades la formación que nos han dado y el interés que han mostrado en nuestro proyecto.

Y ahora…

¿Dónde estamos y cuál es el futuro inmediato de ShowLeap?

ShowLeapPulseraMYO
Trasteando con la pulsera MYO © ShowLeap

A nivel de desarrollo estamos en la fase final de la creación del primer prototipo de nuestro traductor LSE-voz. Hemos realizado diferentes pruebas de reconocimiento de signos obteniendo muy buenos resultados, que compartiremos próximamente.

Tenemos un algoritmo escalable y fiable que nos permite no tener que depender del sensor que utilizamos (Leap Motion) y, en las próximas semanas, publicaremos más y mejor información sobre el estado de nuestro prototipo.

El camino se ha hecho más largo de lo que hubiésemos querido, pero el no haber tenido una financiación importante nos ha impedido acelerar el proceso. Han sido meses de mucho trabajo en los que hemos tenido que combinar nuestras vidas personales y profesionales con el proyecto, pero pesar de los sacrificios que hemos hecho todo el equipo hasta el día de hoy y de los momentos duros, estamos más convencidos que nunca de que pronto vamos a conseguir sacar al mercado un producto que esperemos ayude a mejorar ciertas situaciones del colectivo sordo: el primer traductor de lengua de signos a voz, y viceversa, en tiempo real.