在Matlab中生成动画(AVI文件)而不显示图形 [英] Generating Animations in Matlab (AVI files) without displaying figure

查看:196
本文介绍了在Matlab中生成动画(AVI文件)而不显示图形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

我可以访问具有许多节点的漂亮群集,并希望通过shell脚本并行生成动画:

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

我知道-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文件,而无需使用 figure('visible','off')

显示该数字 strong>和 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 x 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需要一个有效的图形窗口

我已经看到很多关于尝试使用 VIDEOWRITER im2frame 而不是 getframe 的人的堆栈溢出的例子,但是这些都不起作用并且我开始认为 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);
%%————————————————————————%%

解决方案

如果您能够以无头模式将单个帧写入图像*,则VideoWriter将直接获取图像数据,无需使用im2frame .但是,您将不得不遍历已写出的图像,将它们读入,将它们添加到电影中,依此类推,以至于显得有些笨拙.

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

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


* sidenote:并不总是像它第一次出现时那样容易.这可能是在群集上运行avifile/addframe时出现问题的根源.如果我是您,那么我首先要确保可以令人满意地复制写在带显示器的笔记本电脑上,没有显示器的笔记本电脑上以及群集上写出的单个图像.机器之间的默认图形属性可能会发生变化,渲染器的选择(包括硬件与软件OpenGL)可能会引入一些怪异的效果.

I have been trying to generate animation files (.AVI files) in parallel remotely on a cluster via shell script with Matlab. So far this has been an impossible task. I have all but given up, and have just accepted that I will need to generate the animations on my laptop overnight for 8 hours or so. But I’m hoping that someone out there knows how to fix this, or that I can stop someone from wasting a day of trial and error.

I have generated a large number of two dimensional probability distributions numerically (via Matlab) and I want to plot these surfaces as a function of time. I know that I could probably try to output a bunch of .jpegs to file and use another program such as MEncoder or something, but dammit, this is something Matlab should be able to do.

I have access to a nice cluster with lots of nodes and want to generate animations in parallel via shell script:

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

I know that the switch -nojvm will kill Java, so I omit this:

/usr/local/MATLAB/R2013b/bin/matlab -nodisplay -r "TestFile1"

I will go through the progression of my code below, first running code on my laptop (new MacBook Pro) successfully and then failing when trying to run the same code on the cluster. Hopefully someone with more experience with Matlab will notice my error and set me on the correct path.

First I have had success doing this with movie2avi, a simple example for which is shown below:

%%————————————————————————%%
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
%%————————————————————————%%

The problem with this method is that it uses getframe which requires the plots to be generated on the screen.

Second After a lot of trial and error I was able to generate this .AVI file on my laptop without displaying the figure using figure('visible','off') and 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      
%%————————————————————————%%

As I mentioned above, this works quite nicely on my laptop, but is met with the Matlab message:

Warning: AVIFILE will be removed in a future release. Use VIDEOWRITER instead.

When I try to run this on the cluster the error message is:

Error using avifile/addframe>ValidateFrame (line 287) Frame must be 660 by 520.

So I go back to my laptop and print aviobj for each loop iteration and see that the frame size is always Width: 560, Height: 419. At this point I figure maybe Matlab just doesn’t like AVIFILE so instead I should try to use VIDEOWRITER.

Third I found some examples on the web (via the Matlab website and stackoverflow) that generated animations with VIDEOWRITER, but for the life of me I cannot work out how to use this function without also using getframe, so a figure is always displayed. One example that works on my laptop, showing the figure before the .AVI file is generated is shown below:

%%————————————————————————%%
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);
%%————————————————————————%%

Of course when I run this on the cluster I get the expected error:

getframe requires a valid figure window

I’ve seen plenty of examples on stackoverflow of people attempting to use VIDEOWRITER with im2frame instead of getframe, but none of these work and I beginning to think that VIDEOWRITER is incompatible with im2frame.

Is there anyone out there that has solved a similar issue, and if so can you give me a simple example to try to run remotely?

EDIT:

Thanks nkjt, with your advice I was able to create an .AVI file from a series of figures that were saved to disk. I have put my code below for anyone that might be interested. This worked on both my laptop and the cluster I have access to. Though the cluster had some issues with the size of the figure, something I was not able to resolve. Also, when I used this code to write the figures to disk for the actual case I was interesting in, I got the error:

Segmentation fault (core dumped),

something that seems quite common when generating figures with the -nodisplay switch. So I have given up and have instead generated my animations overnight on my laptop. It may be time to start using python instead of Matlab…

To write the plots to file:

%%————————————————————————%%
[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
%%————————————————————————%%

To take the saved plot files and make an .AVI file:

%%————————————————————————%%
% 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);
%%————————————————————————%%

解决方案

If you are able to write your individual frames to images in headless mode*, VideoWriter will take image data directly, there's no need to use im2frame. However, you will have to loop over the written out images, read them in, add them to the movie, and so on, so slightly clunky.

Assuming here that fnames contains all the frames in order (frame001.jpg and so on) and output is your video already created with VideoWriter:

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


*sidenote: not always as easy as it first appears. This may be the source of your issue with running avifile/addframe on the cluster. If I were you, I would first make sure I could satisfactorily replicate a single image written out on the laptop with display, on the laptop without display, and on the cluster. Default figure properties may change between machines and the choice of renderer (including hardware vs. software OpenGL) can introduce some weird effects.

这篇关于在Matlab中生成动画(AVI文件)而不显示图形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆