Code to create animated plot and capture/write as AVI movie returns no errors but only a single frame AVI file.

This code is a "scale model" of a larger plotting code for a 10x10 matrix of audio measurements. I wish to write the animated plot as an *.AVI file (or *.MOV or *.MP4, etc.) for digital submission. I thought I'd cracked it with this code, as no errors were prodcued, but the video file written contains only a single frame (I assume the first). The same result occurs with the video writing lines inside and outside the 'for' loop - I tried it "writing whilst generating" and "writing once generated" (if that makes sense). Should this process be put in a nested 'for' loop? The commented-out code for writing a GIF animation works fine, but including a GIF to AVI process seems like "double-handling" and rather inefficient.
With no error message displayed by MATLAB, I'm not sure where to go. There doesn't appear to be anything already on MATLAB Answers that matches this kind of result. I found a question thread that I thought addressed the same issue, but it turned out to be playing too quickly, rather than only writing one frame. To test if this was the case I tried adding:
VideoObj.FrameRate = 1;
But it was clear that only a single frame had been written to the AVI file.
Thanks.
Here is the main code:
% "SCALE MODEL" of 10x10 PLOTTING CODE
% Build random matrices for example purposes - 5 "channels" of audio, each
% 20 "samples" long. Each five channel signal "played" from five
% positions, resulting in a 5 x 5 matrix of microphones/measurements/audio
% vectors.
fs = 5; % Otherwise 48000 for audio measurements.
a = -1; % Generate values between -1 and 1 to simulate audio signals.
b = 1;
Position1 = a + (b - a) .* rand(20,5); % Would call audio data here.
Position2 = a + (b - a) .* rand(20,5); % Format: Pos01audio = Pos01audiodata.audio(:,1:10);
Position3 = a + (b - a) .* rand(20,5); % Should audio vectors be tranposed into rows?
Position4 = a + (b - a) .* rand(20,5);
Position5 = a + (b - a) .* rand(20,5);
[NumSamples] = size(Position1(:,1)); % Get length of audio vectors from any; all measurements are the same length; 4secs or 4*fs.
NumSamples = NumSamples(1,1);
for i = 1 : NumSamples % Length of audio file in samples.
PlotMatrix = [Position1(i,:); Position2(i,:); Position3(i,:); Position4(i,:); Position5(i,:)]; % Concatenate arrays into matrix to be rewritten in 'for' loop.
OutputPlot = surf(PlotMatrix);
grid on
pause(1/fs) % Make pause equivalent to sample rate.
drawnow
PlotHandle = gcf;
ImageFrames = getframe(PlotHandle);
im = frame2im(ImageFrames);
[imind, cm] = rgb2ind(im,256);
end
% Write AVI video file
VideoObj = VideoWriter('AnimatedPlot.avi');
open(VideoObj);
writeVideo(VideoObj, ImageFrames);
% % Write GIF file
% if i == 1
% imwrite(imind, cm, 'AnimatedFigure.gif', 'gif', 'Loopcount', inf);
% else
% imwrite(imind, cm, 'AnimatedFigure.gif', 'gif', 'WriteMode', 'append');
% end

 Accepted Answer

You are just saving a single frame inside for-loop. Change the lines to
ImageFrames(i) = getframe(PlotHandle); % save an array of frames
im = frame2im(ImageFrames(i));
at the end, close the VideoWriter object
close(VideoObj)

5 Comments

Alternately create and open the VideoWriter object before the loop, writeVideo each frame to the VideoWriter object inside the loop, and close it after. The "Create AVI File from Animation" example on the documentation page for the VideoWriter function shows this technique (with a figure window containing a surf object as the frame being written, so it's quite close to what you want.)
One benefit of this alternative is if you're trying to create a long animation you don't need to keep all the animation frames in memory.
Thanks for the fantastic responses. It seems that what I thought was being outputted to the ImageFrames variable was what I needed (that it was already repeating inside the loop as required), so managed to overlook indexing that variable.
Both suggestions work perfectly, but the suggestion of creating and opening the VideoObj before the loop (and also adjusting frame rate - 20 frames at 30fps is a short video, hehe), and closing it after, seems to be more efficient, so will definitely use that approach with this and especially the "full scale" plotting script that will deal with audio vectors 192000 samples long.
Many thanks, both of you! Cheers!
I forgot to add that without also adding the indexing on the ...
writeVideo(VideoObj, ImageFrames(i));
... line, the resultant AVI file is a loop of the animation, repeated an unknown number of times. Not quite sure how or why that's occurring, but also adding the indexing on writeVideo function call fixed it.
Just in case anyone else with the same issue reads this down the track and misses that too.
You mean you get video loops when you add the line
writeVideo(VideoObj, ImageFrames)
inside the for-loop. Right? Outside the for-loop this will work fine.
Yes, that's correct; just tried that then. I can see why it would loop now.
Thanks for clearing that up.

Sign in to comment.

More Answers (0)

Products

Release

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!