How can I write this animated figure as a movie?

10 views (last 30 days)
This is a scaled-down model of a larger bit of code I have been trying to write to generate an animated plot of audio measurements taken in a matrix of 10 x 10 microphone positions - 10 simulatneous channels per each of the 10 positions (well, 11 channels were recorded at each position, but I only need 10 of them, hence the indexing in the example datacall format from the real code). Was unable to get it to work properly at "full-scale" (no errors, but an almost "jammed" figure, so probably wildly inefficient processing), so made a small model of it to demostrate what I'm trying to achieve. Further to saving the animated plot as a movie, if anyone has any other suggestions on how to improve the code, I'd be very grateful to hear them.
I've tried the things suggested in the documentation for writeAnimation and fanimator, but I don't think I'm giving those functions the correct type of figure/data to write.
Many thanks in advance!
% "SCALE MODEL" of 10x10 PLOTTING CODE
% Build random matrices for example purposes - i.e., 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
end

Answers (1)

KSSV
KSSV on 12 Oct 2020
  10 Comments
Peter Beringer
Peter Beringer on 14 Oct 2020
Tried your latest suggestion, but I'm sorry, I dont understand how these lines of code can be adapted to my needs. At what point should it call frames from the animated figure already generated in the 'for' loop? The surface plot is variable 'h', but isn't refferred to again, but from what I've read and looked at about it, getframe(gca) is acquiring frames from the plot 'h'. It seems this is to rotate and animate a static plot through 180 degrees, not capture an animated plot as a movie or GIF. When inserted and adpted to my script, it gets the first frame of the animated surf plot and rotates it by 180 degrees, but that's all. It would need to capture every redrawing of the plot as an image, so I thought the loop for 'getframe' would be 1 : NumSamples ... one frame per sample, etc.
Another way of putting it is that the figure is already animated, doesn't require animation, just capturing as image frames, to then be aseembled into an AVI or GIF, etc. using writeAnimation or similar.
I get this message after it runs ... which I think means it is coming up against the 'drawnow' function call refershing the figure, hence "invalid or deleted object".
Warning: The following error was caught while executing 'onCleanup' class destructor:
Error using matlab.ui.Figure/set
Invalid or deleted object.
Error in matlab.graphics.internal.getframeWithDecorations>doCleanup (line 57)
set(opts.fig, 'Visible', opts.Visible);
Error in matlab.graphics.internal.getframeWithDecorations>@()doCleanup(opts) (line 39)
cleanupHandler = onCleanup(@() doCleanup(opts));
Error in onCleanup/delete (line 81)
obj.task();
Error in matlab.graphics.internal.getframeWithDecorations (line 53)
end
Error in alternateGetframe
Error in getframe (line 138)
x = alternateGetframe(parentFig, offsetRect, scaledOffsetRect, includeDecorations);
Error in AniSurfSimple03 (line 36)
M(end+1) = getframe(gca);
> In matlab.graphics.internal.getframeWithDecorations (line 53)
In alternateGetframe
In getframe (line 138)
In AniSurfSimple03 (line 36)
Error using getpixelposition (line 30)
First argument must be a valid graphics object handle.
Error in alternateGetframe
Error in getframe (line 138)
x = alternateGetframe(parentFig, offsetRect, scaledOffsetRect, includeDecorations);
Error in AniSurfSimple03 (line 36)
M(end+1) = getframe(gca);
(Is there a "convention" on how to include and format error messages in a comment or answer?)
I'm terribly sorry that I haven't been able to make this work. This is the first time I've ever required an animated plot ... and hopefully the last. Thanks in advance for any help you may be able to provide. Cheers!
This is the 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
M = getframe(gca);
[~, EL] = view;
for k = 0:180
% Rotate the axes
view(k, EL);
% Capture the next frame
M(end+1) = getframe(gca);
end
end
Peter Beringer
Peter Beringer on 14 Oct 2020
Thanks a lot! It got me there in the end. I intend to save as AVI movie, but that looks simple enough to implement from where I am now. The main issue I was having was calling the "axes handle" of the figure being created by the 'for' loop. But now that I've got the image capture working fine, and AVI will be simple.
Looking at the code, I get the impression I have a few unnecesary (or misinterpreted) lines, possibly making it inefficient. Do you have any quick thoughts on that?
Thanks.
Here is the 'for' loop code updated to capture image frames ...
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);
% Write GIF file
if i == 1
imwrite(imind, cm, 'AnimatedFigure.gif', 'gif', 'Loopcount', inf);
else
imwrite(imind, cm, 'AnimatedFigure.gif', 'gif', 'WriteMode', 'append');
end
end

Sign in to comment.

Categories

Find more on Audio Plugin Creation and Hosting in Help Center and File Exchange

Products


Release

R2019b

Community Treasure Hunt

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

Start Hunting!