MATLAB - How to avoid a jagged image? - matlab

How do I avoid a jagged image in MATLAB?
I have a 600 x 600 pixels image opened in MATLAB and do some processing on the image. However, when I save it, it looks so blurred and jagged. What should I do?
(This question is related to my previous question, MATLAB - How to plot x,y on an image and save?)
fid = fopen(datafile.txt);
A = textscan(fid,'%f%f%f'); %read data from the file
code = A{1};
xfix = A{2};
yfix = A{3};
for k=1:length(code)
imagefile=code(k);
rgb = imread([num2str(imagefile) '.jpg']);
imshow(rgb);
hold on;
x = xfix2(k);
y = yfix2(k);
plot(x,y,'-+ b'); % plot x,y on the
saveas(([num2str(imagefile) '.jpg'])) % Save the image with the same name as it open.
end
hold off

If it is just a resolution issue, perhaps using the print command (as listed below) with an explicit resolution option may fix it.
print(gcf,'-djpeg','-r600',[num2str(imagefile)])

My guess would be JPEG compression artifacts. JPEG isn't a great format for data with a lot of high frequency components. Have you tried turning the compression down? Like so:
imwrite(f.cdata,([num2str(imagefile) '.jpg']),'Quality',100);
The default for the quality parameter is only 75. That's plenty for a lot of cases, but you might need more.

Related

Computationally Fast Way to Save Matlab Figures as Image (eg PNG)

I have a program that creates a lot of plots which I want to save as fig001, fig002, .... At the moment, the only way I can do this is to either save them one by one as I go along using print() or so save them into a graphics object FIG.
Unfortunately, I have to create the plots sequentially (can't parallelise it). If I save as I go, then this takes quite a long time; if I store in FIG then do a parfor-loop over all the figures, then this is faster. However, it's still pretty slow, and it's a major bottleneck in my code.
Matlab is automatically writing a 1200x900 pixel image. In reality, it's just a graph with some (horizontal) straight lines on it. I really do not need a high image quality whatsoever; maybe reducing this would help speed things up? I can't find how to do this either.
I've had a look online, in particular at other SE questions, but I haven't been able to come up with a solution. There's various stuff about "playing around with the hardcore function". I'm a mathematician who wants a code to get some intuition for the problem; I'm not a proper programmer! As such, "play around with a function" (that might cause Matlab to crash) is rather difficult for me!
I've sorted this by using the Matlab movie function. Thank you Cecilia for your assistance!
Since your intention is to use the images in a slideshow. I would suggest making a movie and using that instead. I've run a few tests, and saving a movie is much faster than saving individual pngs. I see about a 5x speed up in my simple test.
numImages = 25;
%Saving one figure at a time
tic;
for i= 1:numImages
x = 0:0.1:2*pi;
y = i*sin(x);
plot(x, y);
fig = gcf;
print('img.png', '-dpng', '-r50'); %Downsample resolution
end
toc;
tic;
%Saving a movie
v = VideoWriter('mov.avi');
open(v);
for i = 1:numImages
x = 0:0.1:2*pi;
y = i*sin(x);
plot(x, y);
drawnow; %Force the figure to render
frame = getframe; %Convert the figure to a movie frame
writeVideo(v, frame); %Write the frame to the movie file
end
close(v);
toc;
Using writeVideo also has the advantage of never storing the whole movie in memory. Instead, as each frame is captured, it is immediately written to the file. The one downside is that because the frames need to be written in the correct sequence, you can not use a parfor
You could also consider making a movie matrix. Each element would be a frame. So to initialize the size of the matrix, you would need something like
numImages = 25;
mov(numImages) = struct('cdata',[],'colormap',[]);
Then using the parfor, you can assign all the images to your mov matrix in the correct order. After your loop is finished, you can write the movie to a file using VideoWriter. However, while generating your figures, you will need to keep your whole movie in memory, and there is an overhead associated with parfor, so it may not end up being more efficient.
If you made Matlab output a file like this, called "lines.txt" with each line describing the x1,y1 and x2,y2 of a line on your output image:
10 100 600 100
50 400 800 400
100 820 350 820
Then you could use ImageMagick to draw the lines like this:
#!/bin/bash
# Create the output image, 1200x900
convert -size 1200x900 xc:gray80 result.png
# Loop, reading one line at a time from the file "lines.txt"
while read x1 y1 x2 y2; do
echo Read line $x1,$y1 $x2,$y2
# Tell ImageMagick to draw the line on the image
convert result.png -stroke blue -strokewidth 5 -draw "line $x1,$y1 $x2,$y2" result.png
done < lines.txt
Obviously, you can draw non-horizontal lines and you could output a colour after the x,y coordinates and/or a thickness...
ImageMagick is installed on most Linux distros and is available for OSX and Windows. There are more efficient ways of plotting the lines, but this may be plenty to get you started.
Another option may be to use Gnuplot, see my other answer here.
On top of Cecilia's answer which suggests using getframe to generate a movie, I'd like to add that getframe can also be used to improve speed for saving static images. Combine it with frame2im to convert the figure into a rasterized image, and then use imwrite to save the rasterized image to a file.
frame = getframe(fig); % fig is the figure handle to save
[raster, raster_map] = frame2im(frame); % raster is the rasterized image, raster_map is the colormap
if isempty(raster_map)
imwrite(raster, fig_file);
else
imwrite(raster, raster_map, fig_file); % fig_file is the path to the image
end
In my particular case the time used to save the figures is reduced from ~60s for 19 files (using saveas) down to 7~9s using this method.
Do note that this method
Does not change the background color to white as saveas does;
Does not seem to support resolution and dpi other than that of the current figure;
Does not support saving as a vector image (obviously).

MATLAB: how to save a geoshow figure with faceAlpha?

I am trying to save a figure in Matlab R2014a in which I want to plot data over an Image. This is the code:
[Singapore, R] = geotiffread(file);
s = size(Singapore);
matrix = rand(s(1),s(2));
geoshow(Singapore(:,:,1:3), R)
hold on
geoshow(matrix, R, 'DisplayType', 'texturemap','facealpha',.2);
xlim([103.605,104.04])
ylim([1.2,1.475])
This one is the plot that works perfectly:
While when I am printing the figure
print(gcf, '-dpng', fullfile(FileF, 'test.png'))
the image is completely white
Many thanks for the image link!
I have tried your code (adapted for the `Singapore.tif' file you provided and an appropriate output file) and it works as expected on my system (Matlab 2013b, Linux 64-bit). This is the output file:
So I'm sorry to say that there's nothing wrong with your code, and it's probably something to do with the 'png' driver on windows or your particular installation. Have you tried printing to a different driver? (e.g. jpg or pdf?). Does it actually work if you do this from the figure's graphical menu, i.e. File->Save As; or via File->Export Setup->Export with appropriate properties?
The only other thing I can think of which may be confusing your system is the attempt to print a uint8 rgb image (your Singapore image) and an overlayed double grayscale image. You can see if converting your Singapore image to double solves this by changing:
geoshow(Singapore(:,:,1:3), R)
to
geoshow(mat2gray(Singapore(:,:,1:3)), R)
Might also be worth trying to plot the data manually and see if printing that works, e.g.:
[Singapore, R] = geotiffread('Singapore.tif');
SingaporeXYImage = cat(3, flipud(Singapore(:,:,1)), ...
flipud(Singapore(:,:,2)), ...
flipud(Singapore(:,:,3)));
s = size(Singapore);
matrix3D = repmat( rand(s(1),s(2)), [1,1,3]);
imagesc(R.LongitudeLimits, R.LatitudeLimits, mat2gray(SingaporeXYImage));
hold on;
imagesc(R.LongitudeLimits, R.LatitudeLimits, matrix3D, 'alphadata', .2);
hold off;
axis xy equal tight;
xlim([103.605,104.04])
ylim([1.2,1.475])
print(gcf, '-dpng', 'test.png');
As a bonus, here's how you might perform the same thing in Octave, in case you're interested (I find printed plots from Octave look much nicer, especially in terms of fonts!):
pkg load mapping;
pkg load image;
[SingaporeStruct, R] = rasterread('Singapore.tif');
SingaporeImage = cat(3, SingaporeStruct(1:3).data); % note this is a matrix of
% "doubles" in range [0,255]
SingaporeImage = mat2gray(SingaporeImage); % Convert to appropriate [0,1] range
% for "doubles" rgb images!
s = size (SingaporeImage);
matrix3D = repmat (rand (s(1), s(2)), [1, 1, 3]);
imagesc (R.bbox(:,1), R.bbox(:,2), ...
SingaporeImage .* 0.8 + matrix3D .* 0.2); % manually create
% transparency effect
axis xy equal tight
xlim([103.605,104.04])
ylim([1.2,1.475])
print (gcf, '-dpng', 'test.png');
Also, no disrespect to my colleague and the effort he / she put into his / her answer, but I will note that the other answer you received is essentially completely wrong and you should retract your marked accepted regardless of his / her claim and warnings about how rude it is to retract a marked answer. mapshow is specifically used for images using a MapCellsReference format: the boston.tif image is one such image. Your image however uses a GeographicCellsReference format. mapshow is used for the former, geoshow is used for the latter; geoshow would have failed for boston.tif, in the same way mapshow fails for Singapore.tif. It should have been obvious your image is a "Geo" variant because your line geoshow(Singapore(:,:,1:3), R) worked without throwing an error. Therefore the suggestion to use mapshow is not the correct answer to your question, and is misleading. Not to mention it is completely irrelevant to your actual question about why the print command does not produce the expected result from its figure handle, which should in theory have nothing to do with how the figure was produced in the first place. I would have no qualms about retracting your "accepted" mark from it. Not least because this site functions as a reference for many other viewers; it does not make sense to direct users to the wrong answer just because you got bullied into accepting it.
As suggested by mathworks, using mapshow should solve your problem. The following works for me:
[boston, R] = geotiffread('boston.tif');
figure
mapshow(boston, R);
axis image off
S = size(boston);
matrix=rand(S(1),S(2));
hold on
mapshow(matrix, R,'DisplayType','texturemap','facealpha',0.2);
print(gcf, '-dpng','test.png') ;

Matlab remove noise

I want to remove noise from an image. The image i've been given is a .mat file but it's very complicated because when i load the mat file no image can be seen, then i use imwrite to make it jpg
imwrite(destroyedImg, 'fr.jpg');
But when i use imshow I get only colorful dots in white background!
Is there a way to find out how to clear the noise from this picture?!
I'm not allowed to use the internal functions but to build one myself! But i cannot figure out the kind of noise and then remove it! i also have to return the "clear image" in RGB format and not grayscale!
here is some of my code
clear all; close all;
load('image_destroyed.mat');
imwrite(image_destroyed, 'fraou.jpg');
img = imread('fraou.jpg');
subplot(2,2,1), imshow(img)
title('Fraou');
H = fspecial('average',[3 3]);
average = imfilter(img, H, 'replicate');
subplot(2,2,2), imshow(average);
title('average');H = fspecial('gaussian',[5 5]);
average = imfilter(img, H, 'replicate');
subplot(2,2,3); imshow(average);title('gaussian');
H = wiener2(img,[5 5]);
subplot(2,2,4); imshow(H)
title('wiener 5x5');
DO NOT USE imwrite to 'jpg' to get your image - this only introduces artifacts.
Your input image is of type double with values exceeding the range [0..1] and thus all the confusion.
load('image_destroyed.mat');
image_destroyed = image_destroyed / 255.0; % back to [0..1] range
imshow( image_destroyed ); % should be meaningful now.
The following code, presuming that image_destroyed is a variable contained in image_destroyed.mat, is probably what is causing the issue:
load('image_destroyed.mat');
imwrite(image_destroyed, 'fraou.jpg');
img = imread('fraou.jpg');
At best this is equivalent to img = image_destroyed;, and therefore is unnecessary. It is possible (and given your strange results, quite likely) that this write/read process is actually introducing further degradation into your image, through inappropriate scaling or clipping, compression, etc.
For MATLAB image processing functions, when using doubles, you should make sure your data is scaled between 0 and 1.

MATLAB's 'saveas' saves my figure as squares. But I want them to be more rectangular

I am using MATLABs 'saveas' to save off one of my figures as a .png or .jpg or whatever.
So I just do:
y = randn(1,00);
plot(y); grid on;
saveas(gcf,'y','png');
Now the problem is that the png or final picture comes out as a perfect square - even if I manually stretch the figure before I use the 'saveas' command.
How do I get it so save something more rectangular?
Thanks!
Here's a short sample taken from a mathworks discussion
figure('units','pix','pos',[100 100 200 400]) % create a 200x400 image
>> imagesc(rand(10,10)) % put some random data in it
>> print(gcf,'-dbitmap','test.bmp') % save to bmp
Using print like this saves an image in the desired resolution.

Matlab Imread resizes tif file

so I'm using the imread function in matlab and when I save the TIFF file and open it in photoshop, it has a white border and I can't understand why. I want to maintain its resolution as a 512 by 512 image. Any ideas why? And how I can fix that?
Here's a sample code:
B = imread('W_noise1.tif');
for n = 1:5,
B = medfilt2(B);
end
B = filter2(fspecial('average',3),B)/255;
imshow(B)
Are you sure it's an issue with imread? I'd be surprised if it is.
See this link about medfilt2 where it explains that "medfilt2 pads the image with 0s on the edges, so the median values for the points within [m n]/2 of the edges might appear distorted."
EDIT: I tried to replicate your problem. This is an issue with print where it puts a white frame around the image after you save it. This functionality, print is made for printing plots. If you want to save the image, you should use imwrite.