miércoles, 11 de octubre de 2006

Más sobre creación de imágenes, esta vez en color

En mi primer post (bueno el segundo) os conté cómo crear una imagen bidimensional a partir de un fichero de datos. En esta entrega os contaré como hacer lo mismo con color.

Para empezar, ya no crearemos un fichero pnm sino uno de tipo ppm. La diferencia reside en que los primeros cuantifican el color con un número entre 0 y 65535 y los segundos con una terna de números entre 0 y 255 que representan la cantidad de rojo verde y azul que contiene la imagen.
Para que entendáis mejor el código voy a crear un código intermedio que hace lo mismo que el del post anterior pero en el nuevo formato.

Así, el código en custión sería



#!/bin/bash

if [ $# -ne 3 ]; then
echo "Sintaxis: $0 Nx Ny fichero_de_entrada "
exit
fi

awk '
BEGIN{max=-100000000; min=100000000;}
{
for (i=1;i<=NF;i=i+1){ if (max<$i) max=$i; if(min>$i) min=$i;}
}
END{print max,min}' $3 | awk -v Nx=$1 -v Ny=$2 '
BEGIN{print "P3\n#\n\n" Nx,Ny "\n255 255 255"}
NR==1 {
max=$1;
min=$2;
}
{
for(i=1;i<=NF;i=i+1) { val=int(($i-min)*255/(max-min)) print val,val,val } }' - $3 >$3.ppm

Fijaos en la diferencias:
1) El tipo de archivo no es "P2" sino "P3".
2) En lugar de incluir una única escala (65535) incluimos tres (255 255 255).
3) Por cada pixel imprimo tres números (con el comando print val, val, val)

¿Qué necesitamos para crear una imagen en color? Pues muy fácil, una paleta. Las paletas permiten hacer una mapping entre un subconjunto de los números reales (entre min y max) a un espacio vectorial de tres dimensiones de enteros (entre 0 y 255).

Existen muchas paletas. Yo he usado una que cree hace siglos para una aplicación en basic que hice en el colegio. La versión awk sería la siguiente:

#!/bin/bash

if [ $# -ne 3 ]; then
echo "Sintaxis: $0 Nx Ny fichero_de_entrada "
exit
fi

awk '
BEGIN{max=-100000000; min=100000000;}
{
for (i=1;i<=NF;i=i+1){if (max<$i) max=$i; if(min>$i) min=$i;}
}
END{print max,min}' $3 | awk -v Nx=$1 -v Ny=$2 '
BEGIN{
for(i=0;i<128;i++) i="0;i<128;i++)" i="0;i<="255;i++)">255) r[i]=255; if(g[i]>255) g[i]=255; if(b[i]>255) b[i]=255;}

print "P3\n#\n\n" Nx,Ny "\n255 255 255"
}
NR==1 {
max=$1;
min=$2;
}
{
for(i=1;i<=NF;i=i+1) { val=int(($i-min)*255/(max-min)) print r[val],g[val],b[val] } }' - $3 >$3.ppm

La definición de la paleta está incluida en los bucles

for(i=0;i<128;i++) i="0;i<128;i++)">
El bucle que aparece a continuación de estas líneas es para comprobar que no hay errores de rango. Si queréis crear otra paleta, sólo teneís que definir las matrices r[], g[] y b[]. MATLAB tienes decenas de paletas definidas que probablemente se puedan exportar. Para que veáis un ejemplo os incluyo una imagen de unas simulaciones de un modelo de Crecimiento de Depósitos de Vapor (CVD).