Friday, June 30, 2006

Un pequeño código en awk para crear imágenes a partir de una lista de números reales

El truco de hoy consiste en lo siguiente. Supongamos que hemos hecho una simulación de un problema en dos dimensiones, o en una pero queremos representar en una figura el espacio (eje x) y el tiempo (eje y). Podemos integrar una rutina en nuestro código (lo cual lo ralentiza) o podemos crear la imagen mediante un software de visualización (por ejemplo MATLAB).

Lo que yo os propongo es más sencillo, utilizar un pequeño script basado en la shell bash y en el potentísimo awk (o gawk) para crearlo.

Así, supongamos que tenemos un fichero con una lista (o matriz) que contiene los dimension_x*dimension_y valores de nuestra figura (por ejemplo en un problema de crecimiento para un sistema 100x100, el fichero sería una lista de 10000 líneas que contienen el valor de la altura en cada uno dos los 100x100 puntos). Se supone que ese fichero lo crea nuestra aplicación.

Una vez que tenemos ese fichero (llamémosle height.dat), creamos un fichero de texto (llamado, p. ej. array2pnm) que contenga la siguiente información




#!/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 "P2\n#\n\n" Nx,Ny "\n65535"}
NR==1 {
max=$1;
min=$2;
}
{
for(i=1;i<=NF;i=i+1)
print int(($i-min)*65535/(max-min))
}' - $3 >$3.pnm



Y lo ejecutamos con la siguiente sintaxis

./array2pnm 100 100 height.dat

Este comando creará el fichero "height.dat.pnm" que se puede visualizar con cualquier programa (por ejemplo display). Si queremos convertirlo a otro formato existen infinidad de librerías. Yo os recomiendo que instaléis el paquete ImageMagick que viene con todas las distribuciones de Linux. Tiene un programa llamado "convert" que hace todo el trabajo.

Por ejemplo

convert height.dat.pnm height.gif

Y ya está...

5 Comments:

At 5:14 PM, Blogger aepyornix said...

Muy bonitas las imágenes que salen. Pero tengo dos preguntas:

1) ¿Los datos del fichero de input tienen que ser enteros o pueden ser reales?

2) ¿Se pueden hacer figuras en color?

 
At 5:16 PM, Blogger aepyornix said...

This comment has been removed by a blog administrator.

 
At 11:19 PM, Blogger Mario Castro said...

Los ficheros pueden ser numeros reales o numeros enteros. Podéis hacer la prueba con un fichero aleatorio que podeis generar con el siguiente mini-codigo (y esto podría ser otro post :-). Por ejemplo para generar 100x100 datos aleatorios reales podéis teclear en la consola


awk 'BEGIN{for(i=0;i<=10000;i=i+1)print rand()}'


La segunda pregunta es algo complicada y ese sí que será el tema de otro post. Como adelante os diré que
1) El formato en lugar de pnm tiene que ser pnm. Cada "pixel" en lugar de estar representado por un número entre 0 y 65535 está representado por tres números entre 0 y 255 que representan la cantidad de rojo verde y azul
2) Para crear la imagen con colores hay que definir una matriz de transformación de los números reales al espacio tridimensional de los colores

Pero eso, es otra historia

 
At 4:31 PM, Blogger aepyornix said...

¿Quiere eso decir que el programita toma el mayor número como blanco y el menor como negro (o viceversa)? Eso puede ser un problema si se pintan varias figuras y quieren verse en una misma escala.

 
At 6:08 PM, Blogger Mario Castro said...

Efectivamente el menor es el blanco y el mayor es el negro.

Es trivial evitar que esto sea así. De hecho el codigo queda más corto (aunque el programa debería aceptar más parámetros)

#!/bin/bash

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

awk -v Nx=$1 -v Ny=$2 -v min=$4 -v max=$5 '
BEGIN{print "P2\n#\n\n" Nx,Ny "\n65535"; }
{
for(i=1;i<=NF;i=i+1)
print int(($i-min)*65535/(max-min))
}' $3 >$3.pnm

 

Post a Comment

<< Home