Degraded image quality in a very large figure
8 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Johnny B
el 28 de Mayo de 2021
Comentada: Walter Roberson
el 29 de Mayo de 2021
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 comentarios
Walter Roberson
el 28 de Mayo de 2021
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.
Respuesta aceptada
Walter Roberson
el 28 de Mayo de 2021
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 comentarios
Walter Roberson
el 29 de Mayo de 2021
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
Más respuestas (0)
Ver también
Categorías
Más información sobre Migrate GUIDE Apps en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!