I am faced with making movies with ~10,000 frames and ~ 10,000 pixels per frame using e.g. imagesc
. However, even though my computer is equipped with 8 GB of RAM (running 32-bit MATLAB), MATLAB complains with Out Of Memory
at ~ 1,000 frames. Also, I want my movie compressed as well. What is my best option to create larger movies?
To find out what is your best option, I tested several movie writing functions (Windows 7 MATLAB 2012a 32-bit).
The key is to make sure the function flushes frames to disk before the movie is completed. VideoWriter combined with MPEG-4 yields both constant (small) memory size and a compressed video.
%%%
% General Setup
%%%
number_of_frames = 1000;
Z = peaks;
%%%
% Video Writer -- AVI
%%%
%%
f = figure('renderer', 'zbuffer');
a = axes('parent', f);
axis(a, 'tight');
surf(a, Z);
current_zlim = zlim();
set(a, 'nextplot', 'replacechildren', 'zlimmode', 'manual', 'zlim', current_zlim);
vid = VideoWriter('myPeaks - VideoWriter.avi');
vid.Quality = 100;
vid.FrameRate = 15;
open(vid);
current_memory_used_Bytes(1, number_of_frames + 1) = 0;
current_memory_struct = memory();
current_memory_used_Bytes(1) = current_memory_struct.MemUsedMATLAB;
for(k = 1 : number_of_frames)
surf(a, sin(2*pi*k/20)*Z, Z);
writeVideo(vid, getframe(f));
current_memory_struct = memory();
current_memory_used_Bytes(k + 1) = current_memory_struct.MemUsedMATLAB;
end
close(vid);
figure;
plot((current_memory_used_Bytes(2 : end) - current_memory_used_Bytes(1)) / 1e6);
xlabel('Frame Number');
ylabel('Movie Memory in RAM (MB)');
title('VideoWriter -- AVI');
saveas(gcf, 'myPeaks - VideoWriter -- AVI.png');
close all;
clearvars -except number_of_frames Z
%%%
% Video Writer -- MPEG-4
%%%
%%
f = figure('renderer', 'zbuffer');
a = axes('parent', f);
axis(a, 'tight');
surf(a, Z);
current_zlim = zlim();
set(a, 'nextplot', 'replacechildren', 'zlimmode', 'manual', 'zlim', current_zlim);
vid = VideoWriter('myPeaks - VideoWriter.mp4', 'MPEG-4');
vid.Quality = 100;
vid.FrameRate = 15;
open(vid);
current_memory_used_Bytes(1, number_of_frames + 1) = 0;
current_memory_struct = memory();
current_memory_used_Bytes(1) = current_memory_struct.MemUsedMATLAB;
for(k = 1 : number_of_frames)
surf(a, sin(2*pi*k/20)*Z, Z);
writeVideo(vid, getframe(f));
current_memory_struct = memory();
current_memory_used_Bytes(k + 1) = current_memory_struct.MemUsedMATLAB;
end
close(vid);
figure;
plot((current_memory_used_Bytes(2 : end) - current_memory_used_Bytes(1)) / 1e6);
xlabel('Frame Number');
ylabel('Movie Memory in RAM (MB)');
title('VideoWriter -- MPEG-4');
saveas(gcf, 'myPeaks - VideoWriter -- MPEG-4.png');
close all;
clearvars -except number_of_frames Z
%%%
% Movie2AVI
%%%
%%
f = figure('renderer', 'zbuffer');
a = axes('parent', f);
axis(a, 'tight');
surf(a, Z);
current_zlim = zlim();
set(a, 'nextplot', 'replacechildren', 'zlimmode', 'manual', 'zlim', current_zlim);
movie_frames(1 : number_of_frames) = struct('cdata', [], 'colormap', []);
current_memory_used_Bytes(1, number_of_frames + 1) = 0;
current_memory_struct = memory();
current_memory_used_Bytes(1) = current_memory_struct.MemUsedMATLAB;
for(k = 1 : number_of_frames)
surf(a, sin(2*pi*k/20)*Z, Z);
movie_frames(k) = getframe(f);
current_memory_struct = memory();
current_memory_used_Bytes(k + 1) = current_memory_struct.MemUsedMATLAB;
end
movie2avi(movie_frames, 'myPeaks - Movie2AVI.avi', 'compression', 'none', 'fps', 10);
figure;
plot((current_memory_used_Bytes(2 : end) - current_memory_used_Bytes(1)) / 1e6);
xlabel('Frame Number');
ylabel('Movie Memory in RAM (MB)');
title('Movie2AVI -- AVI');
saveas(gcf, 'myPeaks - Movie2AVI -- AVI.png');
close all;
clearvars -except number_of_frames Z
%%%
% IMWrite
%%%
%%
f = figure('renderer', 'zbuffer');
a = axes('parent', f);
axis(a, 'tight');
surf(a, Z);
current_zlim = zlim();
set(a, 'nextplot', 'replacechildren', 'zlimmode', 'manual', 'zlim', current_zlim);
current_frame = getframe(a);
[frame_indices, cmap] = rgb2ind(current_frame.cdata, 256, 'nodither');
movie_frames = repmat(frame_indices, [1 1 1 number_of_frames]);
current_memory_used_Bytes(1, number_of_frames + 1) = 0;
current_memory_struct = memory();
current_memory_used_Bytes(1) = current_memory_struct.MemUsedMATLAB;
for(k = 1 : number_of_frames)
surf(sin(2*pi*k/20)*Z, Z)
f = getframe(a);
movie_frames(:, :, 1, k) = rgb2ind(f.cdata, cmap, 'nodither');
current_memory_struct = memory();
current_memory_used_Bytes(k + 1) = current_memory_struct.MemUsedMATLAB;
end
imwrite(movie_frames, cmap, 'myPeaks - IMWrite.gif', 'DelayTime', 0, 'LoopCount', inf);
figure;
plot((current_memory_used_Bytes(2 : end) - current_memory_used_Bytes(1)) / 1e6);
xlabel('Frame Number');
ylabel('Movie Memory in RAM (MB)');
title('Movie2AVI -- AVI');
saveas(gcf, 'myPeaks - IMWrite.png');
close all;
clearvars -except number_of_frames Z
%%%
% MPGWrite
%%%
%%
f = figure('renderer', 'zbuffer');
a = axes('parent', f);
axis(a, 'tight');
surf(a, Z);
current_zlim = zlim();
set(a, 'nextplot', 'replacechildren', 'zlimmode', 'manual', 'zlim', current_zlim);
winsize = get(f, 'Position');
winsize(1:2) = [0 0];
movie_frames = moviein(number_of_frames, f, winsize);
current_memory_used_Bytes(1, number_of_frames + 1) = 0;
current_memory_struct = memory();
current_memory_used_Bytes(1) = current_memory_struct.MemUsedMATLAB;
for(k = 1 : number_of_frames)
surf(sin(2*pi*k/20)*Z, Z)
drawnow;
movie_frames(:, k) = im2frame(hardcopy(f, '-Dzbuffer', '-r0'));
current_memory_struct = memory();
current_memory_used_Bytes(k + 1) = current_memory_struct.MemUsedMATLAB;
end
mpgwrite(movie_frames, jet, 'myPeaks - MPGWrite.mpg');
figure;
plot((current_memory_used_Bytes(2 : end) - current_memory_used_Bytes(1)) / 1e6);
xlabel('Frame Number');
ylabel('Movie Memory in RAM (MB)');
title('MPGWrite -- MPG');
saveas(gcf, 'myPeaks - MPGWrite.png');
close all;
clearvars -except number_of_frames Z
As we can see, VideoWriter, IMWrite and Movie2AVI have nearly constant memory requirements, while the memory necessary for AVI2File and MPGWrite scales with the number of frames. This makes sense as the latter require holding every frame before writing the movie, while the former appear to flush to disk regularly.
VideoWriter -- AVI: 154,529 KB
VideoWriter -- MPEG-4: 19,355 KB
IMWrite: 13,385 KB
Movie2AVI -- AVI: 992,276 KB
MPGWrite: 24,301 KB
MPEG-4 yields a much more efficient compression than AVI, as expected. Interestingly, VideoWriter and IMWrite both outperform MPGWrite on this test (though I give credit to MPGWrite for coming many years before VideoWriter!).