3

I am using parfor loop to produce and save quite big number of figures. Due to the amount of data which will be presented in the figures, the resolution of the figures need to be high, something around 920 dpi. Using the normal for, the function works fine. But when we switch to parfor the resolution of the produced and saved pictures becomes totally low.

This is the figure handle creation part:

mainFig=figure('visible','off');
set(mainFig, 'Renderer', 'OpenGL');

and here is the saving part code:

print(mainFig,'-djpeg','-r920',strcat(MyDir,measure,sec_suffix,'.jpeg'))

any idea?

Thanks

Amro
  • 123,847
  • 25
  • 243
  • 454
Mojtaba
  • 249
  • 6
  • 14
  • don't use `strcat` for paths and file names! use [`fullfile`](http://www.mathworks.com/help/matlab/ref/fullfile.html) instead! – Shai Jul 17 '14 at 12:23
  • stupid question: You're using just one drive, where you save your images, don't you? What speed up do you expect from `parfor` if you can/should write just one image per time? Of course it's possible, but it should be even slower using parfor than with a normal loop. – Robert Seifert Jul 17 '14 at 12:24
  • well, thanks. good idea :). but the problem still exists – Mojtaba Jul 17 '14 at 12:24
  • You might want to try to switch your default printing settings. http://www.mathworks.nl/help/matlab/creating_plots/overview-of-printing-and-exporting.html – EJG89 Jul 17 '14 at 12:28
  • Well, apparently it speeds me up to 20 times in saving the figures. but lower quality ones. for normal 'for' it takes me around 10 minutes to create 161 images with 1.4 mg size. With parfor it takes 34 seconds to create the same number but with 37kb. I think this is mostly related to the OS. isnt it? you mean that it is not possible that several files be written done on the hard drive at the same time? – Mojtaba Jul 17 '14 at 12:29
  • Well even if you have multiple write-heads in your harddisk drive, I can't imagine that there are more than maybe 5. If you write 161 images parallel the write-head needs to jump to different locations on your disc all the time, this is definitely slower. I would be interested in the results, when you get your problem solved, but generally I'd say the question is pointless. Well and that writing 161x1.4 Mb is slower than 161x37kB is undoubtly true. No matter whether written in parallel or serial. – Robert Seifert Jul 17 '14 at 12:41
  • Well, i now reduce the resolution of serial for to 70 dpi for 10 images. it takes 70.495767 seconds and exactly the same for parfor take 13.8487234 seconds. My loop consits of reading four .MAT files and plot them on different subplots using imagesc function. Really not that much calculation is in the loop. But your point is also right. Our server has 64 cores. I should gain much more than this which i apparently due to your point :) – Mojtaba Jul 17 '14 at 13:03
  • 1
    If you're working on a server there are probably not just 64 cores, but also multiple harddisk drives in raid. So you probably can access multiply write-heads. That means you actually CAN write multiple images in parallel, and `parfor` makes it possible. So to get the maximum performance, I assume you need to find out, how many files you can write parallel and this should be your number of parallel workers used in Matlab. – Robert Seifert Jul 17 '14 at 13:58

1 Answers1

6

This is a documented limitation of printing in headless mode:

Printing and Exporting without a Display

On a UNIX platform (including Macintosh), where you can start in MATLAB nodisplay mode (matlab -nodisplay), you can print using most of the drivers you can use with a display and export to most of the same file formats. The PostScript and Ghostscript devices all function in nodisplay mode on UNIX platforms. The graphic devices -djpeg, -dpng, -dtiff (compressed TIFF bitmaps), and -tiff (EPS with TIFF preview) work as well, but under nodisplay they use Ghostscript to generate output instead of using the drivers built into MATLAB. However, Ghostscript ignores the -r option when generating -djpeg, -dpng, -dtiff, and -tiff image files. This means that you cannot vary the resolution of image files when running in nodisplay mode.

The same is true for the -noFigureWindows startup option which suppresses figures on all platforms. On Windows platforms the -dwin, -dwinc, and -dsetup options operate as usual under -noFigureWindows. However, the printpreview GUI does not function in this mode. Naturally, the Windows only -dwin and -dwinc output formats cannot be used on UNIX or Mac platforms with or without a display.

Resolution Considerations

Use -rnumber to specify the resolution of the generated output. In general, using a higher value will yield higher quality output but at the cost of larger output files. It affects the resolution and output size of all MATLAB built-in raster formats (which are identified in column four of the table in Graphics Format Files).

Note: Built-in graphics formats are generated directly from MATLAB without conversion through the Ghostscript library. Also, in headless (nodisplay) mode, writing to certain image formats is not done by built-in drivers, as it is when a display is being used. These formats are -djpeg, -dtiff, and -dpng. Furthermore, the -dhdf and -dbmp formats cannot be generated in headless mode (but you can substitute -dbmp16m for -dbmp). See "Printing and Exporting without a Display" for details on printing when not using a display.

Unlike the built-in MATLAB formats, graphic output generated via Ghostscript does not directly obey -r option settings. However, the intermediate PostScript file generated by MATLAB as input for the Ghostscript processor is affected by the -r setting and thus can indirectly influence the quality of the final Ghostscript generated output.

The effect of the -r option on output quality can be subtle at ordinary magnification when using the OpenGL or ZBuffer renderers and writing to one of the MATLAB built-in raster formats, or when generating vector output that contains an embedded raster image (for example, PostScript or PDF). The effect of specifying higher resolution is more apparent when viewing the output at higher magnification or when printed, since a larger -r setting provides more data to use when scaling the image.

When generating fully vectorized output (as when using the Painters renderer to output a vector format such as PostScript or PDF), the resolution setting affects the degree of detail of the output; setting resolution higher generates crisper output (but small changes in the resolution may have no observable effect). For example, the gap widths of lines that do not use a solid ('-') linestyle can be affected.


parfor spawns headless MATLAB instances (both Windows and Unix), so according to the above, the worker processes will fallback to Ghostscript printing driver which ignores the -r option.

When you export figures to raster graphics format (PNG, JPEG, TIFF, etc..) there are two cases:

  • if you printing in a normal session, MATLAB will use its built-in drivers to generate the graphics files directly, and should obey the resolution you specify

  • on the other hand, if you printing in headless mode, MATLAB will internally export the figure in Postscript vector format, and then use Ghostscript to convert it to the requested raster format using the following Ghostscript options:

    -dNOPAUSE -q 
    -I"C:\Program Files\MATLAB\R2014a\sys\extern\win64\ghostscript\ps_files"
    -I"C:\Program Files\MATLAB\R2014a\sys\extern\win64\ghostscript\fonts"
    -sDEVICE=jpeg
    -g576x432
    -sOutputFile="file.jpeg"
    

    as you can see, for some reason MATLAB uses a fixed target size 576x432 in headless mode when converting the PS file to other formats.


Here is some code for quick experimentation. I've tested it on a local parallel pool; All of the raster formats (PNG, JPEG, TIFF, PPM) had a fixed size of 576x432 (-r option ignored as previously explained). The PDF was also generated by converting the PS file to PDF (using -sDEVICE=pdfwrite Ghostscript output device).

fmt = {'ppm', 'tiff', 'png', 'jpeg', 'epsc2', 'pdf'};
outfolder = 'C:\Users\Amro\Desktop\print_test';

parpool(4)
parfor i=1:4
    fig = figure(i);

    % a random plot
    ax = axes('Parent',fig);
    plot(ax, cumsum(rand(1000,1)-0.5))

    % save in each specified format (-r option is mostly ignored)
    for f=1:numel(fmt)
        print(fig, ['-d' fmt{f}], '-r920', ...
            fullfile(outfolder,sprintf('plot%d.%s',i,fmt{f})));
        drawnow
    end

    % also save FIG-file
    hgsave(fig, sprintf('plot%d.fig',i))

    close(fig);
end
delete(gcp)

The way I see it, you ought to export as an EPS file, and manually convert it to whatever format you need. That way you get to specify the target image size in the Ghostscript command invoked (I wouldn't bother with the print -r resolution option, because it has little effect on vector formats)

The alternative would be to export FIG-files inside parfor. You would then load them in a normal MATLAB session with a display, and serially print with the desired resolution and format:

for i=1:4
    fig = hgload('plotXX.fig');
    movegui(fig, 'center')
    print(fig, '-djpeg', '-r920', 'outXX.jpeg')
    close(fig)
end
Amro
  • 123,847
  • 25
  • 243
  • 454
  • Thank you for such a nice explanation, So,it seems that there is no way :\ – Mojtaba Jul 17 '14 at 13:35
  • Or you mean something else than -djpeg, -dpng, -dtiff, and -tiff may work? – Mojtaba Jul 17 '14 at 13:36
  • 1
    (untested) you could try to save the figures as [FIG-files](http://www.mathworks.com/help/matlab/ref/hgsave.html) in the `parfor` loop, and then **serially** load the figure and `print` as JPEG files in a normal MATLAB session – Amro Jul 17 '14 at 13:36
  • btw, can you exlain briefly why .fig will not care the resolution? because it doenst contain rendering process? – Mojtaba Jul 17 '14 at 13:39
  • FIG-files are just regular MAT-files with a special extension. They contain the HG objects and their properties/data. So it's not a graphics format rather serialized data.. – Amro Jul 17 '14 at 13:42
  • 1
    @Mojtaba: also how about you use a vector format like [EPS](https://en.wikipedia.org/wiki/Encapsulated_PostScript) or PDF? `print(..., '-depsc2','file.eps')` – Amro Jul 17 '14 at 13:50
  • Well, thanks for your answers. for now the server is down and i can not try anything. But i think it will not make sense to save them first as .fig and then try to render them. It is exactly the same, because in my loop i am actually loading some .MAT files. But i will try it later to see how much i will gain. I will test your second suggestion too. Thanks again. – Mojtaba Jul 17 '14 at 14:00
  • the EPS doesnt work for me. If it works for you i would be really glad to hear how. It again makes the same low quality ones. But .fig idea was good. It creates the .fig file with 316 KB (one quarter of the expected) and quite fast. So the issue of hard access is really less important. without parfor the job is done in around 10 minutes. with parfour one quarter of the job is done in less than 15 sec. So at least 10 times speed up gained. Thanks Amro for your nice answers :) – Mojtaba Jul 17 '14 at 18:12
  • [PostScript](https://en.wikipedia.org/wiki/PostScript) EPS is not low quality, it's a [vector graphics](https://en.wikipedia.org/wiki/Vector_graphics) format ideal for printing purpose. You can zoom-in and resize it as much as you want and it will still look crisp (just like PDF files or SVG graphics you see in browsers) – Amro Jul 17 '14 at 18:25
  • For instance, you can convert an EPS file to a high resolution JPEG image using something like ImageMagick: http://stackoverflow.com/a/7584726/97160 – Amro Jul 17 '14 at 20:14