我一直在尝试使用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的例子,但这些都没有工作,我开始认为 VIDEOWRITER 与 im2frame 不兼容 .
有谁在那里解决了类似的问题,如果是这样,你能给我一个简单的例子来尝试远程运行吗?
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 回答
如果您能够以无头模式*将各个帧写入图像,
VideoWriter
将直接拍摄图像数据,则无需使用im2frame
. 但是,您必须循环写出的图像,读入它们,将它们添加到电影中,依此类推,因此略显笨重 .假设
fnames
按顺序包含所有帧(frame001.jpg
依此类推),output
是您的视频已使用VideoWriter
创建:*旁注:并不总是像第一次出现一样容易 . 这可能是您在群集上运行
avifile/addframe
的问题的根源 . 如果我是你,我首先要确保我能够在笔记本电脑上用显示器,没有显示器的笔记本电脑和集群上复制一张图像 . 默认图形属性可能会在机器之间发生变化,渲染器的选择(包括硬件与软件OpenGL)可能会引入一些奇怪的效果 .这个数字必须存在,但我使用set(f,'Visible','off')来隐藏绘图,这样可以加快速度 . 我还没有在群集上测试过它,因为它在我的本地机器上运行得非常快,但它似乎与o.p.非常相似 . 开始研究集群了 . 如果您在渲染方面遇到太多问题,我建议您尝试将数据点的数量减少到合理的视频分辨率 .
作为奖励,这个版本并没有对我造成任何影响,它应该以比保存一堆单独图片所需的更少的内存和时间运行 .