inmensia |
Blog
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: 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
He publicado una nueva demo online con todos los cambios realizados: Estimación de la Pose 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 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 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
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" - js-aruco: Augmented Reality Marker Detector - Three.js: 3D Engine
Juan Mellado, 25 Febrero, 2012 - 11:13
Algunos apuntes sueltos sobre Dart, el lenguaje de programación para la web que está desarrollando Google. Programación estructurada #library("test");
#import("test.dart");
Constructores con nombre class Test {Privacidad class Test {Inicialización de variables de instancia class Test {Notación abreviada class Calculator {Parámetros opcionales class Test {final Test test = new Test();Interpolación de String final String hello = "Hello";Operador parte entera de la división value ~/= 17;Enteros de tamaño arbitrario Relación con JavaScript Dart trata de resolver los problemas que plantea JavaScript, como el uso de this por ejemplo. Y además de lo que es el lenguaje de programación en si mismo, también proporciona una serie de librerías completas, como hizo Java en su tiempo. Desde colecciones como arrays, listas, mapas y conjuntos, hasta soporte para realizar operaciones de entrada/salida con ficheros, uso de sockets, etc... Ejecución Errores El entorno de desarrollo es prácticamente un editor, basado en Eclipse, que apenas permite realizar las operaciones más básicas con los proyectos. Un ejemplo de esto es que ni siquiera se le puede cambiar el nombre a un fichero, ni borrarlo para crear uno nuevo con el nombre corregido. Pero lo peor sin duda es que aún no se puede depurar. Lógicamente están trabajando para añadir todas estas características. Durante mis pruebas he encontrado varios errores. He abierto las incidencias correspondientes en dartbug.com y todas las han aceptado como errores, e incluso alguno ya está corregido en el último build nocturno. Aunque creo que hay alguno que les va a llevar un poco más tiempo. He encontrado un error que hace el código se comporte de forma distinta en función de como se escriba. ¡Me ha traído literalmente de cabeza!. Al final he decidido no continuar la migración que estaba haciendo a Dart de LZMA. El algoritmo que está implementado funciona bien cuando se genera código en JavaScript, pero nunca va a poder funcionar bien en Dart con la especificación actual del lenguaje. El motivo es que LZMA basa su funcionamiento en operaciones a nivel de bit con una aritmética de tamaño entero (32 ó 64 bits) y precisamente en Dart los enteros no tienen tamaño predefinido. Estoy por borrar el proyecto.
Juan Mellado, 22 Febrero, 2012 - 18:47
El uso de la librería es muy sencillo, basta con importarla y llamar a la función de descompresión: #import("lzma.dart", prefix: "LZMA");
Aunque Dart viene con librerías que incluyen varios tipos de streams, he decidido aislar un poco mi librería de los posibles cambios en la implementación y definir dos interfaces propias muy sencillas: interface InStream {Llama la atención que en una interface haya definido un método He puesto un ejemplo completo en la página del proyecto, pero al final todo se reduce a instanciar dos objetos y llamar a una función: final InStream inStream = new InStream(data);La función de compresión está en desarrollo. He retrasado su desarrollo porque me ha desanimado bastante que el programa no funcione con la máquina virtual de Dart utilizando la línea de comandos. Eleva una excepción El entorno y el lenguaje tienen cosas curiosas, a ver si me animo a escribir un post con las cuatro cosas que he ido viendo. |