在MATLAB中,可以用两种方法创建动画序列:
保存很多不同的图片,然后以电影的形式进行显示;
在屏幕上连续擦除和重画对象。每次重画都作递增式的改变。
动画适合于每一帧都相当复杂,不能快速重画的情况。可以先创建每个动画帧,回放时与原来绘制动画帧的时间没有关系。动画不是实时绘制的,它只是预先绘好的一系列帧的回放。
动画的第二种技巧,即绘制、擦除,然后重绘,确保MATLAB支持不同的绘图模式。这些模式允许在损失部分绘制精度的情况下,进行快速绘制。必须想好选择哪种模式。
以电影方式创建动画
可以保存任何图形序列,然后回放它。这里有两个步骤:
用getframe获取每个动画帧;
用movie命令运行动画。
一般地,在一个for循环中使用getframe命令组合动画帧的数组。getframe命令返回一个具有下列字段的结构。
cdata 以uint8型矩阵保存的图像数据。在索引颜色系统上,矩阵具有height×width维;在真彩色系统上,具有height×width×3维。
colormap 是一个n×3的矩阵,其中n是颜色个数。在真彩色系统上,colormap字段是空的。
下面演示如何用动画可视化fft(eye(n)),它是一个复杂的n×n矩阵。
1) 创建动画
下面的代码在一个for循环中调用getframe函数捕获图形。因为plot命令重置坐标轴属性,在使用getframe前调用axis equal语句。
for k=1:16
plot(fft(eye(k+16)))
axis equal
M(k)=getframe;
end
生成图2-23。
图2-23 用getframe函数获取动画帧
2) 运行动画
生成动画以后,可以将它回放任意次。例如回放30次,键入
movie(M,30)
在大部分计算机上,可以有序地创建和平稳回放数十帧动画。更多帧的动画需要计算机具有更大的内存或更有效的虚拟系统。
如果试图捕获整个图形窗口的内容,把图形句柄作为参数指定给getframe命令。例如,添加一个滚动条来指示上例中的k值。
h=uicontrol('style','slider','position',...
[10 50 20 300],'Min',1,'Max',16,'Value',1)
for k=1:16
plot(fft(eye(k+16)))
axis equal
set(h,'Value',k)
M(k)=getframe(gcf);
end
本例中,动画帧包括整幅图形。下面使回放坐标系充满整个图形窗口。
clf
axes('Position',[0 0 1 1])
movie(M,30)
for k=1:11,x=k-6;y=sin(x);plot(x,y,'o'),axis([-5 5 -1 1]),M(k)=getframe;end
以重绘方式创建动画
可以用hold on结合pause命令绘制动画过程中图元运动的痕迹。使用hold on保留原有的图形,用pause命令使动画的速度可控。
通过动态改变图元控制点的坐标数据并重绘图形来实现动画,此时不保留图元运动的痕迹。
下面的例子用名为Lorenz奇异吸引子的非线性差分方程描述无序运动。该方程具有下面的形式
y(t)为矢量值函数,矩阵A由y确定,即
本例用最简单的欧拉法,采用固定步长进行求解。结果不是很精确,但是它与其他方法具有相同的定性行为。
A=[ -8/3 0 0; 0 -10 10; 0 28 -1 ];
y=[]';
h=0.01;
p=plot3(y(1),y(2),y(3),'.', ...
'MarkerSize',5);
axis([0 50 -25 25 -25 25])
hold on
for i=1:4000
A(1,3)=y(2);
A(3,1)=-y(2);
ydot=A*y;
% 改变坐标
y=y + h*ydot;
plot3(y(1),y(2),y(3),'.', ...
'MarkerSize',5);
hold on
pause(0.01)
i=i+1;
end
hold off
动画演示点的无序运动,最后生成图2-24。
图2-24 描述无序运动
下面的代码通过动态改变图元控制点的坐标数据并重绘图形来实现动画,此时不保留图元运动的痕迹。
A=[ -8/3 0 0; 0 -10 10; 0 28 -1 ];
y=[]';
h=0.01;
p=plot3(y(1),y(2),y(3),'square', ...
'MarkerSize',10,...
'MarkerEdgeColor',[],'MarkerFaceColor',[1 .7 .7]);
for i=1:4000
A(1,3)=y(2);
A(3,1)=-y(2);
ydot=A*y;
y=y + h*ydot;
set(p,'XData',y(1),'YData',y(2),'ZData',y(3))
drawnow
i=i+1;
end
此时,会将原来的图形擦除,只能看到一个运动的点。