FORMATOS DE IMAGENES DIGITALES Y SU MANEJO EN C/C++. Cosme Rafael Marcano Gamero, Msc. DEA. Profesor del Dpartamento de Igeniería Electrónica de la Universidad Nacional Experimental Poltécnica “Antonio Josñe de Sucre” Vicerrectorado Puerto Ordaz. Urb. Villa Asia, final Calle China. Puerto Ordaz 8040. Estado Bolívar - Venezuela
[email protected]
INTRODUCIÓN La captura, edición y portabilidad de las imágenes y videos ha tenido un vertiginoso avance y popularización en recientes años debido a la sustitución del ahora obsoleto proceso analógico basado en la exposición de una película química, impresionable con la luz, a través de un pequeño diafragma, por un período de tiempo de duración y amplitud controlada, que luego era seguido de un proceso de revelado e impresión, lo cual exigía conocimientos no sólo de fotografía, sino también de un poco de química. Todo ese proceso ha sido suplantado por el uso de formatos digitales, que no son más que representaciones numéricas fáciles de manejar por la computadora. La utilización de estos formatos digitales hacen posible la transferencia de esos bits en forma serial, conforman un caudal de ceros y unos, que van siendo debidamente acomodados en forma de matrices bidimensionales, en filas y columnas que, después de ser acondicionadas, y reconstruidas, permiten ver la imagen en cualquier dispositivo digital adecuado, como pantallas de computadoras y celulares. Para manejar esas imágenes en forma estándar y lograr la portabilidad entre diversas plataformas computacionales, se han desarrollado muchos formatos digitales, de los cuales se han popularizado unos cuantos, como el “mapa de escala de grises” o PGM [1] ,“mapa de bits” o BMP [2], el JPG, y el GIF, entre otros.
III. Formato PGM. Uno de los primeros formatos para guardar imágenes monocromáticas y en escalas de gris es el Portable Gray Map (.pgm), [1] , o mapa de gris portátil; la portabilidad le viene del hecho de poder ser visualizado en cualquier plataforma de hardware.
Por su simplicidad, este formato ha tomado un papel estelar en el desarrollo de algoritmos de detección e identificación de objetos en imágenes digitales. De hecho, La Transformada de Rasgos Invariantes en Escala (o SIFT, por las siglas en inglés de ScaleInvariant Features Transform), propuesta por D. Lowe en 1998 [3], requiere que las imágenes que vayan a ser analizadas con esa transformadas sean previamente convertidas a formato pgm de 15 tonos de gris, es decir el tipo P2, que se explica más adelante, Asimismo, otras transformadas similares requieren la misma conversión de formato, por lo que es un procedimiento estándar ofrecido por la librería para aplicaciones de Visión por Computadora conocida como OpenCV (Open source Computer Vusuion
library), desarrollada por la Intel Corporation, Inc., [4]. En las secciones siguientes se describirá la estructura de archivos pgm y bmp, los cuales contienen la dará de los pixeles correspondientes a imágenes en estos formatos.
III,a. Descripción del formato PGM monocromático (1 bit) y escala de grises (4 bits) . El formato pgm es bastante sencillo de manejar. Por ejemplo, a continuación se muestra el contenido de un archivo que he denominado cuadritos.pgm, y que corresponde a la siguiente imagen:
Figura 1. cuadritos.pgm
El contenido del archivo cuadritos.pgm, el cual se puede ver con ayuda de un simple editor de texto, es: P1 # línea de comentarios opcional 15 10 1 010101010101010 101010101010101 010101010101010 101010101010101 010101010101010 101010101010101 010101010101010 10101010101010 1 010101010101010 10101010101010 1
Figura 2. PGM monocromático, cuadritos.pgm
La primera línea corresponde a la identificación del formato: P1 indica el formato monocromático de 1 bit, y sólo puede representar imágenes en blanco y negro. P2 identifica el formato en escala de gris a 16 tonos, desde el negro (0) hasta el blanco (15), etc. Existe un formato especial que es P5, el cual es almacenado en binario y no en texto. La segunda línea comienza con el símbolo #, y sirve para agregar algún comentario opcional. La tercera contiene el número de columnas, separado del número de filas por al menos un espacio; ambos números expresados en decimal. En este caso, son diez filas por 15 columnas. La cuarta línea contiene el número máximo que puede aparecer dentro de la matriz de 10x15, que aparecerá a partir de la línea siguiente. Así, para el formato P1, ese valor es 1, para el P2 es 15, etc. En todos los casos, ese valor representa un pixel en blanco. Las siguientes líneas contienen los pixeles que conforman la imagen, la cual se mostrará en pantalla desde el tope hasta el final. Cada línea es una fila de pixeles. Cada fila debe contener la misma cantidad de pixeles, separados al menos por un espacio en blanco. El archivo termina con un newlin, i.e., una línea en blanco. La implementación del formato PGM a 4 bits permite obtener imágenes a 2^4 = 16
tomos de gris, desde el 0000b (0 dec.) que corresponde al negro (ausencia de color), hasta el 1111b (15 dec.), que representa la combinación de todos los tonos. La Figura 3 muestra una ejemplo de un archivo en este formato. P2 # línea de comentarios - opcional 17 11 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0
Figura 3. PGM a 16 tonos de gris, degrade.pgm
La imagen correspondiente a este archivo, degrade.pgm, se muestra a continuación.
Figura 4. Imagen contenida en degrade.pgm
Como se puede observar en La Figura 4, la imagen está conformada por 11 filas, que degradan desde el negro hasta el blanco, pasando por 16 tonos. Cada fila es seguida de una línea en blanco, conformada sólo por 15. Nótese, además, que para marcar el lado derecho de la imagen, se agregó un 0 al final de cada fila, con lo cual se formó una línea negra vertical). Existen dos formatos básicos para los archivos pgm: texto (P1, P2,...) y binario (P5). Para crear imágenes sencillas en representación tipo texto, se puede utilizar cualquier editor que utiliza caracteres ASCII (o ISO-8859). Por otra parte, para visualizar y editar los contenidos de un archivo pgm tipo P5, se necesita un editor hexadecimal, es decir, uno que muestre los contenidos en formato hexadecimal en lugar de mostrarlos en binario.
II.b. Cómo crear un archivo pgm desde un programa en C/C++. Con mucha frecuencia surge la necesidad de graficar los resultados obtenidos por aplicaciones de cálculo e incluso en juegos o aplicaciones didácticas. La plataforma de hardware y software multimedia ha sido desarrollada para satisfacer esos requerimientos gráficos. Es así como, además del desarrollo de superficies para despliegues digitales, como las pantallas de computadoras o de teléfonos celulares, se han desarrollado formatos gráficos de archivos que permiten construir, almacenar, editar y transmitir imágenes en formato digital. En general, las imágenes se representan en matrices de dos dimensiones, cuyos elementos son una representación numérica de las características de color de cada pixel, es decir, de cada uno de los pequeños puntos en que es dividida la “superficie” sobre la
cual se mostrará la imagen. Para obtener una mejor calidad de imagen, se incorporó el color y el número de pixeles debe ser más grande. En imágenes a color, de baja resolución, como en las pantallas de los celulares, la cantidad típica de pixeles es de 480 pixeles/columna, por 320 pixeles/fila (es decir, una resolución de 480x320 = 153600 o 150 kB). Por comparación, una pantalla de computadora de baja resolución, posee 800x640 pixeles, o sea, poco menos de medio megabyte de memoria. En el caso del formato pgm a 16 tonos (P2), el archivo que contiene la data de una imagen puede ser generado por medio de la función int escribirMatrizEnArchivo(string ident, int X[], int n, int m), codificada en el lenguaje C++, [5], tal como se muestra en la Figura 5; la función asume que la data correspondiente a los nxm pixeles han sido previamente almacenados en una matriz, cuya dirección inicial es pasada como argumento de dicha función. int escribirMatrizEnArchivo(string ident, int X[], int n, int m){ string _acorde = "MiMenor.pgm"; // lo de _acorde viene de la variable
aplicación...
es
sólo
un
nombre
de
ofstream miArchivo(_acorde.c_str(), ios::out); if (miArchivo==NULL) { cout