matlabanimationffmpegmovie

movie2avi - how to fix the frame size?


I have searched stackoverflow for a similar question and I found question "movie2avi-frame-size-error-and-keeping-frame-size-constant". Unfortunately the answer given there did not solve my problem (it has been suggested the use of xlim, ylim and zlim).

In what follows I send a lightly modified version of a well-known example given elsewhere.

%# figure
figure, set(gcf, 'Color','white')
Z = peaks; surf(Z);  axis tight
set(gca, 'nextplot','replacechildren', 'Visible','off');
[az,el]=view;
xl=xlim;
yl=ylim;
zl=zlim;

%# preallocate
nFrames = 20;
mov(1:nFrames) = struct('cdata',[], 'colormap',[]);

%# create movie
for k=1:nFrames
   view([(az-k*10) el]);
   xlim(xl);ylim(yl);zlim(zl);
   drawnow;pause(0.1);
   mov(k) = getframe(gca);
end
close(gcf)

%# save as AVI file, and open it using system video player
movie2avi(mov, 'myPeaks1.avi', 'compression','None', 'fps',10);

The idea is to rotate the figure and create a movie. Everything works fine except for the last command, that is, movie2avi. The error msg is

Error using avifile/addframe>ValidateFrame (line 290)
Frame must be 435 by 344.

Error in avifile/addframe (line 158)
ValidateFrame(aviobj,width, height,dims);

Error in movie2avi (line 67)
avimov = addframe(avimov,mov);

Error in more_video_test (line 24)
movie2avi(mov, 'myPeaks1.avi', 'compression','None', 'fps',10); 

I have looked at approaches-to-create-a-video-in-matlab here in stackoverflow and found that:

a) Solution ffmpeg works but I would like to avoid it.
b) All other solutions failed even QTWriter. How can I fix the frame size so that all these other solutions work?

Many thanks.

Ed


Solution

  • The problem is that due to the rotation of the graph the size of the axis changes, so you end up with a sequence of frames of different sizes. You can see this if you insert the lines

    s = size(mov(k).cdata);
    fprintf('%d %d\n', s(2), s(1))
    

    within the loop, directly after you grabbed the frame by

    mov(k) = getframe(gca);
    

    The result is

    435 344
    435 343
    435 343
    436 342
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    435 343
    

    Because the first frame has the size 435 x 344, movie2avi expects the following frames to be of the same size – but they're not.

    In order to fix this, you might want to set the axis size (& position) explicitly using set(gca, 'Position', [...]). An easier workaround though is to grab the frame not from the axis, but from the figure. That is, instead of mov(k) = getframe(gca); use

    mov(k) = getframe(gcf);
    

    The frames then have a uniform size of 560 x 420.

    On my machine, the resulting avi has frames upside down. In order to fix this, too, you can additionally insert a line

    mov(k).cdata = mov(k).cdata(end :-1: 1, :, :);
    

    after grabbing the frame.