Compress movies of flat plots of few points and lines in Matlab (why are they so heavy?)

792 views Asked by At

Consider a sequence of points:

N = 8 * 360; t = (0:9:N) + N / 4;
x = sqrt(t) .* cos(t * pi / 180);
y = sqrt(t) .* sin(t * pi / 180);

Then visualize the path, get the frames and make a movie:

f = figure('Position', [300 75 900 600]);
hold on
h_plot1 = plot(x(2:end), y(2:end), 'ob', 'MarkerEdgeColor', 'b', 'MarkerFaceColor', 'b', 'MarkerSize', 5);
h_plot2 = plot(x(1), y(1), 'o-r', 'MarkerEdgeColor', 'b', 'MarkerFaceColor', 'b', 'MarkerSize', 5, 'LineWidth', 3);
x_min = min(x); x_max = max(x); y_min = min(y); y_max = max(y);
x_w = x_max - x_min; y_w = y_max - y_min;
axis([x_min - x_w / 10 x_max + x_w / 10 y_min - y_w / 10 y_max + y_w / 10])
axis equal, axis off
set(f, 'Color', [1 1 .25])
set(gca, 'Color', [1 1 .25])
set(gca,'nextplot','replacechildren');
vid = VideoWriter('myveryheavymovie.avi');
vid.Quality = 100;
vid.FrameRate = 15;
open(vid);
for hh = 1:length(x)-1
  hold on
  set(h_plot1, 'XData', x((hh + 1):end), 'YData', y((hh + 1):end))
  set(h_plot2, 'XData', x(1:(hh + 1)), 'YData', y(1:(hh + 1)))
  tmp = plot(x(hh:hh+1), y(hh:hh+1), 'or', 'MarkerSize', 8, 'MarkerFaceColor', 'r');
  writeVideo(vid, getframe(f));
  delete(tmp)
  writeVideo(vid, getframe(f));
end
close(vid);

The movie is 111,840 KB, unreasonably heavy - is there a way to compress the movie? The images are just a handful of points and lines: can the movie be compressed to - say - less than 1,000 KB?

EDIT following answers from A. Donda, chappjc and horchler

Apparently I cannot change profile and for the moment I haven't tried third party software. I have tried generating a gif animation with imwrite:

% Consider a sequence of points:
N = 8 * 360; t = (0:9:N) + N / 4;
x = sqrt(t) .* cos(t * pi / 180);
y = sqrt(t) .* sin(t * pi / 180);
x_min = min(x); x_max = max(x); y_min = min(y); y_max = max(y);
x_w = x_max - x_min; y_w = y_max - y_min;

% Create figure:
f = figure('Position', [300 75 900 600]);
set(f, 'Color', [1 1 .25])
h_plot1 = plot(x(2:end), y(2:end), 'ob', 'MarkerEdgeColor', 'b', 'MarkerFaceColor', 'b', 'MarkerSize', 3);
hold on
h_plot2 = plot(x(1), y(1), 'o-r', 'MarkerEdgeColor', 'b', 'MarkerFaceColor', 'b', 'MarkerSize', 3, 'LineWidth', 3);
axis([x_min - x_w / 10 x_max + x_w / 10 y_min - y_w / 10 y_max + y_w / 10])
axis equal, axis off
set(gca, 'nextplot','replacechildren', 'Visible','off');

% preallocate mov fo gif animation
nFrames = length(x)-1;
frame = getframe(gca);
[frame, map] = rgb2ind(frame.cdata, 256, 'nodither');
map = [map; 1 0 0];
mov = repmat(frame, [1 1 1 2*nFrames]);

% Visualize it, get the frames and save gif animation
for hh = 1:nFrames
  set(h_plot1, 'XData', x((hh + 1):end), 'YData', y((hh + 1):end))
  set(h_plot2, 'XData', x(1:(hh + 1)), 'YData', y(1:(hh + 1)))
  hold on
  tmp = plot(x(hh:hh+1), y(hh:hh+1), 'or', 'MarkerSize', 8, 'MarkerEdgeColor', 'r', 'MarkerFaceColor', 'r');
  frame = getframe(gca);
  mov(:, :, 1, 2*hh-1) = rgb2ind(frame.cdata, map, 'nodither');
  delete(tmp)
  frame = getframe(gca);
  mov(:, :, 1, 2*hh) = rgb2ind(frame.cdata, map, 'nodither');
end
close(gcf)
imwrite(mov, map, 'mynotsoheavygif.gif', 'DelayTime', 0, 'LoopCount', inf)

The gif file is 4,420 KB - which is not good and not bad but better than the avi file.

3

There are 3 answers

2
horchler On BEST ANSWER

If you can switch to the 'MPEG-4' profile, that will help a lot. Make sure that you specify the 'Quality' as well - the default is 75 out of 100.

One reason that the movies can be large is that the available codecs aren't necessarily the most suitable for typical Matlab content. It looks like you're writing a video of a fairly basic plot window: flat content with areas of constant color and likely little use of gradients and antialiasing. If QuickTime is acceptable to you and you're interested in using a third-party function, you could try my QTWriter. Notably, it supports a QuickTime 'Photo PNG' codec that may compress your content more efficiently than the MPEG-4 codec (or very close) while being lossless and supporting transparency. QTWriter is modeled closely after Matlab's VideoWriter class so switching over should be easy. It's a single M-File and has several other unique and useful features. You can view example code and videos on the project website.

Additionally, if you have a Mac with a Retina display, I think that getframe has a bug that leads to blurry images and video. Depending on the codec, this could make compression better or worse. Regardless, it looks bad. You can try getframebg if this is an issue for you.

0
A. Donda On

The kind of compressed video you can generate depends on the platform: doc VideoWriter says

VideoWriter can create uncompressed AVI and Motion JPEG 2000 compressed AVI files on all platforms, and MPEG-4 files on Windows® 7 and Mac OS X 10.7 and higher.

If you are on a platform that does not support MPEG-4 and you don't want to use Motion JPEG, you can try to use an external tool like ffmpeg to compress the video after you have generated it.

Please note though that almost all video compression algorithms are optimized for real-world photographic scenes with smooth movements. They do not generally perform well on line graphics, but quickly induce compression artefacts even for a slight reduction in file size. VideoWriter provides one alternative to lossy compression, namely lossless Motion JPEG 2000 via the 'Archival' profile.

Depending on what you need the animation for, writing an animated gif using imwrite might be another lossless alternative.

0
chappjc On

Try changing the profile argument when creating the VideoWriter (i.e. writerObj = VideoWriter(filename,profile)). Of interest to you are the following profiles:

profile

String enclosed in single quotation marks that describes the type of file to create. Specifying a profile sets default values for video properties such as VideoCompressionMethod. Possible values:

'Archival' Motion JPEG 2000 file with lossless compression

'Motion JPEG AVI' Compressed AVI file using Motion JPEG codec

'Motion JPEG 2000' Compressed Motion JPEG 2000 file

'MPEG-4' Compressed MPEG-4 file with H.264 encoding (systems with Windows 7 or Mac OS X 10.7 and later)

'Uncompressed AVI' Uncompressed AVI file with RGB24 video

In particular, 'MPEG-4' will give the best compression-quality compromise, if your system supports H.264 encoding.

However, for a video of plots, it may be necessary to use a lossless compression method, such as 'Archival'. Note that with lossless compression, the Quality option is not used.

For the lossy compression methods (e.g. 'MPEG-4' or 'Motion JPEG AVI'), consider simply using a lower Quality setting.