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

时间:2014-09-04 07:36:02

标签: matlab animation video video-capture matlab-figure

我一直在尝试使用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经验的人会注意到我的错误并让我走上正确的道路。

首先我使用 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 ,这需要在屏幕上生成绘图。

第二次经过大量的反复试验后,我能够在笔记本电脑上生成这个.AVI文件而不使用数字显示图形('可见',& #39; 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 ,并看到框架大小始终为宽度:560,高度:419 。在这一点上,我认为Matlab可能不喜欢 AVIFILE ,所以我应该尝试使用 VIDEOWRITER

第三次我在网上(通过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需要一个有效的数字窗口

我已经看到很多关于尝试使用视频网络 im2frame 而不是 getframe 的人的stackoverflow示例,但这些都没有我开始认为 VIDEOWRITER im2frame 不兼容。

有没有人解决过类似的问题,如果有的话,你能给我一个简单的例子来尝试远程运行吗?

编辑:

感谢 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 :(得分: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);

答案 1 :(得分: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)会引入一些奇怪的效果。