Degraded image quality in a very large figure

9 次查看(过去 30 天)
I am running a script, under Linux, that creates a huge hidden figure -- over 8000 pixels square -- and writes it to a JPEG file using the print function. The axes region ends up being about 5600 pixels square, and there is a 2400×2400 grayscale RGB image that is plotted in the axes. Until recently, the script was being run under R2014b (!), and the images it produced were fine; each pixel of the image in the axes became 2 or 3 pixels in the JPEG as would be expected from the 5600:2400 ratio.
That computer system has now been upgraded to R2018a, and the same script is now producing really poor images. The figure itself looks fine; tick marks are one pixel wide, and the axes labels are sharp and clear. But the image within the axes has been coarsened, with each original image pixel becoming 9 1/2 JPEG pixels. It is as if the original 2400×2400 image had been downsampled to 600×600.
I've tried resizing the image so that the axes covers exactly 2400×2400 pixels, and the result is the same. I've used getframe on the figure and the returned cdata has 2400×2400 pixels in the axes area, but every 4×4 block is the same. Clearly it is the original image rendering that is to blame. I know that MATLAB added DPI-awareness in R2015a, but everything I've read about that change seems to indicate that I should see better images in later versions.
I've come up with a workaround -- capturing the figure with getframe and replacing the axes region with my original image -- but it is tedious and not very flexible. Is there some way to force MATLAB to use my image's full resolution since it clearly has the space to do so?
==== Update ====
As requested, here is a code snippet. Note that it won't illustrate the problem on Windows, because Windows doesn't allow the figure to be larger than the screen.
% Create a figure, turn visibility off, and make it large enough for a
% 2400×2400-pixel axes
hf = figure('Visible', 'Off');
hf.Position = [ 0 0 3277 2946 ];
hf.GraphicsSmoothing = 'off';
numAxPixels = 2400;
% Set some horizontal and vertical spacing for our test grid
h = 5;
v = 8;
% Create a test grid of one-pixel lines
checks = zeros(numAxPixels);
checks(h:h:end, :) = 1;
checks(:, v:v:end) = 1;
% Put the image on the axes and resize the axes to make it the same size as
% the image
imagesc(checks)
colormap(gray(2))
colorbar
% Adjust the axes to be exactly the right size
ha.Units = 'pixels';
ha.Position = [ 417 325 numAxPixels numAxPixels ];
% Grab what's in the figure, and display it in a new figure
F = getframe(hf);
figure
imagesc(F.cdata)
axis image
set(gca, 'Position', [ 0 0 1 1 ])
  12 个评论
Walter Roberson
Walter Roberson 2021-5-28
When I zoom in on Mac, I get what appears to be a regular grid, plausibly 5:8 ratio (I did not measure.)
ha.Units = 'pixels';
ha.Position = [ 417 325 numAxPixels numAxPixels ];
Notice that ha does not refer to the current axes; you are just creating a struct there.
Johnny B
Johnny B 2021-5-29
Ah, you're right about ha not being a handle. The Linux system on which the problem occurs is not connected with the real world, so I had to re-type the code onto my Windows machine, and I left out the ha=gca; statement. Thanks for catching that. But I did have that statement in my code to recreate the problem on the other system.

请先登录,再进行评论。

采纳的回答

Walter Roberson
Walter Roberson 2021-5-28
Also, you are not necessarily drawing into the figure you created. However, that in itself is not enough to repair the problem.
The problem seems to occur when the numAxPixels is 2050 or higher, but not when it is 2049 or lower. I might have guessed 2048 as a boundary.
% Create a figure, turn visibility off, and make it large enough for a
% 2400×2400-pixel axes
hf = figure('Visible', 'Off');
hf.Position = [ 0 0 3277 2946 ]
hf.GraphicsSmoothing = 'off';
ha = axes(hf);
numAxPixels = 2400 - 350
% Set some horizontal and vertical spacing for our test grid
h = 5;
v = 8;
% Create a test grid of one-pixel lines
checks = zeros(numAxPixels);
checks(h:h:end, :) = 1;
checks(:, v:v:end) = 1;
% Put the image on the axes and resize the axes to make it the same size as
% the image
imagesc(ha, checks)
colormap(ha, gray(2))
colorbar(ha)
% Adjust the axes to be exactly the right size
ha.Units = 'pixels';
ha.Position = [ 417 325 numAxPixels numAxPixels ];
% Grab what's in the figure, and display it in a new figure
F = getframe(hf);
figure
imagesc(F.cdata)
axis image
set(gca, 'Position', [ 0 0 1 1 ])
  2 个评论
Johnny B
Johnny B 2021-5-29
I'm not sure what you mean by "you are not necessarily drawing into the figure you created." There is nothing between the figure creation step and the image commmand that would have changed the CurrentFigure of the root or the CurrentAxes of the figure.
Walter Roberson
Walter Roberson 2021-5-29
There are circumstances under which the focus can change between commands:
  • if the debugger fires, then if you incidentally click on any other window (such as to move it out of the way so you can see the command window), then the other window will become the Current figure
  • timer callbacks and I/O callbacks (such as serial port callbacks or DAQ callbacks) can occur at the beginning of any line of MATLAB code, and can result in the Current figure changing
  • Although the model for traditional figures does not permit interruptions except when there is a pause() or drawnow() or uiwait() or waitfor() or figure() call, the desktop and App framework permits multiple figures to be active simultaneously, so it is possible for the programming for them to change the Current figure
Because of these kinds of factors, you should always provide the graphics handle for any operation that supports supplying graphics handles. See https://www.mathworks.com/matlabcentral/answers/317181-non-deterministic-behavior-with-multiple-figures#answer_247493

请先登录,再进行评论。

更多回答(0 个)

类别

Help CenterFile Exchange 中查找有关 Migrate GUIDE Apps 的更多信息

产品


版本

R2018a

Community Treasure Hunt

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

Start Hunting!

Translated by