首页 文章

在Matlab中生成动画(AVI文件)而不显示图形

提问于
浏览
3

我一直在尝试使用Matlab通过shell脚本在集群上远程并行生成动画文件(.AVI文件) . 到目前为止,这是一项不可能的任务 . 我已经放弃了,并且刚刚接受了我需要在我的笔记本电脑上生成动画过夜8小时左右 . 但我希望那里有人知道如何解决这个问题,或者我可以阻止某人浪费一天的反复试验 .

我已经用数字生成了大量的二维概率分布(通过Matlab),我想将这些曲面绘制为时间的函数 . 我知道我可能会尝试将一堆.jpegs输出到文件并使用另一个程序,如MEncoder或其他程序,但该死,这是Matlab应该能做的事情 .

我可以访问一个包含大量节点的好集群,并希望通过shell脚本并行生成动画:

/ usr / local / MATLAB / R2013b / bin / matlab -nojvm -nodisplay -r“TestFile1”

我知道switch -nojvm会杀掉Java,所以我省略了这个:

/ usr / local / MATLAB / R2013b / bin / matlab -nodisplay -r“TestFile1”

我将在下面介绍我的代码,首先在我的笔记本电脑上运行代码(新的MacBook Pro),然后在尝试在集群上运行相同的代码时失败 . 希望有更多Matlab经验的人会注意到我的错误并让我走上正确的道路 .

First 我用 movie2avi 做了这个成功,一个简单的例子如下所示:

%%————————————————————————%%
clear Mov
clear rect
rect = get(gcf,'Position');
rect(1:2) = [0 0];
figure(1)
for ii=1:100
clf;
meshc(((ii+75)/100).*peaks)
grid on
axis([0 50 0 50 -20 20 -10 10])
colorbar
shading interp 
Mov(:,ii) = getframe(gcf,rect);
end 
movie2avi(Mov, 'test0.avi', 'compression','None','fps',30); % fps = frames per second
%%————————————————————————%%

此方法的问题在于它使用 getframe ,这需要在屏幕上生成绘图 .

Second 经过大量的反复试验后,我能够在笔记本电脑上生成这个.AVI文件而不使用 figure('visible','off')addframe 显示图形 .

%%————————————————————————%%
aviobj=avifile('test1.avi','compression','None');  
hf= figure('visible','off');                              
for ii=1:100
clf;
meshc(((ii+75)/100).*peaks)
grid on
axis([0 50 0 50 -20 20 -10 10])
colorbar
shading interp 
aviobj=addframe(aviobj,hf);
end  
aviobj=close(aviobj); 
close(hf);
exit      
%%————————————————————————%%

正如我上面提到的,这在我的笔记本电脑上非常好用,但是遇到了Matlab消息:

警告:将来的版本中将删除AVIFILE . 请改用VIDEOWRITER .

当我尝试在群集上运行此错误消息时:

使用avifile / addframe时出错> ValidateFrame(第287行)帧必须是660乘520 .

所以我回到我的笔记本电脑并为每个循环迭代打印 aviobj 并看到帧大小始终是 Width: 560, Height: 419 . 在这一点上我想也许Matlab只是不喜欢 AVIFILE 所以相反我应该尝试使用 VIDEOWRITER .

Third 我在网上(通过Matlab网站和stackoverflow)发现了一些用 VIDEOWRITER 生成动画的例子,但是对于我的生活,我不知道如何在不使用getframe的情况下使用这个函数,所以总会显示一个数字 . 在我的笔记本电脑上工作的一个示例,显示生成.AVI文件之前的图形如下所示:

%%————————————————————————%%
writerObj = VideoWriter('test2.avi');
open(writerObj);
Z = peaks; surf(Z); 
axis tight
set(gca,'nextplot','replacechildren');
set(gcf,'Renderer','zbuffer');
for k = 1:100 
   surf(sin(2*pi*k/20)*Z,Z)
   frame = getframe;
   writeVideo(writerObj,frame);
end
close(writerObj);
%%————————————————————————%%

当然,当我在集群上运行它时,我得到了预期的错误:

getframe需要一个有效的数字窗口

我已经看到很多关于试图使用 VIDEOWRITER 而不是 getframe 的人的stackoverflow的例子,但这些都没有工作,我开始认为 VIDEOWRITERim2frame 不兼容 .

有谁在那里解决了类似的问题,如果是这样,你能给我一个简单的例子来尝试远程运行吗?

EDIT:

谢谢 nkjt ,根据您的建议,我能够从一系列保存到磁盘的数字中创建.AVI文件 . 我已将我的代码放在下面,供可能感兴趣的人使用 . 这适用于我的笔记本电脑和我可以访问的集群 . 虽然群集在图形大小方面存在一些问题,但我无法解决这个问题 . 另外,当我使用这段代码将数字写入磁盘的实际情况时,我感兴趣的是,我得到了错误:

分段故障(核心转储),

使用-nodisplay开关生成数字时似乎很常见的东西 . 所以我放弃了,而是在我的笔记本电脑上一夜之间生成了我的动画 . 可能是时候开始使用python而不是Matlab ...

要将图表写入文件:

%%————————————————————————%%
[X,Y] = meshgrid(-3:0.1:3);
Z = peaks(X,Y);
set(gcf,'Visible','off');
for ii=1:100
filename1 = [ 'WTest', num2str(ii),'a.jpg' ];
clf;
meshc(X,Y,((ii+75)/100).*Z)
grid on
axis([-3 3 -3 3 -20 20 -10 10])
colorbar
saveas(gcf,filename1,'jpg');
end
%%————————————————————————%%

要获取保存的打印文件并生成.AVI文件:

%%————————————————————————%%
% Take plots to file and make .AVI file
vidObj = VideoWriter('Wtest.avi');
vidObj.Quality = 100;   % 0 -- 100
vidObj.FrameRate = 10;  % fps
open(vidObj);
set(gcf,'Visible','off');
for ii = 1:100
    clf;
filename1 = [ 'WTest', num2str(ii),'a.jpg' ];
    img = imread(filename1);
    writeVideo(vidObj,img);
end
close(vidObj);
%%————————————————————————%%

2 回答

  • 0

    如果您能够以无头模式*将各个帧写入图像, VideoWriter 将直接拍摄图像数据,则无需使用 im2frame . 但是,您必须循环写出的图像,读入它们,将它们添加到电影中,依此类推,因此略显笨重 .

    假设 fnames 按顺序包含所有帧( frame001.jpg 依此类推), output 是您的视频已使用 VideoWriter 创建:

    for n = 1:length(fnames)
        img = imread(fnames(n,:));
        writeVideo(output,img);
    end
    close(output);
    

    *旁注:并不总是像第一次出现一样容易 . 这可能是您在群集上运行 avifile/addframe 的问题的根源 . 如果我是你,我首先要确保我能够在笔记本电脑上用显示器,没有显示器的笔记本电脑和集群上复制一张图像 . 默认图形属性可能会在机器之间发生变化,渲染器的选择(包括硬件与软件OpenGL)可能会引入一些奇怪的效果 .

  • 1

    这个数字必须存在,但我使用set(f,'Visible','off')来隐藏绘图,这样可以加快速度 . 我还没有在群集上测试过它,因为它在我的本地机器上运行得非常快,但它似乎与o.p.非常相似 . 开始研究集群了 . 如果您在渲染方面遇到太多问题,我建议您尝试将数据点的数量减少到合理的视频分辨率 .
    作为奖励,这个版本并没有对我造成任何影响,它应该以比保存一堆单独图片所需的更少的内存和时间运行 .

    f=figure;
    set(f,'Visible', 'off');%'animating in background
    a=gca;
    set(a,'DataAspectRatio',[1 1 1])
    daspect('manual')
    axis manual
    hold on
    ylabel('y');
    title('title');
    writerObj = VideoWriter(fullfile(PATH,FILENAME),'Motion JPEG AVI');
    writerObj.Quality = 100;
    writerObj.FrameRate = RATE;%frames per sec
    open(writerObj);    
    for j = 1:NUMBER_OF_FRAMES
        cla(a);
        axis([x1 x2 y1 y2])%useful to specify sometimes    
        %%PLOT YOUR STUFF NOW
        DYNAMIC_LABEL = sprintf('%s\n%s',LABEL,FOOTNOTE)
        xlabel(DYNAMIC_LABEL)%I like to use this as a changing footnote
        drawnow;
        frame = getframe(f);
        writeVideo(writerObj,frame);   
    end
    close(f)
    daspect('auto')
    close(writerObj);
    

相关问题