Creating animations in Matlab (AVI files) without displaying the picture

I am trying to generate animation files (.AVI files) in parallel remotely on a cluster via a shell script using Matlab. Until now, this has been an impossible task. I almost forgot and just assumed that I would need to generate animation on my laptop overnight for 8 hours or so. But I hope that someone out there knows how to fix this, or that I can prevent someone from spending a day of trial and error.

I have generated a large number of bivariate probability distributions numerically (via Matlab) and I want to plot these surfaces as a function of time. I know I could probably try to release a bunch of .jpegs to write and use another program like MEncoder or something, but heck this is what Matlab has to do.

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

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

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

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

I'll walk through my code below, first running the code on my laptop (new MacBook Pro) and then failing when trying to run the same code on the cluster. Hopefully someone with more experience with Matlab will spot my mistake and put me on the right track.

First . I had success 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 graphs to be displayed 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 shape, using number ("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 very well on my laptop, but meets Matlab's post:

Attention: AVIFILE will be removed in the next version. Use VIDEOWRITER instead.

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

Error using avifile / addframe> ValidateFrame (line 287). The frame should be 660 by 520.

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

Third I found some examples on the internet (via Matlab website and stackoverflow) that generated animations with VIDEOWRITER , but for life I can't figure out how to use this function without using the getframe function, so the number is always displayed. One example that works on my laptop showing a shape before creating the .AVI file 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 shapes window

I have seen many examples on stackoverflow of people trying to use VIDEOWRITER with im2frame instead of getframe , but none of these work and I find that VIDEOWRITER is incompatible with im2frame .

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

EDIT:

Thanks nkjt , with your advice, I was able to create an .AVI file from a series of numbers saved to disk. I have posted my code below for those who might be interested. This worked on both my laptop and the cluster that I have access to. Although the cluster had some problems with the shape size, something I could not solve. Also, when I used this code to write digits to disk for the actual case I was interested in, I got the error:

Segmentation fault (kernel reset)

what seems to be quite common when it generates numbers using the -nodisplay switch. So I gave up and created the animation on my laptop instead. Maybe it's time to start using python instead of Matlab ...

To write graphs to a 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 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);
%%β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”%%

      

+3


source to share


2 answers


If you can write separate frames for images in headless mode *, VideoWriter

will receive image data directly, there is no need to use im2frame

. However, you will have to go through the recorded images, read them, add them to the movie, etc., so a little awkward.

Assuming it 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 sounds. This could be the source of your problem when running avifile/addframe

on a cluster. If I were you, I would first make sure that I can satisfactorily reproduce one image captured on a laptop with a display, a laptop without a display, and in a cluster. The default shape properties can change between machines, and rendering choices (including OpenGL hardware and software) can lead to some strange effects.

0


source


The digit should exist, but I am using set (f, 'Visible', 'off') to hide the graph, which makes things faster. I haven't tested this on a cluster yet, because it runs pretty fast on my local machine, but it seems very similar to op working on a cluster. If you have too many rendering issues, I would suggest trying to reduce the number of data points to something reasonable for your video resolution.
As a bonus, this version didn't work for me, and it should work with less memory and time than it takes to keep a bunch of individual images.



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


source







All Articles