Failing to print current figure - animation

Here is an attempt of creating a simple animation by generating frames as a sequence of figures, saved in .png format1:
clc
clear
close all
% don't display plot : produces error.
%set(0, 'defaultfigurevisible', 'off');
% number of frames.
N = 2;
% generate data sets.
x = linspace(0, 6 * pi, 1000);
y = sin(x);
% run animation.
for i = 1 : N
% create figure.
clf
% hold on % produces error.
plot(x, y, x(i), y(i), 'ro')
% plot(x(i), y(i), 'ro')
grid on
axis tight
title( sprintf( 'Sine Wave at (%f, %f)', x(i), y(i) ) )
xlabel('x')
ylabel('y')
drawnow
% create frame name: fr00001.png, etc.
framename = sprintf('output/fr%05d.png', i);
% save current figure in file: output.
print(framename);
end
However, the only thing I get is:
Mesa warning: couldn't open dxtn.dll, software DXTn compression/decompression unavailableGL2PS error: Incorrect viewport (x=0, y=240883432, width=0, height=240885832)error: gl2ps_renderer::draw: gl2psBeginPage returned GL2PS_ERRORerror: called fromopengl_print at line 172 column 7print at line 519 column 14sinewave at line 48 column 3
Any recommendation would be appreciated.
Note: the commented lines are intentionally left.
1. Later on to be stitched into a movie in .avi format with the help of an encoder.
Executed on Octave-4.2.1 on Windows 10

What helps1 is to use print() with a graphics handle to the figure and to define the file names (.png) including the absolute path of the directory in which they will be stored. Noticing that sub-directory is denoted with \ rather than /, moreover, it needs an additional \ escape character to be valid. Then the following code:
N = 1000;
x = linspace(0, 6*pi, N);
y = sin(x);
abspath = 'D:\\...\\Project\\output\\';
fh = figure();
for i = 1 : N
clf
hold on
plot(x, y);
plot(x(i), y(i), 'ro')
grid on
axis tight
title( sprintf( 'Sine Wave at (%f, %f)', x(i), y(i) ) )
xlabel('x')
ylabel('y')
drawnow
framename = sprintf('%sfr%04d.png', abspath, i);
print(fh, framename);
end
produces 1000 frames, which when2 stitched together give:
1. It still crashes unexpectedly after few hundred plots.
2. The first 100 .png files are converted to a .gif with the use of imagemagick's command: magick convert -delay 10 -loop 0 *png output.gif.

Related

How to output the Cascading images or stacking images

See above image, if there are 24 pictures, how to use MATLAB to achieve this output effect. This kind of graph often appears in papers. I define a function, but there is one line of code that cannot be implemented.
function h = op(file_path, pad,m,n)
img_path_list = dir(strcat(file_path,'*.jpg'));
num = length(img_path_list);%
% [m,n]=size(image);
fw=n+(num-1)*pad;
fh=m+(num-1)*pad;
h=figure('position',[0,0,fw+pad,fh+pad]);
for j = 1:num
image_name = img_path_list(j).name;
image = imread(strcat(file_path,image_name));
hold on
pd=(j-1)*pad;
rpl=fw-n-pd;
rpb=fh-m-pd;
%How to specify the location of the output on the image canvas
% set('Position',[rpl rpb n m]);
% axes('position',[rpl rpb n m]);
imshow (image);
end
% h=gcf;
You can use the Xdata, and Ydata in imshow() function to set the axis position of each image to display them on the same axis stacked one upon other shifted to a fixed units for each image.
The code illustrating the procedure is given below.
close all
% read the images in metrices
i1 = imread('onion.png');
i2 = imread('cameraman.tif');
i3 = imread('peppers.png');
i4 = imread('moon.tif');
i5 = imread('trees.tif');
i6 = imread('greens.jpg');
% create a cell array of the images
imgs = {i1, i2, i3, i4, i5, i6};
% variable to shift the position of each image
shift = 0;
% looping from 1 to length of the cell arrays
for i = 1:numel(imgs)
% display image, shifting the position to 2 units
% for each image on the same axis
imshow(imgs{i}, 'XData', [1+shift 10+shift], ...
'YData', [1+shift 10+shift],'InitialMagnification', 400)
% hold on the axis
hold on
% increment the shift value
shift = shift + 2;
end
% set the axis limits
xlim([1 10+shift])
ylim([1 10+shift])
% hide the axis lines
axis off
Sample Output

Matlab - Scale Colorbar of Image

How can I scale the colorbar axis of a false color image?
I read this post,and copied the code but it seems not to work correctly:
MATLAB Colorbar - Same colors, scaled values
Please see the two images below. In the first (without the scaling) the coloraxis goes
[1 2 3 4 5 6]*10^4
In the second image, it goes
[0.005 0.01 0.015 0.02 0.025]
The correct scaling (with C = 100000) would be
[0.1 0.2 0.3 0.4 0.5 0.6]
Without scaling
Wrong scaling
I want that the coloraxis is scaled by 1/C and I can freely choose C, so that when the pixel value = 10^4 and C=10^6 the scale should show 10^-2.
The reason why I multiply my image first by C is to get more decimals places, because all values below 1 will be displayed as zero without the C scaling.
When I run the code I get yticks as a workspace variable with the following values:
[500 1000 1500 2000 2500]
My code:
RGB = imread('IMG_0043.tif');% Read Image
info = imfinfo('IMG_0043.CR2'); % get Metadata
C = 1000000; % Constant to adjust image
x = info.DigitalCamera; % get EXIF
t = getfield(x, 'ExposureTime');% save ExposureTime
f = getfield(x, 'FNumber'); % save FNumber
S = getfield(x, 'ISOSpeedRatings');% save ISOSpeedRatings
date = getfield(x,'DateTimeOriginal');
I = rgb2gray(RGB); % convert Image to greyscale
K = 480; % Kamerakonstante(muss experimentel eavaluiert werden)
% N_s = K*(t*S)/power(f,2))*L
L = power(f,2)/(K*t*S)*C; %
J = immultiply(I,L); % multiply each value with constant , so the Image is Calibrated to cd/m^2
hFig = figure('Name','False Color Luminance Map', 'ToolBar','none','MenuBar','none');
% Create/initialize default colormap of jet.
cmap = jet(16); % or 256, 64, 32 or whatever.
% Now make lowest values show up as black.
cmap(1,:) = 0;
% Now make highest values show up as white.
cmap(end,:) = 1;
imshow(J,'Colormap',cmap) % show Image in false color
colorbar % add colorbar
h = colorbar; % define colorbar as variable
y_Scl = (1/C);
yticks = get(gca,'YTick');
set(h,'YTickLabel',sprintfc('%g', [yticks.*y_Scl]))
ylabel(h, 'cd/m^2')% add unit label
title(date); % Show date in image
caxis auto % set axis to auto
datacursormode on % enable datacursor
img = getframe(gcf);
nowstr = datestr(now, 'yyyy-mm-dd_HH_MM_SS');
folder = 'C:\Users\Taiko\Desktop\FalseColor\';
ImageFiles = dir( fullfile(folder, '*.jpg') );
if isempty(ImageFiles)
next_idx = 1;
else
lastfile = ImageFiles(end).name;
[~, basename, ~] = fileparts(lastfile);
file_number_str = regexp('(?<=.*_)\d+$', basename, 'match' );
last_idx = str2double(file_number_str);
next_idx = last_idx + 1;
end
newfilename = fullfile( folder, sprintf('%s_%04d.jpg', nowstr, next_idx) );
imwrite(img.cdata, newfilename);
Problems:
1) You are getting YTick of the figure (gca) but not the color bar. That would give you the "pixel" coordinates of the graph, instead of the actual values. Use yticks = get(h,'YTick');.
2) caxis auto Should come before overwriting YTicks (and after enabling the color bar); otherwise the scale and ticks will mismatch.
3) Do you mean C = 100000?
Result:

Matlab image - how to count number of white pixels

The matlab code below splits up an image into a number of smaller images. It then counts the number of black pixels in the image and displays it as a percentage of the total number of pixels in the picture. example of image
My question is - instead of counting the black pixels and displaying the percentage, how can I count the white pixels? (essentially the opposite!)
Thanks
% Divide an image up into blocks (non-overlapping tiles).
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
workspace; % Make sure the workspace panel is showing.
fontSize = 20;
% Read the image from disk.
rgbImage = imread('edge-diff.jpg');
% Display image full screen.
imshow(rgbImage);
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
drawnow;
% Get the dimensions of the image. numberOfColorBands should be = 3.
[rows columns numberOfColorBands] = size(rgbImage)
%==========================================================================
% The first way to divide an image up into blocks is by using mat2cell().
blockSizeR = 400; % Rows in block.
blockSizeC = 400; % Columns in block.
% Figure out the size of each block in rows.
% Most will be blockSizeR but there may be a remainder amount of less than that.
wholeBlockRows = floor(rows / blockSizeR);
blockVectorR = [blockSizeR * ones(1, wholeBlockRows), rem(rows, blockSizeR)];
% Figure out the size of each block in columns.
wholeBlockCols = floor(columns / blockSizeC);
blockVectorC = [blockSizeC * ones(1, wholeBlockCols), rem(columns, blockSizeC)];
% Create the cell array, ca.
% Each cell (except for the remainder cells at the end of the image)
% in the array contains a blockSizeR by blockSizeC by 3 color array.
% This line is where the image is actually divided up into blocks.
if numberOfColorBands > 1
% It's a color image.
ca = mat2cell(rgbImage, blockVectorR, blockVectorC, numberOfColorBands);
else
ca = mat2cell(rgbImage, blockVectorR, blockVectorC);
end
percentBlack = cellfun(#(x)sum(sum(all(x == 0, 3))) / (numel(x) / size(x,3)), ca);
% Now display all the blocks.
plotIndex = 1;
numPlotsR = size(ca, 1);
numPlotsC = size(ca, 2);
for r = 1 : numPlotsR
for c = 1 : numPlotsC
fprintf('plotindex = %d, c=%d, r=%d\n', plotIndex, c, r);
% Specify the location for display of the image.
subplot(numPlotsR, numPlotsC, plotIndex);
ax2 = subplot(numPlotsR, numPlotsC, plotIndex);
% Extract the numerical array out of the cell
% just for tutorial purposes.
rgbBlock = ca{r,c};
imshow(rgbBlock); % Could call imshow(ca{r,c}) if you wanted to.
[rowsB columnsB numberOfColorBandsB] = size(rgbBlock);
set(ax2, 'box', 'on', 'Visible', 'on', 'xtick', [], 'ytick', []);
% Make the caption the block number.
averageBlack = percentBlack(r,c);
disp(numPlotsR);
disp(averageBlack);
caption = sprintf('Frame #%d of %d\n Percentage information content %0.2f', ...
plotIndex, numPlotsR*numPlotsC, averageBlack*100);
title(caption);
drawnow;
% Increment the subplot to the next location.
plotIndex = plotIndex + 1;
end
end
This line:
percentBlack = cellfun(#(x)sum(sum(all(x == 0, 3))) / (numel(x) / size(x,3)), ca);
specifically the part that says all(x == 0, 3) means "all color channels have value 0". You want to change it to "all color channels have value 1 (or 255 depends on your image)"
So basically, change that 0 to 1 or 255, deependinf if your image is unit8 or double

How to reconstruct an image using rgb values of all pixels in Matlab

I am trying to read an image using imread then, save the RGB values of all of the pixels in an array. And finally, be able to recreate this image using only the RGB values.
This is the for loop that saves all of the RGB values of each pixel.
A=imread('image.jpg');
N=2500; %the image dimensions are 50x50
i=1;
rgbValues = zeros(N, 3);
for x = 1:50
for y = 1:50
rgbValues(i,:) = A(x,y,:);
i=i+1;
end
end
Now, how am I able to recreate this image if I have all of the rgb values saved.
A direct way to do this is:
ny = 50;
nx = 50;
recreatedImage = zeros(ny,nx,3, 'uint8');
for ind = 1:3
recreatedImage(:,:, ind) = ( reshape(rgbValues(:, ind), nx, ny))';
end
As Natan indicated, reshape will work also but you have to do this:
recreatedImage=reshape(rgbValues,[ny,nx,3]);
Which is, unfortunately, transposed so you will need to work it to get it rotated back up.
You might consider swapping your x and y values in your for loop so you iterate over all y and then all x values---because this is how MATLAB stores the data and you can change the above code to:
for ind = 1:3
recreatedImage(:,:, ind) = ( reshape(rgbValues(:, ind), ny, nx));
end
(edit) and then the direct reshape works as well:
rgbValuesBacktoShape=reshape(rgbValues,[50,50,3]);

How to limit the raster processing extent using a spatial mask?

I am trying to limit raster processing in MATLAB to include only areas within a shapefile boundary, similar to how ArcGIS Spatial Analyst functions use a mask. Here is some (reproducible) sample data I am working with:
A 4-band NAIP image (WARNING 169MB download)
A shapefile of study area boundaries (A zipped shapefile on File Dropper)
Here is a MATLAB script I use to calculate NDVI:
file = 'C:\path\to\doi1m2011_41111h4nw_usda.tif';
[I R] = geotiffread(file);
outputdir = 'C:\output\'
% Calculate NDVI
NIR = im2single(I(:,:,4));
red = im2single(I(:,:,1));
ndvi = (NIR - red) ./ (NIR + red);
double(ndvi);
imshow(ndvi,'DisplayRange',[-1 1]);
% Stretch to 0 - 255 and convert to 8-bit unsigned integer
ndvi = floor((ndvi + 1) * 128); % [-1 1] -> [0 256]
ndvi(ndvi < 0) = 0; % not really necessary, just in case & for symmetry
ndvi(ndvi > 255) = 255; % in case the original value was exactly 1
ndvi = uint8(ndvi); % change data type from double to uint8
% Write NDVI to .tif file (optional)
tiffdata = geotiffinfo(file);
outfilename = [outputdir 'ndvi_' 'temp' '.tif'];
geotiffwrite(outfilename, ndvi, R, 'GeoKeyDirectoryTag', tiffdata.GeoTIFFTags.GeoKeyDirectoryTag)
The following image illustrates what I would like to accomplish using MATLAB. For this example, I used the ArcGIS raster calculator (Float(Band4-Band1)/Float(Band4+Band1)) to produce the NDVI on the right. I also specified the study area shapefile as a mask in the environment settings.
Question:
How can I limit the raster processing extent in MATLAB using a polygon shapefile as a spatial mask to replicate the results shown in the figure?
What I have unsuccessfully tried:
roipoly and poly2mask, although I cannot seem to apply these functions properly (taking into account these are spatial data) to produce the desired effects.
EDIT:
I tried the following to convert the shapefile to a mask, without success. Not sure where I am going wrong here...
s = 'C:\path\to\studyArea.shp'
shp = shaperead(s)
lat = [shp.X];
lon = [shp.Y];
x = shp.BoundingBox(2) - shp.BoundingBox(1)
y = shp.BoundingBox(3) - shp.BoundingBox(1)
x = poly2mask(lat,lon, x, y)
Error messages:
Error using poly2mask
Expected input number 1, X, to be finite.
Error in poly2mask (line 49)
validateattributes(x,{'double'},{'real','vector','finite'},mfilename,'X',1);
Error in createMask (line 13)
x = poly2mask(lat,lon, x, y)
You can read the region of interest by:
roi = shaperead('study_area_shapefile/studyArea.shp');
Chop the trailing NaN:
rx = roi.X(1:end-1);
ry = roi.Y(1:end-1);
If you have several polygons in your shapefile, they are seperated by NaNs and you have to treat them seperately.
Then use the worldToIntrinsic-method from your spatial reference of the sat-image to convert the polygon-points into image-coordinates:
[ix, iy] = R.worldToIntrinsic(rx,ry);
This assumes both coordinate systems are the same.
Then you can go and make your mask by:
mask = poly2mask(ix,iy,R.RasterSize(1),R.RasterSize(2));
You can use the mask on your original multilayer image before making any calculation by:
I(repmat(~mask,[1,1,4])) = nan;
Or use it on a single layer (i.e. red) by:
red(~mask) = nan;
If the regions are very small, it could be beneficial (for memory and computation power) to convert a masked image to a sparse matrix. I have not tried if that makes any speed-difference.
red(~mask) = 0;
sred = sparse(double(red));
Unfortunatly, sparse matrizes are only possible with doubles, so your uint8 needs prior to be converted.
Generally you should crop the ROI out of the image. Look in the objects "roi" and "R" to find useful parameters and methods. I haven't done it here.
Finally my version of your script, with some slight other changes:
file = 'doi1m2011_41111h4nw_usda.tif';
[I R] = geotiffread(file);
outputdir = '';
% Read Region of Interest
roi = shaperead('study_area_shapefile/studyArea.shp');
% Remove trailing nan from shapefile
rx = roi.X(1:end-1);
ry = roi.Y(1:end-1);
% convert to image coordinates
[ix, iy] = R.worldToIntrinsic(rx,ry);
% make the mask
mask = poly2mask(ix,iy,R.RasterSize(1),R.RasterSize(2));
% mask sat-image
I(repmat(~mask,[1,1,4])) = 0;
% convert to sparse matrizes
NIR = sparse(double(I(:,:,4)));
red = sparse(double(I(:,:,1)));
% Calculate NDVI
ndvi = (NIR - red) ./ (NIR + red);
% convert back to full matrizes
ndvi = full(ndvi);
imshow(ndvi,'DisplayRange',[-1 1]);
% Stretch to 0 - 255 and convert to 8-bit unsigned integer
ndvi = (ndvi + 1) / 2 * 255; % [-1 1] -> [0 255]
ndvi = uint8(ndvi); % change and round data type from double to uint8
% Write NDVI to .tif file (optional)
tiffdata = geotiffinfo(file);
outfilename = [outputdir 'ndvi_' 'temp' '.tif'];
geotiffwrite(outfilename, ndvi, R, 'GeoKeyDirectoryTag', tiffdata.GeoTIFFTags.GeoKeyDirectoryTag);
mapshow(outfilename);
There are three steps here, for which I will create 3 functions:
Compute the NDVI for the complete input image: ndvi = comp_ndvi(nir, red)
Compute the mask from the shapefile: mask = comp_mask(shape)
Combine the NDVI and the mask: output = combine_ndvi_mask(ndvi, mask)
You have the code for comp_ndvi() in your question. The code for combine_ndvi_mask() depends on what you want to do to the masked areas; if you want to make them white, it might look like:
function output = combine_ndvi_mask(ndvi, mask)
output = ndvi;
output(~mask) = 255;
end
In comp_mask() you will want to use poly2mask() to convert the polygon vertices into the raster mask. In order to help here I need to know what you've got already. Have you loaded the vertices into MATLAB? What have you tried with poly2mask?

Resources