RealidadAumentada

Juan Mellado, 19 Marzo, 2012 - 17:39

Un vídeo que muestra en acción la última demo de js-aruco, mi librería de realidad aumentada escrita en JavaScript:

Demo online:
http://inmensia.com/files/aruco/debug-posit/debug-posit.html

Lo que se ve en el vídeo es la ejecución en Chrome 18 con el flag "--enable-media-stream" activo.

Juan Mellado, 19 Marzo, 2012 - 15:59

Realidad AumentadaHe actualizado los fuentes de js-aruco con los últimos cambios en los que he estado trabajando últimamente. La principal novedad es la posibilidad de calcular la pose en tres dimensiones de un marcador a partir de su proyección en dos dimensiones. Aunque también hay otros cambios importantes, así como varias mejoras realizadas para optimizar el rendimiento.

He publicado una nueva demo online con todos los cambios realizados:
- http://inmensia.com/files/aruco/debug-posit/debug-posit.html

Estimación de la Pose
Para calcular las poses en tres dimensiones he utilizado el método descrito en "Iterative Pose Estimation using Coplanar Feature Points". Este no es el método que utiliza la librería original que tomé como punto de partida, pero lo he preferido porque no requiere los parámetros de calibración de la cámara. Sus únicos parámetros de entrada son el tamaño real del marcador y la longitud focal de la cámara. El primero es sencillo, es lo que mide realmente de lado a lado el marcador (en milímetros). Y aunque el segundo suena un poco más difícil de calcular, en realidad se puede aproximar asumiendo simplemente que es igual al ancho de la imagen con la que se esté trabajando (en pixels).

El algoritmo devuelve dos poses estimadas caracterizadas por una matriz de rotación y un vector de traslación. Esto es así porque la proyección de un cuadrilátero en dos dimensiones puede corresponderse con dos posiciones distintas del mismo cuadrilátero en tres dimensiones. Para averiguar cual es la proyección más correcta, si es que existe alguna, se calcula el error que existe entre el modelo del marcador de partida, y el resultado de aplicar cada rotación y traslación calculada a la proyección dada. La pose estimada que produce el menor error se considera la más correcta de las dos.

He acabado realizando dos implementaciones, la primera basada en el código original utilizado por Daniel DeMenthon escrito en C, y la segunda basada en el código en C# descrito en un artículo por Andrew Kirillow. Dan resultados bastantes similares, aunque hay ciertas diferencias en el cálculo del método del error. Las he exportado con el mismo nombre, ya que la idea es utilizar un método u otro, y para ello basta con incluir posit1.js o posit2.js según cual método se prefiera. Está explicado en la web del proyecto.

Como añadido, he tenido que implementar en JavaScript el algoritmo de descomposición en valores singulares de una matriz, más conocido por su siglas en inglés "SVD". Para ello he seguido la implementación original descrita en "Numerical Recipes in C - Second Edition".

Stack Box Blur
Para aumentar el rendimiento general de la librería he sustituido el cálculo del Gaussian Blur, que se utilizaba para realizar el Threshold Adaptativo, por un Stack Box Blur.

El cálculo del Gaussian Blur era la parte que más tiempo de proceso llevaba de toda la librería. Utilizaba un tamaño de kernel de 7, lo que implicaba que para cada pixel de la imagen se tenían que realizar del orden de un centenar de accesos a memoria y otras tantas operaciones matemáticas. El Stack Box Blur utiliza un tamaño de kernel de 2, reduce considerablemente el número de accesos a memoria utilizando una pequeña pila (stack), evita tener que utilizar un buffer intermedio del mismo tamaño que la imagen, y gracias a una tabla precalculada apenas realiza unas pocas operaciones aritméticas por pixel. Y lo mejor de todo es que el resultado final es apenas indistinguible del original Gaussian Blur cuando se utiliza para calcular el Threshold Adaptativo.

He implementado una versión adaptada a las necesidades de la librería, que en este punto concreto trabaja con imágenes en escala de grises, utilizando un sólo canal, frente a las implementaciones originales, que sólo permiten trabajar con imágenes de tres o cuatro canales.

Supersampling
Una de las cosas que tenía pendiente prácticamente desde que implementé la librería era mejorar el warp. Este proceso es el que extrae de la imagen las áreas donde se encuentran los marcadores detectados y las proyecta en cuadriláteros con la idea de reconstruir el aspecto original real de cada uno de ellos. Su principal carencia era la falta de algún tipo de interpolación entre los pixeles adyacentes, por lo que las imágenes resultantes no eran todo lo buenas que podían llegar a ser cuando los marcadores estaban en ángulos "complicados" en vez de directamente enfrentados a la cámara.

Los cambios realizados han sido de dos tipos. Por una parte optimización del código existente, y por otra parte adición de supersampling. La optimización no ha sido demasiado difícil, ya que originalmente la función no estaba nada optimizada y ha sido fácil obtener una ganancia de rendimiento rápidamente. Desgraciadamente la implementación del supersampling se ha comido la ganancia y algo más. No estoy nada contento con la implementación, se basa en el uso de un par de decenas de variables locales, y eso resulta difícil que la máquina virtual pueda optimizarlo tratando de cachear valores en registros del microprocesador. La parte positiva es que las imágenes que se obtienen ahora son de muchísima más calidad, con bordes rectos en vez de dentados como ocurría antes.

Rendimiento
Utilizando como referencia la última demo, el rendimiento global del sistema en mi equipo es de 60 FPS estables con un consumo de entre el 7 y el 9 por ciento de CPU. Los FPS están perfectos, ya que es el máximo que permite el navegador, y la CPU no está demasiado mal, aunque me haría un poco más feliz ver una cantidad menor ahí. Afortunadamente creo que aún hay bastante margen de mejora.

Juan Mellado, 4 Marzo, 2012 - 16:16

En el vídeo adjunto se pueden ver las primeras pruebas que estoy haciendo sobre js-aruco, mi detector de marcadores de realidad aumentada, con el objeto de añadirle un algoritmo que resuelva el llamado "problema de la pose" para obtener la orientación de un objeto 3D a partir de su proyección en 2D.

El código es una implementación en JavaScript del método llamado "Coplanar POSIT", y lo que se ve en el vídeo es la ejecución en Chrome 18 con el flag "--enable-media-stream" activo.

En la parte superior está la captura de la webcam y un simple cubo que se mueve en función de como lo hace el marcador. La distancia la calcula bastante bien en general, pero con las rotaciones aún tengo problemas. En la parte inferior se muestran las dos posibles orientaciones que devuelve el algoritmo. La que tiene menor error a la izquierda, y la de mayor error a la derecha. Todavía es bastante inestable y queda trabajo por hacer, pero ya empiezan a verse los resultados.

Referencias

- "Iterative Pose Estimation using Coplanar Feature Points"
Denis Oberkampf, Daniel F. DeMenthon, Larry S. Davis

- js-aruco: Augmented Reality Marker Detector
http://code.google.com/p/js-aruco/

- Three.js: 3D Engine
https://github.com/mrdoob/three.js

Juan Mellado, 7 Diciembre, 2011 - 15:42

Un experimento rápido y un poco tonto con js-aruco usando las sombras como marcadores de realidad aumentada.


Demo online:
www.inmensia.com/files/aruco/debug/debug.html

Juan Mellado, 28 Noviembre, 2011 - 13:15

He hecho unas modificaciones a js-aruco para poder disponer de unas cuantas imágenes intermedias que permitan ir siguiendo con más detalle lo que hace la librería por dentro en cada frame. (Recomiendo ver el vídeo a pantalla completa)


Demo online:
www.inmensia.com/files/aruco/debug/debug.html

Las imágenes auxiliares muestran:
- La conversión a escala de grises
- El proceso de umbralización
- La detección de contornos
- La aproximación a polígonos
- Los polígonos candidatos
- La transformación de perspectiva
- La umbralización de los candidatos con Otsu

Y aún podría añadir algunas imágenes más, como la resultante del filtro gaussiano y la diferencia de esta con la de escala de grises que se utiliza para el proceso de umbralización, o algún tipo de información numérica, como el número de pixels contabilizados dentro de cada cuadrícula de los marcadores.

Actualizado 28/02/2012: He eliminado el uso de Flash, ahora la demo se debe ejecutar con Chrome 18 o posterior usando el flag --enable-media-stream en línea de comandos.