Curso autodidacta/complementario de Matlab: videos, ejercicios, códigos y más ...
Mostrando entradas con la etiqueta Temas avanzados. Mostrar todas las entradas
Mostrando entradas con la etiqueta Temas avanzados. Mostrar todas las entradas
Cómo poner textura de imagen a una superficie 3D en Matlab
Resumen
Muchos video juego y simuladores usan texturas de imágenes sobre superficies de polinomios. Como si coloran una piel a un armazón. Aquí exploramos cómo se hace esta superposición en Matlab.
Además mostramos que se pueden cargar imagenes desde Internet a nuestro programa de Matlab.
Preguntas para pensar
1) ¿Cómo puede ser importante este programa para una aplicación médica?
2) ¿Cómo se eliminan las lineas guías (cuadricula) de la imagen 3D?
4) Las proyecciones planas se incorporaron a la superficie 3D. Lo que crea sitios con discontinuidades. ¿Como se puede mejorar el ajuste de una imagen que funciona como piel sobre una superficie digital?
Código Matlab
% Superficie 3D con una textura de imagen
% Inicialización
clear all; close all; clc; format compact;
% Constantes y valores iniciales
k = -.5; j = 0.6;
% Generando los valores x,y,z
[x,y] = meshgrid(-3:.2:3, -3:.2:3);
z = k.*(1-(cos(x.^2+y.^2))./(x.^2+y.^2+j));
% Dibujando la superficie
h = surf(x,y,z);
% Añadiendo una imagen a la superficie
img = imread('http://upload.wikimedia.org/wikipedia/en/5/5d/Ubinas_ali_2010205.jpg');
% Ubinas: el volcan más reciente de Perú
set(h,'CData',img,'FaceColor','texturemap')
axis off
% fin del guión.
Cómo hacer el símbolo del pentagrama con Matlab
Resumen
Un pentagrama es una estrella de cinco picos, hecha con cinco trazos. Tiene propiedades geométricas muy interesantes.
Para construirla, aquí dibujamos una linea horizontal, y la giramos mediante la función rot2d, cuyo al código encontraras al final de esta entrada. El guión del pentagrama se basa en dibujar una linea horizontal y luego rotarla. Sin embargo, se tiene cuidado de usar adecuadamente las definiciones de operaciones de matrices para obtener los vectores rotados.
Preguntas para pensar
1) ¿En que situaciones Matlab es una herramienta cómoda y adecuada para dibujar?, ¿y en situaciones Matlab es una pesima herramienta para hacer dibujos?
2) ¿Mejorando el entorno gráfico de Matlab, hace más amigable sus funciones de dibujo?
Ejercicios
1) Dibuje una estrella de David, utilizando de base los códigos de esta entrada
2) Explique con un ejemplo la importancia de de usar x = [x x(1)]; para obtener una rotación adecuada.
3) ¿En que coordenadas el punto en que gira la linea horizontal?, ¿Cómo puede especificar otro punto como pivote de los giros?
Códigos Matlab
function [xt, yt] = rot2d(t, x, y)
% La función rot2d rota un objeto bidimensional
% que es representado por dos vectores: X y Y
% El ángulo de rotación es t, en radianes.
r = [cos(t) -sin(t); sin(t) cos(t)];
x = [x x(1)];
y = [y y(1)];
z = r*[x;y];
xt = z(1,:);
yt = z(2,:);
%guión para dibujar el pentagrama
%% Pentagrama
% Author: Vicente Torres Zuñiga
%
% Guión Matlab para graficar el símbolo de un pentagrama en el sistema
% cartesiano
% El símbolo consiste en un círculo con un pentagrama en interior -un
% estrella de cinco puntas dibujada con cinco lineas %
%
% El algoritmo se enfoca en obtener las coordenadas de dibujo:
% primero de un circulo, luego de una linea horizontal, que posteriormente
% se rota para generar cuatro lineas para completar el pentagrama
%
close all; clear; clc % limpiamos la casa
num_puntos = 250; % número de puntos
t = linspace(0, 2*pi, num_puntos); % Intervalo
noLados = 5; % Número de lados del polígono
AnguloInt = 2*pi/noLados; % Ángulo interior del polígono
%
% Variables del círculo
r = 2; % Radio
h = 0; k = 0; % Coordenadas del centro
%
% Ecuación parámetrica del círculo:
x = r*cos(t)+h; y = r*sin(t)+k;
%
%% Ecuaciones para la linea horizontal
% Longitud de la linea horizontal
lH = 2*r*sin(AnguloInt);
% Distancia de la linea horizontal al centro: (0,0)
dist_lH = r*cos(AnguloInt);
%
% Definición del intervalo de la línea horizontal
xH = linspace(-lH/2, lH/2, num_puntos);
% Definición de vectores
L = zeros(2,num_puntos);
L(1,:) = xH;
L(2,:) = -dist_lH;
%
[L0rx L0ry] = rot2d(AnguloInt*0, L(1,:), L(2,:));
[L1rx L1ry] = rot2d(AnguloInt, L(1,:), L(2,:));
[L2rx L2ry] = rot2d(AnguloInt*2, L(1,:), L(2,:));
[L3rx L3ry] = rot2d(AnguloInt*3, L(1,:), L(2,:));
[L4rx L4ry] = rot2d(AnguloInt*4, L(1,:), L(2,:));
%
% Gráficas
hold on
plot(x,y, 'r', 'LineWidth', 4) % círculo
plot(L0rx, L0ry, 'LineWidth', 4) % línea horizontal
plot(L1rx, L1ry, 'LineWidth', 4)
plot(L2rx, L2ry, 'LineWidth', 4)
plot(L3rx, L3ry, 'LineWidth', 4)
plot(L4rx, L4ry, 'LineWidth', 4)
axis square off
hold off
% fin del guión/script
Cómo ocultar una imagen en una rejilla espacial con Matlab
Se han hecho populares estas imágenes en Facebook, son fotos ocultadas a través de una densa rejilla espacial. Te mostramos cómo hacer esta ilusión óptica con Matlab.
Básicamente, se trata de disminuir el contraste de las fotos, alejarse de los tonos oscuros y luego introducir muchas franjas oscuras en la imagen. El resultado es que percibimos primero franjas oscuras y claras, pues entre ellas hay más contraste, cuando cambiamos de perspectiva (al inclinar la pantalla o la cabeza o alejarnos de la imagen) o sacudir la cabeza podemos ver la imagen oculta.
Se trata más de una curiosidad que de un verdadero sistema de criptografía, asi que diviértanse con el código y las imágenes que dejo en esta entrada.
Preguntas para pensar
1) ¿Por qué aparece la imagen cuando cambiamos de perspectiva?
Ejercicios
1) Altera el código para que sea una función de cuatro parámetros, que de de salida una imagen .gif
Imagen utilizada
Guión Matlab
% A limpiar la casa
clear all; close all; clc;
% Cargar la imagen y ponerla en grises
im_fuente = rgb2gray(imread('maz.jpg'));
% cambia la clase de una variable
imgs = cast(im_fuente,'double');
% La imagen se ajusta a 60 tonos de gris,
img = 60*((imgs)./(max(max(imgs))));
img = img + 195; % desplazar los tonos a 195
% al final tengo tonos de 195 a 255
[f c d] = size(img); % el proceso es para cada capa
% Paso es el número de columnas negras en la imagen final
paso = floor(c/160); %redondea hacia abajo, frecuencia 1/160
for i = 1:2*paso:c
img(:,i:i+paso,:) = 0; %img suele tener tres capas
end
im_final = cast(img,'uint8');
imshow(im_final); % ver para creer
%fin del guión
Más información en la ref.
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.
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:
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:
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,
Suscribirse a:
Entradas (Atom)






