Documentación FPanorama

Práctica 1 de TIA. Universidad De Alicante

Autor: Ernesto Azuar Valenzuela (lanshor@gmail.com)


1. Introducción

El objetivo es desarrollar una inteligencia artificial que detecte puntos característicos de una secuencia de imágenes y opere con ellas para formar una sola imagen panorámica final.

La forma de implementación será en una función para javavis que esté perfectamente integrada en el programa, y que admita diversos parámetros de entrada para poder ajustar el comportamiento de la IA.

2. Método y Diseño

Para cada imagen de la secuencia he calculado los puntos característicos aplicando el método de Nitzberg. Para corresponder cada punto con su honónimo de la imagen contigua he usado el test de correlación cruzada con un tamaño de ventana especificado por el usuario (por defecto 8 píxeles de radio). Además intento descartar los puntos ambiguos usando un factor lambda (por defecto 0.95).

El test de correlación cruzada se efectua para cada par de puntos según la siguiente expresión:

CC = i n [ ( I 1 i - m 1 ) * ( I 2 i - m 2 ) ] i n [ ( I 1 i - m 1 ) ] 2 * i n [ ( I 2 i - m 2 ) ] 2

n: número de píxeles de la ventana
m: media aritmética de la intensidad en escala de gris de la ventana

Finalmente descarto aquellos puntos posiblemente ambiguos usando el factor lambda, de forma que sólo considero válidos aquellos puntos para los que sea cierta la siguiente condición:
CC 1 λ > CC 2

Por cada pareja de puntos válida creo un vector de traslación con la presunta transformación adecuada que he de aplicar a la imagen. Finalmente hago la media aritmética de todas las transformaciones y obtengo la transformación final.

2.A. Optimizaciones


3. Ejecución y Funcionamiento

Esta es la pantalla de configuración con los parámetros para FPanorama:

Parámetros:

4. Desarrollo y Pruebas

Cuando hacemos fotos con una cámara convencional, a pesar de intentar hacer traslaciones perfectas de nuestra posición (sin rotar ni cambiar la profundidad de la cámara) lo normal es que la cámara gire y rote levemente. Debido a esto la perspectiva cambia completamente y las imágenes resultantes no pueden ser unidas de forma suave y perfecta (este efecto se mitiga cuando se fotografían paisajes y escenas en las que todos los objetos están muy lejanos, pues simulan ser un plano frontal 2D).

Así que lo primero para probar si el algoritmo funciona bien es huir de las imágenes reales y hacer pruebas con imágenes enteras, cortadas a propósito para la ocasión, y dejar que la IA trate de unirlas como si de un puzzble se tratase.

Nota: Dentro de la carpeta "imagenes/perfectas" de la entrega están todas las imágenes usadas en esta sección.

Ejemplo 1: Mi hamster

Usando los parámetros por defecto y la siguiente lista de imágenes:



Lista de imágenes usadas

La función devuelve el siguiente resultado:


Resultado final con parámetros por defecto

Ejemplo 2: Una mantis en la universidad

Usando los parámetros por defecto (y activando "steps"), y la siguiente lista de imágenes:




Lista de imaǵenes usadas

La función devuelve el siguiente resultado:


Resultado devuelto con parámetros por defecto

Y el poster con la evolución:


Cada imagen N del poster es el resultado de fusionar las imaǵenes N-1 y N-2.

Ejemplo 3: Lenna (L)

Lenna es una imagen muy especial, porque tiene muy poco contraste y todos los colores son planos y de tonos pastel. Por ello es necesario usar un tamaño de ventana mayor para obtener el resultado correcto. Usando la siguiente lista de imágenes y los parámetros por defecto:




Lista de imágenes usadas

La función devuelve el siguiente resultado:


Resultado con ventana de radio 8

Este resultado, aunque es aproximado es incorrecto. Dadas las características de la imagen, es necesario ampliar el tamaño de ventana. Sin cambiar nada más que el radio de la ventana de 8 a 16... el resultado devuelto ya es perfecto:


Resultado con ventana de radio 16

Ejemplo 4: Mi Ordenador

En esta imagen sucede lo mismo que con Lenna (esta vez, aunque hay colores brillantes, todos brillan en la misma intensidad de gris):




Lista de imágenes usadas

La función devuelve el siguiente resultado:


Resultado con ventana de radio 8

Este resultado, aunque bastante bueno, es incorrecto (se aprecian saltos). Sin cambiar nada más que el radio de la ventana de 8 a 16... el resultado devuelto ya es perfecto:


Resultado con ventana de radio 16

Ejemplo 5: Las montañas

Una vez comprobado que la IA funciona perfectamente con imágenes perfectas, es hora de ponerla a prueba con las imperfectas imágenes reales:


Lista de imágenes usadas


Resultado con valores por defecto


Poster con el desarrollo

Ejemplo 6: Puente



Lista de imágenes usadas


Resultado con valores por defecto

Ejemplo 7: San Francisco



Lista de imágenes usadas


Resultado con valores por defecto

Ejemplo 8: Ópera de Sídney


Lista de imágenes usadas


Resultado con valores por defecto


Poster con el desarrollo

Ejemplo 9: Mi balcón

Por último he tratado de unir 4 fotos hechas desde mi balcón (Ventana de radio 16). Estas fotos incluyen mucha rotación y suponen la prueba final para el algoritmo. Como nota adicional cabe destacar que la unión de estas imágenes ha tardado unos 7 minutos (en Core2Duo 2GHz, 1Giga de RAM) en llevarse a cabo.


Lista de imágenes usadas


Resultado con valores por defecto

A pesar de la lentitud... el resultado es más que convincente :)

Conclusiones

La efectividad del algoritmo pasa por elegir los parámetros adecuados. En imágenes con muchos pequeños detalles un tamaño de ventana excesivo puede producir errores importantes, en imágenes con pocos puntos un tamaño de ventana insuficiente también producirá errores muy visibles. El factor lambda por defecto (0.95) y el Threshold para Nitzberg han funcionado bastante bien en todas las pruebas que he hecho, sólo ha sido necesario ajustar el tamaño de ventana.

En la práctica es el usuario el que debe experimentar con los parámetros para obtener el mejor resultado, he proporcionado unos parámetros por defecto que funcionan bien para la mayoría de las imágenes, pero esto no es suficiente para garantizar el mejor resultado.

La velocidad del algoritmo es su punto más débil, si bien creo que podría mejorarse sustancialmente si javavis proporcionase métodos mejores para trabajar con los datos de las imágenes. Leer y escribir píxel a píxel es muy costoso, con métodos para obtener píxeles de una banda en fragmentos cuadrados de una imagen devueltos en forma de array, y con métodos para escribir esos fragmentos en posiciones específicas la velocidad se incrementaría de forma muy muy notable.

Dado el coste computacional (tanto espacial como temporal) del algoritmo, trabajar con secuencias largas de imágenes grandes se hace imposible.

Implementación

El código es bastante claro y no necesita demasiados comentarios. Cada función realiza una parte del algoritmo según indica su nombre y su descripción (mirar comentarios en el código). La función processImg ha sido rescrita para no hacer nada (sólo se trabaja con secuencias).

La función processSeq ha sido rescrita para adaptarla al funcionamiento del programa. El método principal es Process(JIPImage), que recibe una imagen de la secuencia y la fusiona con las anteriores.

Process(JIPImage) debería ser la función de partida para leer el código, es una estructura clara del algoritmo seguido.