【MATLAB绘图进阶教程】(2-6)动态绘图制作详解与例程,包括drawnow、pause、getframe、video write等命令

在这里插入图片描述

MATLAB动画制作完全指南:从基础的实时图形更新到专业视频制作,掌握drawnow、getframe、VideoWriter等核心技术,轻松创建流畅的三维旋转动画和科学可视化视频。

实时更新图形 - drawnow 与 pause

基本语法

drawnow           % 立即更新图形
drawnow limitrate % 限制更新速率
pause(t)          % 暂停t秒
pause             % 暂停直到按键

使用场景

  • drawnow: 强制MATLAB立即更新图形显示
  • pause: 控制动画播放速度
  • 创建流畅的实时动画效果

简单示例

% 简单的动态正弦波
figure;
x = 0:0.1:4*pi;
h = plot(x, sin(x), 'b-', 'LineWidth', 2);
xlabel('X'); ylabel('Y'); title('动态正弦波');
grid on;

% 动态改变相位
for phase = 0:0.2:4*pi
    y = sin(x + phase);
    set(h, 'YData', y);
    title(sprintf('动态正弦波 (相位: %.1f)', phase));
    drawnow;  % 立即更新图形
    pause(0.1);  % 暂停0.1秒
end

在这里插入图片描述

进阶示例

% 多条动态曲线
figure;
x = 0:0.1:4*pi;
colors = ['r', 'g', 'b', 'm'];
h = [];

% 初始化多条曲线
for i = 1:4
    y = sin(x + (i-1)*pi/2);
    h(i) = plot(x, y, colors(i), 'LineWidth', 2);
    hold on;
end
xlabel('X'); ylabel('Y'); title('多波动态叠加');
grid on; legend('波1', '波2', '波3', '波4');

% 动态更新所有曲线
for t = 0:0.1:6*pi
    for i = 1:4
        y = sin(x + t + (i-1)*pi/2) .* exp(-0.1*t);  % 衰减波
        set(h(i), 'YData', y);
    end
    title(sprintf('衰减波动画 (t = %.1f)', t));
    drawnow limitrate;  % 限制更新速率提高性能
    pause(0.05);
end

在这里插入图片描述

帧捕获 - getframe 命令

基本语法

F = getframe           % 捕获当前图形
F = getframe(gcf)      % 捕获指定图形
F = getframe(gca)      % 捕获当前坐标轴
F = getframe(h, rect)  % 捕获指定区域

使用场景

  • 将动画的每一帧保存为图像
  • 创建动画文件的原始数据
  • 后期视频编辑和处理

示例

简单示例

% 捕获简单动画帧
figure;
[X, Y] = meshgrid(-2:0.2:2, -2:0.2:2);
frames = [];  % 存储帧数据

for t = 1:20
    Z = sin(sqrt(X.^2 + Y.^2) - t*0.3);
    surf(X, Y, Z);
    shading interp;
    axis([-2 2 -2 2 -1 1]);
    title(sprintf('波动动画 帧 %d', t));
    
    frames(t) = getframe(gcf);  % 捕获当前帧
    pause(0.1);
end

% 显示捕获的帧信息
fprintf('捕获了 %d 帧动画\n', length(frames));
fprintf('帧大小: %d x %d\n', size(frames(1).cdata, 1), size(frames(1).cdata, 2));

进阶示例

% 高质量帧捕获设置
figure;
[X, Y, Z] = sphere(50);
frames = [];

% 设置高质量渲染
set(gcf, 'Renderer', 'opengl');
set(gca, 'NextPlot', 'replacechildren');

for angle = 0:10:360
    % 绘制旋转的球体
    surf(X, Y, Z);
    shading interp;
    material('shiny');
    light('Position', [2, 2, 3]);
    colormap('jet');
    
    % 设置视角
    view(angle, 30);
    axis equal; axis off;
    title(sprintf('旋转球体 (角度: %d°)', angle));
    
    % 捕获高质量帧
    drawnow;
    frames(end+1) = getframe(gcf);
    pause(0.05);
end

fprintf('捕获了 %d 帧高质量动画\n', length(frames));

运行结果:
在这里插入图片描述

视频制作 - VideoWriter 命令

基本语法

v = VideoWriter(filename)              % 创建视频对象
v = VideoWriter(filename, profile)     % 指定编码格式
open(v)                               % 打开视频文件
writeVideo(v, frame)                  % 写入帧
close(v)                              % 关闭视频文件

常用视频格式

  • ‘MPEG-4’: 高质量,文件较大
  • ‘Motion JPEG AVI’: 兼容性好
  • ‘Uncompressed AVI’: 最高质量,文件很大

示例

简单示例

% 制作简单的视频文件
v = VideoWriter('simple_animation.mp4', 'MPEG-4');
v.FrameRate = 10;  % 设置帧率
open(v);

figure;
[X, Y] = meshgrid(-2:0.1:2, -2:0.1:2);

% 生成并写入视频帧
for t = 1:50
    Z = sin(sqrt(X.^2 + Y.^2) - t*0.2);
    surf(X, Y, Z);
    shading interp;
    colormap('jet');
    axis([-2 2 -2 2 -1 1]);
    title(sprintf('波动动画 帧 %d/50', t));
    
    frame = getframe(gcf);
    writeVideo(v, frame);  % 写入当前帧
    pause(0.05);
end

close(v);
fprintf('视频已保存为: simple_animation.mp4\n');

运行结果:
在这里插入图片描述
视频如下:

simple_animation

进阶示例

figure;
% 制作高质量旋转动画视频
v = VideoWriter('rotating_surface.mp4', 'MPEG-4');
v.FrameRate = 30;        % 高帧率
v.Quality = 95;          % 高质量
open(v);

figure;
set(gcf, 'Color', 'white');  % 白色背景

% 创建复杂曲面
[X, Y] = meshgrid(-3:0.1:3, -3:0.1:3);
Z = peaks(X, Y);

for angle = 0:2:720  % 两圈旋转
    surf(X, Y, Z);
    shading interp;
    material('shiny');
    light('Position', [3, 3, 5]);
    colormap('jet');
    colorbar;
    
    % 平滑旋转视角
    view(angle, 20 + 10*sin(deg2rad(angle*2)));  % 上下轻微摆动
    axis tight;
    xlabel('X'); ylabel('Y'); zlabel('Z');
    title(sprintf('Peaks函数旋转视图 (%.0f°)', mod(angle, 360)));
    
    drawnow;
    frame = getframe(gcf);
    writeVideo(v, frame);
end

close(v);
fprintf('高质量旋转视频已保存: rotating_surface.mp4\n');

运行结果:
在这里插入图片描述
自动生成如下mp4文件:
在这里插入图片描述

视频内容如下:

rotating_surface

旋转曲面动画案例

基本旋转动画

% 基本旋转曲面动画
figure;
[u, v] = meshgrid(0:0.1:2*pi, 0:0.1:pi);

% 创建环面(甜甜圈)
R = 3; r = 1;
X = (R + r*cos(v)) .* cos(u);
Y = (R + r*cos(v)) .* sin(u);
Z = r * sin(v);

% 旋转动画
for azimuth = 0:5:360
    surf(X, Y, Z);
    shading interp;
    colormap('copper');
    light('Position', [5, 5, 5]);
    material('metal');
    
    view(azimuth, 30);  % 水平旋转
    axis equal; axis off;
    title(sprintf('环面旋转 (方位角: %d°)', azimuth));
    
    drawnow;
    pause(0.05);
end

运行结果:

在这里插入图片描述

多轴旋转动画

% 复杂的多轴旋转动画
figure;

% 创建三个子图进行不同类型的旋转
surfaces = cell(1,3);
titles = {'水平旋转', '垂直旋转', '复合旋转'};

% 准备三种不同的曲面
[X1, Y1] = meshgrid(-2:0.1:2, -2:0.1:2);
Z1 = peaks(X1, Y1);

[X2, Y2, Z2] = sphere(30);

[u, v] = meshgrid(0:0.2:2*pi, -1:0.1:1);
X3 = u .* cos(u);
Y3 = u .* sin(u);
Z3 = v;

surfaces{1} = {X1, Y1, Z1};
surfaces{2} = {X2, Y2, Z2};  
surfaces{3} = {X3, Y3, Z3};

% 动画循环
for frame = 1:72  % 360度,每5度一帧
    for i = 1:3
        subplot(1, 3, i);
        
        X = surfaces{i}{1};
        Y = surfaces{i}{2};
        Z = surfaces{i}{3};
        
        surf(X, Y, Z);
        shading interp;
        light('Position', [2, 2, 3]);
        colormap(gca, 'jet');
        
        % 不同的旋转方式
        angle = frame * 5;
        switch i
            case 1  % 水平旋转
                view(angle, 30);
            case 2  % 垂直旋转  
                view(45, angle/2);
            case 3  % 复合旋转
                view(angle, 30 + 20*sin(deg2rad(angle*2)));
        end
        
        axis tight;
        title(sprintf('%s (%d°)', titles{i}, angle));
    end
    
    drawnow;
    pause(0.1);
end

运行结果:
在这里插入图片描述

完整动画项目案例

制作完整的科学可视化动画

% 完整的波动方程可视化动画项目
    % 设置视频参数
    v = VideoWriter('wave_equation.mp4', 'MPEG-4');
    v.FrameRate = 24;
    v.Quality = 90;
    open(v);
    
    % 设置图形窗口
    figure('Position', [100, 100, 1200, 800]);
    set(gcf, 'Color', 'black');
    
    % 创建网格
    [X, Y] = meshgrid(-4:0.2:4, -4:0.2:4);
    total_frames = 120;
    
    fprintf('开始生成 %d 帧动画...\n', total_frames);
    
    for frame = 1:total_frames
        clf;  % 清除图形
        
        % 计算波动方程
        t = frame * 0.1;
        Z1 = exp(-0.3*(X.^2 + Y.^2)) .* sin(sqrt(X.^2 + Y.^2) - 2*t);
        Z2 = 0.5 * exp(-0.2*((X-2).^2 + (Y-2).^2)) .* cos(sqrt((X-2).^2 + (Y-2).^2) - 3*t);
        Z = Z1 + Z2;
        
        % 绘制主曲面
        surf(X, Y, Z, 'EdgeColor', 'none');
        shading interp;
        colormap('jet');
        alpha(0.8);
        
        % 添加光照
        light('Position', [5, 5, 3], 'Color', [1, 1, 1]);
        light('Position', [-3, -3, 2], 'Color', [0.5, 0.5, 1]);
        material('shiny');
        
        % 设置视角(缓慢旋转)
        view_angle = 45 + 30 * sin(2*pi*frame/total_frames);
        view(view_angle, 25);
        
        % 美化图形
        axis([-4 4 -4 4 -1 1]);
        xlabel('X', 'Color', 'white', 'FontSize', 12);
        ylabel('Y', 'Color', 'white', 'FontSize', 12);
        zlabel('Z', 'Color', 'white', 'FontSize', 12);
        title(sprintf('波动方程可视化 (t = %.1f)', t), ...
              'Color', 'white', 'FontSize', 16);
        
        % 设置坐标轴颜色
        set(gca, 'XColor', 'white', 'YColor', 'white', 'ZColor', 'white');
        grid on;
        
        % 添加颜色条
        cb = colorbar;
        set(cb, 'Color', 'white');
        
        drawnow;
        
        % 捕获帧并写入视频
        frame_data = getframe(gcf);
        writeVideo(v, frame_data);
        
        % 显示进度
        if mod(frame, 10) == 0
            fprintf('已完成: %d/%d 帧\n', frame, total_frames);
        end
    end
    
    close(v);
    fprintf('动画制作完成!文件保存为: wave_equation.mp4\n');

运行结果:
在这里插入图片描述
视频如下:

wave_equation

交互式动画控制

% 可控制的实时动画
    figure('Position', [100, 100, 800, 600]);
    
    % 创建控制按钮
    uicontrol('Style', 'pushbutton', 'String', '开始/暂停', ...
              'Position', [20, 20, 80, 30], 'Callback', @toggle_animation);
    uicontrol('Style', 'pushbutton', 'String', '重置', ...
              'Position', [120, 20, 80, 30], 'Callback', @reset_animation);
    
    % 速度滑块
    uicontrol('Style', 'text', 'String', '速度:', ...
              'Position', [220, 25, 40, 20]);
    speed_slider = uicontrol('Style', 'slider', 'Min', 0.01, 'Max', 0.2, ...
                            'Value', 0.05, 'Position', [270, 20, 100, 30]);
    
    % 全局变量
    global is_running current_time;
    is_running = false;
    current_time = 0;
    
    % 初始化图形
    [X, Y] = meshgrid(-3:0.2:3, -3:0.2:3);
    h_surf = surf(X, Y, zeros(size(X)));
    shading interp;
    colormap('jet');
    light('Position', [3, 3, 5]);
    axis([-3 3 -3 3 -2 2]);
    title('交互式波动动画');
    
    % 动画主循环
    while ishandle(h_surf)
        if is_running
            current_time = current_time + get(speed_slider, 'Value');
            Z = sin(sqrt(X.^2 + Y.^2) - current_time);
            set(h_surf, 'ZData', Z);
            title(sprintf('交互式波动动画 (t = %.2f)', current_time));
        end
        drawnow;
        pause(0.02);
    end
    
    % 回调函数
    function toggle_animation(~, ~)
        is_running = ~is_running;
    end
    
    function reset_animation(~, ~)
        current_time = 0;
    end
end

运行结果:

性能优化技巧

提高动画性能

% 性能优化的动画制作
figure;
[X, Y] = meshgrid(-2:0.1:2, -2:0.1:2);

% 预分配和优化设置
set(gca, 'NextPlot', 'replacechildren');  % 避免重复创建对象
h_surf = surf(X, Y, zeros(size(X)));
shading interp;
light('Position', [2, 2, 3]);

% 使用句柄更新而非重新创建
tic;
for t = 1:100
    Z = sin(sqrt(X.^2 + Y.^2) - t*0.1);
    set(h_surf, 'ZData', Z);  % 只更新数据,不重新创建对象
    title(sprintf('优化动画 帧 %d', t));
    drawnow limitrate;  % 限制更新率
    pause(0.01);
end
elapsed_time = toc;
fprintf('优化后动画用时: %.2f 秒\n', elapsed_time);

在这里插入图片描述

总结与最佳实践

命令使用建议

  1. drawnow vs drawnow limitrate

    • 普通动画使用 drawnow
    • 高频更新使用 drawnow limitrate
  2. pause时间设置

    • 流畅动画: 0.02-0.05秒
    • 慢速演示: 0.1-0.5秒
    • 快速预览: 0.01秒
  3. 视频制作参数

    • 演示用: FrameRate = 15-24
    • 科学分析: FrameRate = 30-60
    • Quality = 80-95

性能优化原则

  • 使用句柄更新数据而非重新绘制
  • 预设固定的坐标轴范围
  • 合理使用 drawnow limitrate
  • 避免在循环中创建新对象

上述例程汇总为mlx文件,如下:

通过网盘分享的文件:2.6 动态图形与动画
链接: https://pan.baidu.com/s/1qK1hiF2HnXd-Lk65FgntwQ?pwd=5emw 提取码: 5emw

如需帮助,或有导航、定位滤波相关的代码定制需求,请点击下方卡片联系作者

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MATLAB卡尔曼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值