Tres ejemplos de matemáticas discretas

Pueden consultar los post relacionados con los temas que vimos el día de hoy:



Por su puesto, revisen a detalle el excelente ejemplo de filtraje de electrocardiogramas. Finalmente, consulten el código para hacer la primera derivada. Uds. pueden hacer el código para hacer la primera integral de una función discreta.

¿Me falto mencionar algo? Dejen un comentario si necesitan más información u omití algo importante. 





Jugando con perfiles e histogramas en imágenes de Matlab

Entregar reporte de resultados, DE ESTA ENTRADA, antes del 19  de septiembre  2012

Las imágenes de prueba están en C:\MATLAB\toolbox\images\imdemos
Pruebe las siguientes funciones:
           
imagen bacteria, archivo
en escala de grises
X = imread('bacteria.jpg','JPG');     % probar al menos tres imágenes distintas
image(X);
colormap(map);
colormap(hot); colorbar;
pause
image(X);
liney=X(:,100);     % column profile (vert)
linex=X(60,:);       % row profile (horiz)
hold on; plot(linex);



Resultado de la primera rutina
1. Pruebe otros perfiles sin exceder las dimensiones de la imagen (recordar “size(X)”) e interprete dichos perfiles en función de la imagen

2.  Los valores de gris de los píxeles de una imagen son una población cuya distribución (frecuencia) permite caracterizar ciertas propiedades de la imagen, sin preservar información espacial (aunque depende de dónde se toman las muestras.   Pruebe las funciones de histograma de una señal, pero ahora en una imagen.   Implemente usted su propia función para calcular un histograma y grafiquelo en diferentes escalas.

Sugerencia (ejercicio: corregir índices definiendo por ejemplo H como subvector de otra matriz ):

% X se define como arriba:  una matriz que contiene la imagen.
H=zeros(256,1);    % iniciar vector de histograma a 0
[m,n] = size(X);    % obtener dimensiones
for i=1:m
  for j=1:n
     H(X(i,j)+1) = H(X(i,j)+1)+1;   % usar datos como direcciones para contra frecuencias
  end
end
plot(H);

3.  Calcule ahora su histograma en escala logarítmica, muestreando la imagen de manera uniforme; pruebe la función random.   Observe los detalles del histograma y pruebe otras escalas.  Comente sus observaciones.

4.  Si N es el total de pixeles, y se muestrean M. Calcule histograma de zonas de interés (un rectángulo que contenga las bacterias, por ejemplo).  Compare con histogramas del fondo en distintas áreas.  ¿Cómo se relacionan con el histograma global?   Repita 4. para una zona de interés (no del fondo).  

6. Compara la implementación de arriba con las funciones de histograma predefinidas en Matlab (úselas).

7.  Aumente el intervalo dinámico de los valores de gris (o sea el contraste) usando la información del histograma (recordar lo que se vio en clase), en uno global y en dos locales.  Para esto será necesario modificar los valores de gris de acuerdo al histograma.

8.   ¿Cómo definir y almacenar  su propia paleta de colores?  Diseñe una que vaya de café obscuro a color crema y de crema azul claro, de azul claro a verde.

Cómo transformar una figura de Matlab en una imagen portable.




Resumen
En esta ocasión se muestran las bases para que nuestras figuras en Matlab se exporten como archivos de imagen y se puedan incorporar en un procesador de textos.
Básicamente, existen cuatro caminos para exportar:

1) El copy-page; en la barra de menús de la imagen, damos clic en Edit y luego en Copy figure. Ya después podemos pegar nuestra información en otro programa, tal vez powerpoint.

2) Salvar como. Utilizando la interface gráfica de la figura Matlab, podemos cómodamente salvar nuestra figura en diversos formatos de imagen (png, pdf, jpg, etc.). Únicamente hay que seguir las instrucciones

3) Uso del comando print. Este comando es muy versátil y permite guarda las imágenes en varios formatos, controlar la calidad de pdi de la imagen e incluso automatizar el proceso de guardar-nombrar archivos. Además de ser el de mayor calidad. Mejor aún, utilizando previamente los comandos:

Set(gcf, ‘InvertHardcopy’, ‘off’)

Así, se preserva el color del fondo que nosotros escogimos previamente para la figura.

4) Impresión de pantalla. En el video omitimos esta opción para salvar las imágenes, pues no es propio de Matlab. El botón de ImprPant es muy general y depende de la resolución de tu monitor, suele mostrar elementos innecesarios que se deberían de corregir en un programa que manipule imágenes. Cuando se trabaja con muchas imágenes y se busca la mejor calidad, este camino se debe evitar

Contar con gráficas de alta calidad visual y de datos es vital para que nuestra publicación, tesis o trabajo escolar sea aprobado por los revisores; por ello no se debe descuidar la presentación de nuestras imágenes.

Preguntas para pensar
1) ¿Qué determina que la imagen sea de alta calidad?
2) ¿Por qué usar 300 dpi en esta clase de imágenes?, ¿Siempre es así?

Ejercicios
1) Introduzca en un ciclo for el comando print, de modo que obtenga 10 imágenes secuenciadas de una senoidal a la que se le varia la frecuencia o la amplitud.

Juntas, pero no revueltas: sub-gráficas en una misma figura de Matlab

Ejemplo del uso de subplot
El comando de Matlab subplot es lo suficientemente versátil para darle sendos ejes y características adicionales a las gráficas que coloquemos en una misma imagen.

Efectivamente, basta con indicar como se compondrá la matriz de la imagen (a,b) y que espacio p ocupará cada una de las gráficas; es decir, subplot (m, n, p) hace la división del espacio de la figura. Matlab asignara el espacio con en paneles regulares para cada gráfica. Este es un ejemplo simple de una rutina aplicada una figura compuesta de 2 gráficas.

Asignación simple de paneles
x= 1:0.1:2*pi;
subplot(2,1,1), plot(x)
subplot(2,1,2), plot(sin(x))

En general, el comando subplot brinda una figura de configuración simétrica de paneles, que son donde se colocan las gráficas. Y cada panel es independiente de los otros. Sin embargo, si el parámetro p es una matriz, entonces se puede ocupar más de un panel para una gráfica. Por tanto, en una misma figura se puede colocar una gráfica grande y otras más pequeñas. Por ejemplo usando el siguiente código:


Asignación asimétrica de paneles
x= 1:0.1:2*pi;
subplot(2,2,[1 2]); plot(sin(x))
subplot(2,2,3); plot(log(x))
subplot(2,2,4); plot(exp(x))

Finalmente, hay que destacar que se puede utilizar el subplot dentro de ciclos de programación, de forma que se pueden automatizar colecciones de imágenes que siguen una línea de historica. Por ejemplo:




Ejemplo del uso de  subplot
en un ciclo for
y = zeros(4,15); % se inicializa un vector, para ser más eficiente
for k = 1:4 % seran cuatro colecciones de datos
y(k,:) = rand(1,15); % se crea un vector de 15 elementos aleatorios
subplot(2, 2, k) % el índice se usa para dar orden a la secuencia de gráficas
plot(y(k,:)); % se hace la gráfica
end

Precauciones
Utilizando scripts, solamente se pueden crear estas gráficas cuando ya se cuenta con la matriz completa. En otro caso hay que utilizar comandos como drawnow, del que ya anteriormente hemos mostrado unos ejemplos.

Preguntas para pensar
1) Describa un ejemplo especifico donde los subplot en un ciclo for son aplicados


Ejercicios
1) Obtenga la siguiente imagen utilizando diferentes comandos de Matlab

Ejercicio de esta entrada

Dibujando gráficas como si fueran animaciones en Matlab

Manos dibujando
Matlab permite fácilmente crear gráficas; pero ¿qué pasa cuando queremos hacer una animación de esa gráfica? Por ejemplo, ir presentado cómo se produce la trayectoria de un cuerpo en movimiento. Con animaciones esta tipo de gráficas son espectaculares en cualquier presentación. En una entrada anterior trate un poco sobre este tema utilizando fotogramas.

Aquí, presentare ejemplos donde no se crea video.

Ingenuamente podemos usar un código simple, como el siguiente.

figure(1);
for i=1:1000
T(i)=cos(i);
plot(T);
end

Efectivamente, aunque no aprovechamos la ventaja de la preasginación de memoria, la idea es que no es importante la velocidad del cálculo, sino que se cuente con la construcción dinámica de la curva; por ello, el comando plot tiene ir dentro del ciclo for.

Sin embargo, hasta este punto, el código es inútil. Pues la reserva de memoria de los cálculos es independiente y asíncrona de la memoria gráfica. Es decir la gráfica se producirá cuando se cuente con el vector completo.  La solución es insertar un comando que actualice todas las ventanas ese comando es drawnow.

Con todo, nuestro código se puede estar ejecutando muy rápido; por lo que hay que añadir dentro del código una pausa (comando pause) al que se le puede controlar el tiempo de ejecución. Digamos que esperamos .3 segundos por iteración. De tal modo que nos da bastante tiempo para ver con comodidad los resultados, pero esto es útil cuando los cálculos son pocos.

Mi ejemplo de código entonces es:

figure(1);
for i=1:1000
T(i)=cos(i);
plot(T);
drawnow;
pause(0.3)
end

El factor comet

El comando comet es otra opción para darle movimiento a la construcción de nuestras gráficas. Sin embargo, para pocos puntos su ejecución es demasiado rápida para apreciarse. Por lo cual se requieren muchos puntos para poder apreciar la construcción. Una alternativa es disminuir el paso entre punto y punto o aumentar el intervalo del vector a graficar. Lamentablemente, este comando no tiene una opción para controlar la velocidad, y aunque se puede alterar el código original para cambiar la velocidad, no es muy recomendable si estas iniciando el arte de hacer código para Matlab.

Pero si sientes que tu experiencia es suficiente para hacerlo, pues te recomiendo ir a los foros del mismo Matlab Central donde te puedes dar una idea de cómo hacer tal alteración: foro1, foro2


El siguiente video te muestra el código y los resultados que obtengo.



Preguntas para pensar 

1) Sin que se cree un video en que casos particulares es más útil esta opción que la de crear un video en Matlab. Revisa nuestra entrada anterior  sobre la  creación de animaciones.

Ejercicios

1)  Realiza una rutina donde se pueda visualizar al mismo tiempo varias gráfica en un una sola ventana, puedes usar el comando subplot

2) Aplica esta solución para ver la dinámica una gráfica de tres variables (X,Y,Z) que cambia con el tiempo.

Uso de operaciones vectoriales en lugar de ciclos for para aumentar el desempeño de Matlab

Consideremos el siguiente ciclo, reescrito directamente de C o Fortran

dx = pi/30;
nx = 1+ 2*pi/dx;
for i = 1:nx
     x(i) = (i-1) * dx;
     y(i) = sin(3*x(i));
end

Todas las declaraciones anteriores son validas en Matlab, pero son ineficientes en el proceso de crear tanto a x como a y. Recordemos, Matlab localiza memoria para las variables cada vez que se les añade un nuevo miembro. Como ya lo comentamos en anteriormente en una entrada sobre reasignación de memoria RAM.
Entonces el mejor modo de crear los mismos dos vectores x y y es mediante los siguientes comandos:

x = 0: pi/30:2*pi;
y = sin(3*x);

La primera declaración crea al vector x; con 61 elementos que son almacenados en zonas continuas del RAM. La segunda declaración crea una nueva matriz, y, con el mismo número de elementos que x.

Matlab está diseñado para desarrollar eficientemente operaciones de matrices y vectores. Para tomar la ventaja máxima del hardware de la computadora; por tanto debemos utilizar operaciones vectoriales lo más que podamos.

Un ejemplo más sofisticado
A pesar que Matlab ajusta automáticamente el tamaño de una matriz (o vector) es mucho mejor predesignar la memoria de la matriz. La preasignación garantiza que los elementos de la matriz se almacenaran en zonas continuas de la memoria RAM y que sólo se realizara una vez este proceso.

Consideremos este ejemplo (que admito es artificial, pero didáctico) para crear dos vectores x y y:

dx = pi/30;
nx = 1 + 2*pi/dx;
nx2 = nx/2;

for i = 1:nx2
    x(i) = (i-1)*dx;
    y(i) = sin(3*x(i));
end

for i = round(nx2):nx
     x(i) = (i-1)*dx;
     y(i) = sin(5*x(i));
end

Aquí, conocemos desde el principio el tamaño de los vectores x y y. Así que reasignaremos la memoria creando un vector antes de que sus elementos sean individualmente asignados. Por lo común se utilizan las funciones ones y zeros para la reasignación de memoria; por ejemplo, de este modo:

dx = pi/30;
nx = 1 + 2*pi/dx;
nx2 = nx/2;

x = zeros(1,nx); % pre-allocate row-vectors, x
y = zeros(1,nx); % and y

for i = 1:nx2
x(i) = (i-1)*dx;
y(i) = sin(3*x(i));
end

for i = round(nx2):nx
x(i) = (i-1)*dx;
y(i) = sin(5*x(i));
end

Sin embargo, las declaraciones x(i) y y(i) no han tomado ventaja de la vectorización, aunque los elementos de x y y han sido almacenados continuamente en la RAM.

Así que mejoraremos estas declaraciones mediante un poco de vectorización. Por ejemplo, escribiendo:

x = 0:pi/30:2*pi; % vectorized calculation of x
nx = length(x);
nx2 = nx/2;

y = x; % pre-allocate memory for y

for i = 1:nx2
     y(i) = sin(3*x(i));
end

for i = round(nx2):nx
    y(i) = sin(5*x(i));
end

Finalmente, podemos observar que los cálculos de y puede también ser vectorizados. Por ejemplo, de este modo:

x = 0:pi/30:2*pi; % vectorized calculation of x
nx = length(x);
nx2 = nx/2;

y = x; % pre-allocate memory for y

y(1:nx2) = sin(3*x(1:nx2)); % compute first part of y
y(round(nx2):nx) = sin(5*x(round(nx2):nx)); % and the second part


En mi computadora, resulta que el aumento de velocidad fue de aprox. 1.2 veces. Es decir, utilizar los cálculos basados en vectores fue notoria la mejora. Sin embargo, en este ejemplo son pocos los elementos de los vectores. Mientras más grande es la matriz o vector, más significativo será utilizar vectorización en lugar de una reconstrucción de la matriz por medio del ciclo for.

Por cierto, para medir el tiempo de estos ejemplos, los he escrito como rutinas (scripts que los nombre ejemplo_vector.m) y utilice los siguientes comandos para medir el tiempo.

clear; tic; ejemplo_vector; disp( ['se tardo ' num2str(toc) 's.'] );

Y la salida de este ejemplo es la siguiente imagen:


Uso de pre-asignación de memoria en Matlab para aumentar la velocidad de cálculos

Fun home 1
Como en cualquier otra actividad, programar requiere seguir reglas para ser efectivo. Del mismo modo en que deberíamos limpiar nuestro cuarto de vez en cuando; debemos economizar la memoria de la computadora.

Por ello, en esta entrada, platicaré de las bases de la preasignacion de memoria (memory preallocation) en Matlab. La preasignación de memoria es una práctica excelente de programación que SIEMPRE debemos seguir.

¿De qué trata la preasignación de memoria en Matlab?

A diferencia de los otros lenguajes de programación, como C; Matlab “cuida” de la asignación de memoria automáticamente. Así cuando ejecutas un programa, Matlab reserva espacios de memoria para los datos de todas las variables que se utilizan. Y esto se basa en información local, de un modo similar como en el caso de los tipos de datos o el espacio necesario para todos los elementos.  Veamos un ejemplo con código Matlab:

X = 1:100;
Y = cos(X);

En la línea 1, Matlab identifica que X es un vector compuesto de 100 elementos de formato doble. Entonces reserva la memoria necesaria para cuando se emplee.

En la línea 2, Y es del mismo tamaño que X, de modo que Matlab reserva memoria antes de llenar el espacio con la información de la función cos(X).

Una consecuencia de este mecanismo es que CADA VEZ que se le pide a Matlab almacenar un nuevo conjunto de datos, Matlab realiza el proceso de asignar algo de memoria. Por ejemplo:

X = 1:100;
X(101) = 1;

En este ejemplo, X está compuesto inicialmente de 100 elementos; luego cuando se le ordena a Matlab que llene el elemento 101, implícitamente se le pide a Matlab que reasigne algo de memoria para que se pueda incluir el nuevo elemento de X.

¿Por qué tanto alboroto con la preasignación de memoria?

Para todos los datos en una matriz, Matlab requiere un proceso de memoria continua. Como resultado, si el espacio de memoria para el espacio 101 es solicitado; entonces Matlab copia todos los valores originales de X y los coloca en un nuevo sitio donde hay espacio para hasta los 101 elementos.

Veamos un ejemplo más extremo, si X esta hecho 100 mil elementos en lugar de 100, el tamaño de memoria para X es grande y estos grandes espacios de memoria no son tan fáciles de localizar. Es como querer estacionar un autobús turístico en el centro de la ciudad… toma bastante tiempo.

Es especialmente en los ciclos for cuando este proceso de asignación de memoria es notorio. Por ejemplo en esta rutina (script) al que llame ejemplo_memoria0:

for i=1: 100000
Y(i)=cos(i);
end

En este caso, a cada paso en el ciclo for, se le pide a Matlab que añada un elemento a la matriz Y. De hecho, se le pide a Matlab que engrose a Y en memoria a cada paso.

Al principio del proceso, es fácil y rápido; pues Y es pequeño. Pero a medida que progresa el ciclo, Y se hace cada vez más grande, de modo que Matlab debe encontrar espacios de memoria mucho más grandes. Por lo que se vuelve una pesadilla de asignare

La solución es simple: preasignación de memoria

La idea se basa en que tú sabes de antemano cual será el tamaño del vector, por ello se lo debes comunicar a la computadora antes de que entre en el ciclo for. Por ejemplo, la mayoría de las personas utilizan funciones como ones o zeros de este modo:


Y = zeros(100000,1);
for i= 1:100000
   Y(i) = cos(i);
end

En mi computadora viejita y sobre-explotada, la primera versión tarda: 21.6511 s; y utilizando la pre-asignación de memoria tarda en ejecutarse: 0.009333 s. Es decir, estos cambios significaron que: ¡¡~688 VECES AUMENTÓ LA VELOCIDAD DEL CÁLCULO!!


Ahora, se puede aumentar la velocidad un poco más. En lugar de gastar el tiempo llenado con ceros una matriz, se le puede pedir a Matlab que llene solamente el último elemento de un vector. Por ejemplo:

Y (100000) =0;
for i= 1:100000
Y(i) = cos(i);
end

En este último caso, la rutina tardo 0.009074 s. Este ahorro de tiempo es especialmente significativo cuando se construyen diversas matrices de gran tamaño.

Preguntas para pensar:
1) ¿Cuáles otras prácticas de programación se deben emplear para aumentar la eficiencia de nuestros programas?

Ejercicios
1) En la línea de comandos de Matlab, yo utilicé los siguientes comandos para medir el tiempo de ejecución de mi rutina:

clear, tic; ejemplo_memoria0; disp( ['se tardo ' num2str(toc) 's.'] );

a) ¿Qué hace los comandos tic y toc?
b) En este caso, ¿Por qué es necesario transformar un número en cadena de caracteres?
c) Crea una tabla con los tres ejemplos mostrados en esta entrada donde se muestre la diferencia de velocidades en los procesos de cálculo,
Related Posts Plugin for WordPress, Blogger...