Save Spectrogram as an Image in MATLAB - 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');

Related

Matlab, high quality plot, two legends

I would like to produce a plot with two y-axis and two legends, looking something like this:
I have modified a code I found online to produce a high-quality plot to use in reports/papers. I was wondering how you add a second y-axis in such a code? I have attached the matrix and code to produce the high-quality plot: https://drive.google.com/file/d/1aKZLFeoO1wmQ1P2tEiiucvOFI7PehkGL/view?usp=sharing
https://drive.google.com/file/d/1aKZLFeoO1wmQ1P2tEiiucvOFI7PehkGL/view?usp=sharing
NOTE: This is basically a comment, however, it grew too long, and I felt it was too important not to mention properly.
Reporting plots from Matlab should always, unless you have some very good excuse, be done using vector graphics, i.e. pdf, ps, eps or similar format. The reason for this is the quality, e.g. here I have taken your high-quality and the similar pdf-version and zoomed in.
The png version has artifacts. The reason for this is that the png (similar for jpg and more) is that the picture is saved using pixels, thus when you zoom the quality deteriorate.
The pdf version, which is made with vector graphics, save the vectors, thus when I zoom the pdf viewer can regenerate the pixels and maintain the same quality. As an added bonus, the vector-graphic version is typically smaller in size.
This is made in Matlab using
saveas(gcf,'myfigure.pdf')
Use yyaxis to add another plot with an axis. Take a look at the following modified portion of your code.
yyaxis left
plot(N(:,1),N(:,3)/(27.5*2),'b-','DisplayName','Location','LineWidth',lw); %<- Specify plot properites
yyaxis right
plot(N(:,1),N(:,4)/(27.5*2),'r-', 'DisplayName','NorthEast','LineWidth',lw); %<- Specify plot properites
legend('Location', 'NorthEast');

imshow shows different output than imwrite

I was wondering how it is possible to save an image created by imshow in matlab. The code below uses the imshow function with the min and max arguments specified - How can I apply this directly to the image itself instead of just specifying Matlab to show it?
maxBlur=3;
a = imshow(fDmap,[0 maxBlur]);
imwrite(a, 'img.png');
Writing to the file produces a different output to what is shown via imshow.
Can anyone suggest how to get the output from imshow saved as an image?
To specify upper and lower intensity limits for imwrite (similar to what you've done for imshow), you will want to use the second inputs to mat2gray to adjust the contrast of your image prior to saving it with imwrite.
imwrite(mat2gray(fDmap, [0 maxBlur]), 'img.png');
If you literally want an image of what you're seeing with imshow, you can use saveas to take a screenshot. This will potentially be lower resolution than the previous approach and will also include whitespace around the image.
imshow(fDmap, [0 maxBlur]);
saveas(gcf, 'img.png');
NOTE: The a variable that you passed to imwrite in your post is a MATLAB graphics handle to an image object that is used to manipulate the rendered image. imwrite expects image data in matrix form not as a graphics handle.

How do I display a surf of an image in MATLAB?

I have an image that shows depth of the image using colors where warmer colors represent the closer parts of the image and cooler colors represent objects further away. I want to represent this image as a surf plot showing the depth. I have to do this in java but I think its easier to understand the process in Matlab first before moving on. I tried using the size of the image and plotting that but it kept giving me errors. Any help would be much appreciated.
I tried the surf function:
`img = imread('sample.png');
grayImage = rgb2gray(img);
surf(double(img))`
and got this error:
>> surf
Attempt to execute SCRIPT surf as a function:
C:\Users\kuchin\Documents\MATLAB\surf.m
Error in surf (line 3)
surf(double(img))
EDIT
As seen in your comment in this own post, your problem is that you are overriding the surf function by another surf.m file you have. Dont name your matlab files with the same name that Matlab built functions. Go to C:\Users\kuchin\Documents\MATLAB\surf.m and name it mysurf.m. It will resolve your problem.
ORIGINAL POST
If you have a depth image (MxN) of doubles just
surf(img);
if they are uint8
surf(double(img));
Will do the trick.
Test code:
img=imread( 'coins.png' );
surf(double(img))
Outputs:

Convert just the content of a figure to an image in 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)

Smoothing matlab plot figures

I have obtained the following figure using a 120x120 matrix and the surf function.
Is there a simple way to make the lines between different colors look smoother?
First of all, surf may not be the best way to display 2D-image - if you don't actually need the height information, imagesc will work just fine. Even better, it won't show the differently colored lines between hexagons, since it's not going through the colormap at intersections.
However, regardless of your approach, a low-resolution bitmap will not be automatically transformed into a "arbitrary"-resolution vector graphics - and you may not want that, anyway, if you use the figure to allow you to inspect at which combination of (x,y) you obtained at a given value.
There are three approaches to make your image prettier - (1) segment the hexagons, and use patch to create a vector-graphics image. (2) upsample the image with imresample. (3) create a RGB image and smoothen each color separately to get softer transitions:
%# assume img is your image
nColors = length(unique(img));
%# transform the image to rgb
rgb = ind2rgb((img+fliplr(img)),jet(nColors)); %# there are much better colormaps than jet
%# filter each color
for i=1:3,rgbf(:,:,i)=imfilter(rgb(:,:,i),fspecial('gaussian',9,3),'replicate');end