Para las imágenes vectoriales desarrollollamos una subclase de Image llamada MultiPlaneImage. Esto es así porque una imagen de pixels vectoriales ES UNA imagen. La relación ES UN(A) es lo que define la herencia en Smalltalk. Esto permite heredar tanto el protocolo como la implementación de la superclase. Dado que MultiPlaneImage ya hereda la variable de instancia donde almacenar los pixels, almacenamos todos los pixels en el mismo array, ubicando el pixel (x, y, z) en la posición ((y-1) * width + (x-1)) * planeCount + z del array, donde las coordenadas comienzan en 1, asi como la indexación del array.
Con referencia al iterador, se solicitaba que reciba una función. En Smalltalk es usual para ésto el uso de Bloques. No es preciso que el bloque tome como parámetro la imagen en cuestión, sino sólo las coordenadas de cada pixel. La implementación que hicimos permite, por ejemplo:
anImage xyIndexesDo:
[ :x :y |
anImage
atX: x y: y
put: ((anImage atX: x y: y)procesadoDeAlgunaManera) ].
este segmento de código opera tanto sobre imagenes escalares como sobre los pixels vectoriales de una imagen vectorial. Si, por el contrario, se desea operar sobre las componenetes escalares de una imagen vectorial, es posible:
anImage xyzIndexesDo:
[ :x :y :z |
anImage
atX: x
y: y
z: z
put: ((anImage atX:x y:y z:z)procesadoDeAlgunaManera) ].
este segmento de código opera únicamente sobre imagenes vectoriales
Para mostrar por pantalla las imágenes escalares de tipo Byte, los pixels se consideran tonos de gris. Para las imagenes Float, se hace stretching para adaptar el rango de los pixels realmente contenidos en la imagen a tonos de gris. Para las Integer, se toma la parte mas significativa como rojo, la del centro como verde, y la menos significativa como azul. Para mostrar por pantalla las imágenes vectoriales, se puede tomar 3 bandas como componentes Rojo, Verde y Azul, o tomar la norma de los vectores como tonos de gris. En ambos casos, la implementación lo que hace es solicitar mostrar por pantalla una imagen color de 32 bits, que es manejada por la máquina virtual del Smalltalk, para mostrarla sobre la pantalla realmente disponible. En este sentido, cabe mencionar que yo soy el implementador de la máquina virtual de Squeak para el sistema operativo OS/2. Esto incluye la conversión de las distintas profundidades de color a la disponible en la pantalla física, incluyendo modos de video paletizados, y técnicas de dithering para dar la ilusión de más colores que los efectivamente disponibles.
Implementamos los métodos correspondientes a las operaciones solicitadas. Asimismo se implementó la lectura y grabación de los formatos de archivo solicitados. También es posible leer archivos en formato BMP, GIF y JPG. Se incluyó en los comentarios de ambas clases una selección de ejemplos que ilustran el funcionamiento de las operaciones solicitadas. Implementamos también una interfaz al usuario para interactuar con las imagenes. Esta interfaz, juntamente con las clases Image y MultiPlaneImage ya descriptas, puede la base de una aplicación completa para el procesamiento de imágenes.
Un histograma dinámico incluye entradas únicamente para los valores de los pixels realmente presentes en una imagen. Esto hace posible manejar histogramas de imágenes con gran cantidad de valores posibles. Por ejemplo, las imágenes Integer o Float pueden tener 232 valores posibles. Es claro que una imagen de tamaño razonable utilizará únicamente un subconjunto pequeño de estos valores, ya que la cantidad de pixels sera mucho menor a 232. Adicionalmente, resulta imposible manejar arreglos de este tamaño, pero si la imagen entra en memoria, un histograma dinámico también será manejable. Sin embargo, la implementación de histogramas dinámicos resulta más trabajosa, necesitándose recurrir a una tabla de hash. En mi implementación usé una instancia de la clase Dictionary, que es justamente una tabla de hash.
La implementación la hice en dos clases, ImageHistogram y una subclase llamada StaticImageHistogram. ImageHistogram es un histograma dinámico, y acepta cualquier objeto como posible valor de los pixels. StaticImageHistogram hereda de ella, y redefine los métodos necesarios para funcionar como histograma estático, únicamente para imágenes con pixels de tipo Byte, por las razones ya expuestas.
Implementamos también una interfaz al usuario atractiva, integrada a la realizada para manejar las imágenes y accesible desde ella, que permite visualizar el histograma de una imagen.