Search code examples
matlabperformancematlab-figure

Computationally Fast Way to Save Matlab Figures as Image (eg PNG)


I have a program that creates a lot of plots which I want to save as fig001, fig002, .... At the moment, the only way I can do this is to either save them one by one as I go along using print() or so save them into a graphics object FIG.

Unfortunately, I have to create the plots sequentially (can't parallelise it). If I save as I go, then this takes quite a long time; if I store in FIG then do a parfor-loop over all the figures, then this is faster. However, it's still pretty slow, and it's a major bottleneck in my code.

Matlab is automatically writing a 1200x900 pixel image. In reality, it's just a graph with some (horizontal) straight lines on it. I really do not need a high image quality whatsoever; maybe reducing this would help speed things up? I can't find how to do this either.

I've had a look online, in particular at other SE questions, but I haven't been able to come up with a solution. There's various stuff about "playing around with the hardcore function". I'm a mathematician who wants a code to get some intuition for the problem; I'm not a proper programmer! As such, "play around with a function" (that might cause Matlab to crash) is rather difficult for me!


I've sorted this by using the Matlab movie function. Thank you Cecilia for your assistance!


Solution

  • Since your intention is to use the images in a slideshow. I would suggest making a movie and using that instead. I've run a few tests, and saving a movie is much faster than saving individual pngs. I see about a 5x speed up in my simple test.

    numImages = 25;
    
    %Saving one figure at a time
    tic;
    for i= 1:numImages
        x = 0:0.1:2*pi;
        y = i*sin(x);    
        plot(x, y);
    
        fig = gcf;
        print('img.png', '-dpng', '-r50'); %Downsample resolution
    end
    toc;
    
    tic;
    
    %Saving a movie
    v = VideoWriter('mov.avi');
    open(v);
    for i = 1:numImages
        x = 0:0.1:2*pi;
        y = i*sin(x);
        plot(x, y);
    
        drawnow; %Force the figure to render
        frame = getframe; %Convert the figure to a movie frame
        writeVideo(v, frame); %Write the frame to the movie file
    end
    close(v);
    
    toc;
    

    Using writeVideo also has the advantage of never storing the whole movie in memory. Instead, as each frame is captured, it is immediately written to the file. The one downside is that because the frames need to be written in the correct sequence, you can not use a parfor

    You could also consider making a movie matrix. Each element would be a frame. So to initialize the size of the matrix, you would need something like

    numImages = 25;
    mov(numImages) = struct('cdata',[],'colormap',[]);  
    

    Then using the parfor, you can assign all the images to your mov matrix in the correct order. After your loop is finished, you can write the movie to a file using VideoWriter. However, while generating your figures, you will need to keep your whole movie in memory, and there is an overhead associated with parfor, so it may not end up being more efficient.