我一直在尝试使用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);
%%————————————————————————%%
答案 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)会引入一些奇怪的效果。