Introducción al Diseño


Identificación de objetos  básicos

Cuando uno estudia libros clásicos de tratamiento de imágenes o simplemente dialoga con algún desarrollador en el tema, encuentra que existe una especie de consenso en que una imagen es una matriz de píxeles. En consecuencia es común que la mayor parte del software al que se tiene acceso, esté implementado en: Fortran, Blitz, Matlab u otro lenguaje o biblioteca de propósito matemático. Anteriormente vimos que una biblioteca no es el ambiente natural para desarrollar apliciones de imágenes así que no vamos a volver a este punto; lo que nos interesa ahora es analizar la conveniencia de una matriz para representar una imágen.

Asumamos que es posible y eficiente tener una matriz de pixeles más generales que enteros o reales; ya que de lo contrario no sería posible representar imágenes sin caer en problemas como mantener tres imágenes para representar una en color por ejemplo. Es indiscutible que en estas condiciones una matriz de pixeles, es suficiente para mantener toda la información de una imagen digital 2D y no hay mejor prueba de esto, que el hecho que este tipo de implementación haya mantenido su vigencia, y mal o bien haya bastado para desarrollar todos los algoritmos existentes hasta ahora.

Nuestro grupo ha encontrado que aunque posible, una representación de una imágen digital con un arreglo de pixeles, no es adecuada para mantener toda la información de esta. Ejemplos tan simples como el de un histograma, ilustran el por que de lo anterior. Antes de pasar a ellos, destacaremos que si bien una matriz algebraica es un arreglo en el que es posible representar la imagen 2D, conceptualmente una imagen digital es distinta a esta. En consecuencia muchas operaciones o propiedades sobre matrices (como la inversa), carecen de sentido en imágenes y sin ir más lejos, imágenes 3D no son representables naturalmente en matrices algebraicas. Por eso de aquí en más nos referiremos al arreglo multidimensional con el que representamos en forma cartesiana a los pixeles que componen la imagen digital, como la "Implementación" de esta.

Supongamos que un algoritmo que calcula el histograma de cierta implementación monocromática, retorna en algún vector de datos (que de hecho es lo que hacía la biblioteca anterior). Si un programador desarrollara posteriormente otro algoritmo que hace uso de este histograma, como la equalización uniforme, el resultado sería sumamente inestable. Por ejemplo, si en el futuro se intentara generalizar el histograma para abarcar imagenes color, cualquier cambio en el tipo de datos colisionaría con el algoritmo de ecualización. La solución de compromiso inevitable es crear dos funciones distintas, aún cuando la mayor parte de estas sean comunes. Surge como consecuencia la necesidad de encapsular el histograma con el fin de dotarlo de una interface estándar, o sea transformalo en un tipo de objeto de la biblioteca. El histograma entonces debe existir como parte integral del framework y no como un objeto auxiliar del algoritmo de alguien, ya que en el último caso inevitablemente se tenderá a implementar múltiples versiones del mismo. Es cierto que para lograr incorporar un histograma al framework, es necesario dotarlo de una flexibilidad y generalidad muy por encima de la que podía tener nuestra primitiva versión, pero en contrapartida este trabajo se hará una única vez.

Podemos llevar la idea aún más lejos e imaginar que pasaría, si un programador quiere hacer cierta operación con los pixeles asociados a algún valor en el histograma (como equalizarlo). En este caso una solución siempre posible es volver a recorrer la imagen en busca de los pixeles, pero la idea choca inmediatamente con nuestro sentido común; no es práctico re-calcular el histograma cada vez, sobre todo si los valores de los pixeles cambian con cada iteración. Por las mismas razones que en el ejemplo anterior, es conveniente tener objetos adicionales que me permita ligar valores de pixeles como en el ejemplo, con posiciones en la implementación.

Ambos objetos tienen un común denominador; son vistas de la implementación, esto es: se calculan a partir de esta y por lo tanto no agregan información. Aún así son muy importantes, ya que me dan solo la información que necesito y de forma conveniente, en un instante dado.

Al mismo tiempo ambos objetos son distintos en un aspecto. Mientras el histograma crudo es un resultado final desconectado por completo de la implementación, el segundo está fuertemente asociado a esta y me permite ver (incluso modificar) pixeles.

La identificación de estos objetos fue una de las partes que requiró más tiempo y esfuerzo, así que no nos extenderemos más en ejemplos y presentaremos las que a nuestro entender, son las categorias de objetos que enriquecen la representación de la imagen, acercándola a nuestra idea abstracta.
 

La imagen abstracta

Un imagen abstracta es el agregrado de cuatro tipos de objeto como se muestra en el siguiente esquema.
A continuación daremos una definición formal y una explicación cada uno.

Implementation

Es la representación espacial de la imagen digital en un arreglo mutidimensional de pixeles, accesibles a través de sus coordenadas cartesianas. Es completa y siempre está presente.

Dexel

Representación no necesariamente completa de una imagen en pixeles o atributos de estos, según un criterio no espacial, pero manteniendo referencia a las posiciones en la implementación.

Transformed

Representación completa de la imagen alternativa a la implementación, en la que no existen correspondencias directas de los tipos en sus pixeles con los de la esta última. 

Property

El resultado de cualquier función sobre cualquiera de los componentes de la imagen abstracta, siempre y cuando este no sea de tipo: Implementation, Dexel o Transformed.
La implementación de una imagen es el primero de los objetos y el que debería despertar menos dudas, ya que es el que todo el mundo usaba para representarla antes de BICOTI.

El primer objeto novedoso es el Dexel. Su ingenioso nombre ( contracción de DESCriptive ELement ) fue uno de los muchos aportes que el Dr. Hans Schmid hizo a nuestro proyecto. En esencia son una forma de mantener conjuntos de pixeles de la implementación, clasificados según algún criterio. Ejemplos de Dexeles son: regiones, el resultado de un labeling, la extensión del histograma que asocia a los valores las posiciones en la implementación e incluso curvas definidas en la misma. Los ejemplos muestran la diversidad y como resultado, la poca interfaz común a todos. Los Dexeles solo comparten su protocolo de actualización con la implementación, y la estructura de su arquitectura intenta más ser un ejemplo de crecimiento ordenado, que una forma de re-usar código o lógica. Aún así existen fuertes relaciones entre ellos como veremos adelante, que muestran la conveniencia de su clasificación.

La transformada es básicamente el resultado de cualquier transformación invertible que al ser aplicada a la implementación, cambie la naturaleza de los pixeles en esta. Si bien es conceptualmente diferente a la implementación, aprovechamos la enorme generalidad de los pixeles en Bicoti para guardar su información en otra implementación; pudiendo de esta forma re-usar todos los algoritmos definidos para esta. El acceso a los datos suele hacerse a través del objeto que encapsula el algoritmo, ya que este es el que conoce las características de la transformación concreta. Esta separación entre abstracción e implementación es el bridge discutido en los design patterns. Un ejemplo de transformada es la de Fourier.

Las propiedades son el resto de los objetos con datos de la imagen. Existen propiedades asociadas a la implementación como el valor medio de los pixeles, otras asociadas a dexeles particulares como el baricentro de una región e incluso pueden existir propiedades asociadas a transformaciones u otras propiedades. Los primeros dos ejemplos claramente son propiedades ya que no tienen porque estar asociados a pixeles o atributos de estos en la implementación, esto es no son Dexeles, ni obviamente son el resultado de alguna transformación invertible sobre esta. Otros ejemplos son más ambiguos; pensemos en el máximo valor de los pixeles en una implementación (suponiendo que la comparación está definida para estos). Esta es una propiedad pero si asociamos al valor, los puntos de la implementación donde este se alcanzan tendremos un dexel. Existen un par de ejemplos de estos casos duales, en los que a veces se tienen simultaneamente una propiedad asociada a un dexel; así como otros en los que una propiedad se calcula a partir de un Dexel.