Convert just the content of a figure to an image in MATLAB - matlab

I am currently using getframe() and frame2im in MATLAB to convert a figure of a plot to an image.
I just realized that this is working almost like a screenshot of the figure, with all the axes and labels taken into account as well.
How can I convert JUST the contents of the figure (aka the "plot") into an image?
I don't really want to save all of them to file first.

You can use the getframe / cdata idiom. What this will do is that if you call getframe on the current frame in focus without any parameters, it will return a structure to you that contains a structure element called cdata. This stores the RGB pixel array of just the figure contents themselves. The axes and labels are not captured - only what is painted onto the figure is captured.
Here's an example to get you started:
im = imread('cameraman.tif');
imshow(im);
h = getframe;
out = h.cdata;
figure;
imshow(out); %// Should give you the contents within the imshow frame.
FWIW, I also answered this same question here, though it was for a different situation: keep new image when drawing lines by dragging the mouse in matlab

As far as i know, cdata DOES NOT WORK. I had a major problem recently with the same thing - the only work around i could find is to crop each image after using getframe and cdata - this will work fine for images that are all the same size (ugly as it is - you just need to find the grey edges in the image), but if the images are all different, this wont work (well, it wont work well. there might be some way to automatically adjust the crop size)

Related

MATLAB how to get rid from whitespace when saving figures as JPG

I am writing a code for flowers recognition in MATLAB
but whenever I want to save a figure
it is saved with a white border - margin
how can I remove it
and save it as the exact size of the original image?
any help would be much appreciated
You can use getframe(gca) to grab the axes and not the entire figure (which is what would happen with simply getframe alone or getframe(gcf)). Then convert that frame to an image with frame2im. Then you can write that image to file with imwrite.
figure;
plot(x,y);
axis off
img = frame2im(getframe(gca));
imwrite(img,'myImage.png');
This might help:
figure('Color','none');
plot(1:10,1:10)
axis off
set(gca,'Color','none');
print ('-djpeg', 'no_background.jpg')

Image gradually erased when overlayed with lines

Apart from the fact there exist special functions to plot vector fields, I have encountered a strange Matlab behaviour: Plotting an image (with imagesc or imshow) and overlaying it with colored lines (with plot or line) leads at some point to an erasement of the background image.
%% some data...
% random image
Image = rand(200,400);
% 900 lines of random color
color1 = rand(1,900);
color2 = rand(2,900);
color3 = rand(3,900);
% some positions
x = 31:60;
y = 31:60;
[X,Y] = meshgrid(x,y);
%% plot process
% plot Image (with 'imshow' or 'imagesc')
imshow(Image);
hold on;
% plot the lines (with 'line' or 'plot')
for i = 1:900
line([X(i), X(i)+1],[Y(i),Y(i)+2],'color',[color1(i),color2(i),color3(i)]);
if i == 100 % nothings happens to background image after 100 vectors
pause();
elseif i == 200 % gradually starts to change...
pause();
end
end
% ... at the end it is completely erased
Result: 100 lines
Result: 200 lines
Result: 900 lines
Nice side fact Saving the image as PNG restores the image (but destroys the line resolution).
This is not properly an answer, as it doesn't exactly explain why this is happening, but it provides a workaround, along with some more observations of the weird behaviour.
Scope:
I tried your example and indeed:
pre HG2 (R2013a): Same behavior than you described
HG2 (R2015a) : No problem, everything is there.
Workaround:
After a few trial and error, I worked out that it is a specific behaviour of the painter renderer in pre HG2 versions.
If you change the renderer to any other than the default painter, you get back your image and your superimposed lines.
set(gcf,'Renderer','zbuffer')
%// OR
set(gcf,'Renderer','opengl')
Observations:
Note that I also tried to:
display the lines first (no problem), then the image (and reorder using uistack) => same black image.
use multiple axes => black frame
And to show you how persistent is the glitch:
if you delete all the lines, the image does not reappear (=black frame).
if you delete all graphics objects, then re display the image => black frame
if you cla or even clf then re display the image => black frame
The only way I found to get the image displayed is to change the renderer as described above.
Printing/Saving
Initially, I thought the change of renderer was happening behind the scene when you were saving the figure, thereby allowing the final output to be fully displayed. Unfortunately, by exploring a bit more it doesn't seem to be so simple.
I tried different version with print (instead of saveas) since it allows you to select the renderer. For each renderer I chose 2 formats, PDF which uses the ghostscript engine, and PNG which uses the Matlab engine:
%%
print(1,'-dpng','-painters','testimageP.png')
print(1,'-dpng','-zbuffer' ,'testimageZ.png')
print(1,'-dpng','-opengl' ,'testimageO.png')
%%
print(1,'-dpdf','-painters','testimageP.pdf')
print(1,'-dpdf','-zbuffer' ,'testimageZ.pdf')
print(1,'-dpdf','-opengl' ,'testimageO.pdf')
Well, after results I am still unsure of what is happening. All these saved figures show the proper image and the lines on top... But:
The 3x png images (Matlab engine) are exactly similar. They do not even show slight difference in saturation like you can observe when you switch the renderer manually. This made me think that Matlab chose to ignore my renderer specification. It just decided which one was the most relevant and went ahead printing 3 times the same figure. So I thought may be the painter renderer wasn't used and that's why the images were shown.
Well not so fast. On the 3x pdf images (ghostscript engine) ... I can observe the small nuances between the 3 pictures ... so the renderer wasn't the same between them. The painter was used on one of them, and successfully rendered the image.
So in conclusion, it seems the painter renderer is only glitchy when applied to a (pre-HG2) figure!

Save Spectrogram as an Image in MATLAB

I'm analyzing some sound clips using the spectrogram() function in MATLAB. I would like to save the spectrogram as an image (jpg, png, etc). But regardless of what image format I save the figure in, the resulting image always looks different ("spotty") from what I see in the figure.
Here's an example of the spectrograms: Matlab Figure vs. Saved Image
All I want is to save exactly what I see in the figure as an image. I've already tried saving the figure in all the image formats possible but all of them are producing the same "spotting" effect. I've also tried both manual saving (click on file -> save as) and programmatically using the print() and the saveas() functions. Same result every time.
Any help would be appreciated!
What is the data range of your spectrogram?
One of reasons might be that your spectrogram range is out of the [0,1] region for double images or [0,255] for uint* images (your white spots on saved image are suspiciously close to the local minima on MatLab figure).
Another guess might be that you are using imwrite function, in particular its imwrite(X,map,filename,fmt) syntax. MatLab documentation explains:
imwrite(X,map,filename,fmt) writes the indexed image in X and its associated colormap map to filename in the format specified by fmt. If X is of class uint8 or uint16, imwrite writes the actual values in the array to the file. If X is of class double, imwrite offsets the values in the array before writing, using uint8(X–1). map must be a valid MATLAB colormap. Note that most image file formats do not support colormaps with more than 256 entries.
so the uint8(X–1) might be the source of the white spots.
Though have no idea why they appear after print()'ing.
I found a work-around for this problem by using the pcolor() function, which is essentially a rotated surf() function plotted in a grid format (doc). After tinkering with the spectrogram() function more, I'm convinced that these "spotting" artifacts have nothing to do with the data format, property, or scale. The problem seems to lie in the way MATLAB plots and visualizes 3D plots. I tried plotting with the mesh() function as well and it produced a different kind of "spotting" effect. pcolor() works because it's a 2D visualization of a 3D plot.
This is how spectrogram() plots the image using surf() (adapted from the doc):
[S,T,F,P] = spectrogram(X,256,250,256,2000);
surf(T,F,abs(S),'EdgeColor','none');
axis tight; view(0,90);
... and this is how to use pcolor() to plot a save-friendly image:
[S,T,F,P] = spectrogram(X,256,250,256,2000);
h = pcolor(T,F,abs(S));
set(h,'EdgeColor','none');
The white spots are an OpenGL issue, which is the renderer used in spectrogram()'s internal call to surf().
Since you are interested in plotting a 2D visualization, change the renderer for the current figure to zbuffer:
set(gcf, 'renderer', 'zbuffer');
where gcf means "get current figure". The white spots are now gone.
Note that you can also select the zbuffer renderer when you create the figure, before calling spectrogram():
myNewFig = figure('renderer','zbuffer');

Images not being displayed properly

I am working with MATLAB R2012b. I am trying to get 7 images to display on one figure but I can get the image that MATLAB to displays to look exactly like the original file. I set the color map to gray in hopes that you make it look the same but no its still different. I have included both the original and what I get from MATLAB so you can see what is happening.
Here is my code:
w8 = imread('Winter8','jpg');
subplot(2,4,1), image(w8);
title('Winter8.jpg');
axis('off','image');
colormap('gray');
truesize;
And here are the images:
Orirginal:
Result from MATLAB:
Thanks for you help.
imagesc seems to work better than image
imagesc(w8);
colormap('gray');
imagesc makes a nicer looking image in your case because you seem interested in using a gray color map as a filter. You can specify a range with clims, but you don’t have as much control as with image.
If you run colorbar on your figure, you’ll see what I’m talking about.
image would be better to use in a situation where you want much finer control over your data. For example, if you wanted to plot your data in true color instead of with a colormap, it would be easier to hack that together with the image function compared to the imagesc function because you wouldn’t be worried about scaling clims with a true color image.

how to make an image large enough to avoid tick label overlapping?

Assume that the data X has size 1000 *1000. X is displayed using the command:
imagesc(X);
and all the rows are labeld using:
set(gca, 'YTickLabel', somelabels);
Although the data X are properly polotted and the Ytick labels are also shown, the labels are highly overlapped because of the large number of rows. Is there any way to solve the problem? Any help will be highly appreciated.
Edit 1
I realize my question was not stated well to represent my problem. I am going to wrap up my understanding based on the answers and re-ask a question:
To show as many rows/labels in a Figure Window, the following helps:
set(gca,'FontSize',6),
or, alternate the distance (suggested by yuk),
or, set(gca,'YTick',1:10:1000,'YTickLabel',somelabels(1:10:1000));
The code
set(gca,'Units','pixels','Position',[20 20 10000 10000]);
will display a zoomed-in image by default. But if the zoomed-in image is too large to fit in the Figure Window, only part of the image will be displayed. However, neither zoom out nor the pan tool can reach to the rest part of that image.
The default behavior of the code
imagesc(X);
set(gca, 'ytick', 1:1000, 'yticklabe', ylabel);
displays the whole image fitting to the Figure Window with overlapping labels. Nevertheless, it does allow one to zoom into part of the image and to see the un-overlapped labels.
If I save the image into a pdf file:
imagesc(X);
set(gca, 'ytick', 1:1000, 'yticklabe', ylabel);
saveas(gcf, 'fig.pdf');
Then the saved pdf is only the image fit to the Figure Window with overlapping labels. However, unlike zoom in within Matlab figure window, zoom in within a pdf reader won't change the relative position/distance of labels. As a result, the zoomed-in image in pdf is still label-overlaped.
So my question is:
How to save the image into a pdf file or png such that it has a similar behavior as of point 3 above when opened in Adobe reader, rather than that of point 4?
You can also play with axes label font to make it smaller.
set(gca,'FontSize',6)
See also other axes properties to change font - FontName, FontWidth, FontUnits, etc.
Another solution: If your labels are short, you can alternate there distance from the axes, so the labels will not overlap. Check this example:
lbl = cellstr(reshape(sprintf('%3d',1:100),3,100)');
lbl(1:2:100) = strcat(lbl(1:2:100),{' '});
imagesc(rand(100))
set(gca,'ytick',1:100)
set(gca,'yticklabel',lbl)
Part of the resulted image:
UPDATE
To answer your updated question.
PDF document can contain only static images. Once you saved the figure to PDF (or any other graphic file), you cannot zoom in/out as with MATLAB figure tools.
You can zoom first on the MATLAB figure, then save PDF file. In this case the figure will be saved as is. But this way assumes user interactivity with the figure.
If you know your region of interest in advance, you can set axes limits with XLim/YLim properties, then save the figure.
Example:
imagesc(X);
set(gca, 'ytick', 1:1000, 'yticklabe', ylabel);
set(gca, 'XLim',[1 20], 'YLim', [20 40])
saveas(gcf, 'fig.pdf');
By the way, you can also save figure to file with PRINT function. More flexible. SAVEAS is just wrapper around it.
print('-dpdf','fig.pdf')
Another option is to rotate the tick labels which is discussed in this technical solution. You can find a number of easy-to-use implementations on the MATLAB File Exchange.