How to save figures of 4D matrix in a subfolders in matlab - matlab

I have a 4D matrix with a size of 3x600x600x28 and want to save all the images in a 3D matrix (600X600x28) which contains 28 images in subfolders that correspond with the first index of the matrix. It means I need 3 main folders which each of them contains 28 images.
The question is that how can I save the first 28 images in the folder which is named 1 and the second 28 images in folder 2 and so on...
I stuck at the last line of the code saveas...
Here is my try:
clc;
clear;
n=3;
A = randi([1 255],n,600,600,28);
for i=1:n
mkdir('Output_image',num2str(i));
for j=1:28
h=figure;
p = pcolor(A(i,:,:,j));
p.EdgeColor='none';
set(gca,'visible','off')
colormap('jet');
axis equal;
title 'Von Mises Stress';
saveas(h,sprintf('Output_image/%i/FIG%d.jpg',j));
end
end

Related

Get pixel values in RGB images using PixelList in MATLAB

I am trying to get pixel intensity values from regions of interest in RGB images.
I segmented the image and saved the regions of interest (ROI) using regionprops 'PixelList' in MATLAB, as shown below:
In this example I am using "onion.png" image built in MATLAB. (But in reality I have hundreds of images, and each of them have several ROIs hence why I'm saving the ROIs separately.)
%SEGMENTATION PROGRAM:
a=imread('C:\Program Files\MATLAB\MATLAB Production Server\R2015a\toolbox\images\imdata\onion.png');warning('off', 'Images:initSize:adjustingMag');
figure; imshow(a,[]);
nrows = size(a,1);ncols = size(a,2);
zr=ones(nrows,ncols); %matrix of ones
r=a(:,:,1);g=a(:,:,2);b=a(:,:,3); %get RGB values
rr=double(r);gg=double(g);bb=double(b);% convert to double to avoid uint8 sums
bgd=(rr+bb)./(2*gg); %calculation RGB ratio of background
zr1=bgd>1.15; %matrix containing background as 1 and ROI as 0
% remake binary image for holes command which requires white object to fill % (this step is not relevant for this example, but it is for my data)
zr2=zr1<0.5;
zr3=imfill(zr2, 'holes');
figure;imshow(zr3); pause;
roi=regionprops(zr3,'Centroid','PixelList','Area');
ar=[roi.Area];
% find sort order , largest first
[as, ia]=sort(ar(1,:),'descend');
for w=1:length(roi); xy(w,:)=roi(w).Centroid;end
% use sort index to put cenrtoid list in same order
xy1=xy(ia,:);
%and pixel id list
for w=1:length(roi)
roi2(w).PixelList=roi(ia(w)).PixelList;
end
%extract centriod positions as two colums
%SAVE PIXEL LIST FOR EACH ROI IN A SEPARATE FILE
for ww=1:w;
k=roi2(ww).PixelList;
save('onion_PL','k');
end
How do I use this pixel list to get the intensity values in the original image? More specifically, I need to get the ratio of pixels in Green channel over Red ("grr=rdivide(gg,rr);"), but only in the region of interest labeled with PixelList. Here's my code so far:
%PL is the PixelList output we got above.
a=imread('C:\Program Files\MATLAB\MATLAB Production Server\R2015a\toolbox\images\imdata\onion.png');warning('off', 'Images:initSize:adjustingMag');
PL=dir(['*PL.mat']); %load file PixelList files. "dir" is a variable with directory path containing the pixelist files. In this example, we saved "onion_PL.mat"
for m=1:length(PL);
load(PL(m).name);
ex=[]; %empty matrix to hold the extracted values
for mm=1:length(k);
%INSERT ANSWER HERE
end
This next bit is wrong because it's based on the entire image ("a"), but it contains the calculations that I would like to perform in the ROIs
figure; imshow(a,[]);
pause;
nrows = size(a,1);ncols = size(a,2);
zr=ones(nrows,ncols); %matrix of ones
r=a(:,:,1);g=a(:,:,2);b=a(:,:,3); %get RGB values
rr=double(r);gg=double(g);bb=double(b);% convert to double to avoid uint8 sums
grr=rdivide(gg,rr);
I am brand new to MATLAB, so my code is not the greatest... Any suggestions will be greatly appreciated. Thank you in advance!
The loop you are looking for seems simple:
grr = zeros(nrows, ncols); % Initialize grr with zeros.
for mm = 1:length(k)
x = k(mm, 1); % Get the X (column) coordinate.
y = k(mm, 2); % Get the Y (row) coordinate.
grr(y, x) = gg(y, x) / rr(y, x);
end
A more efficient solution is using sub2ind for converting the x,y coordinates to linear indices:
% Convert k to linear indices.
kInd = sub2ind([nrows, ncols], k(:,2), k(:,1));
% Update only the indices in the PixelList.
grr(kInd) = rdivide(gg(kInd), rr(kInd));
In your given code sample there are 5 PixelLists.
I don't know how do you want to "arrange" the result.
In my code sample, I am saving the 5 results to 5 mat files.
Here is an executable code sample:
close all
%SEGMENTATION PROGRAM:
a=imread('onion.png');warning('off', 'Images:initSize:adjustingMag');
figure; imshow(a,[]);
nrows = size(a,1);ncols = size(a,2);
zr=ones(nrows,ncols); %matrix of ones
r=a(:,:,1);g=a(:,:,2);b=a(:,:,3); %get RGB values
rr=double(r);gg=double(g);bb=double(b);% convert to double to avoid uint8 sums
bgd=(rr+bb)./(2*gg); %calculation RGB ratio of background
zr1=bgd>1.15; %matrix containing background as 1 and ROI as 0
% remake binary image for holes command which requires white object to fill % (this step is not relevant for this example, but it is for my data)
zr2=zr1<0.5;
zr3=imfill(zr2, 'holes');
figure;imshow(zr3); %pause;
roi=regionprops(zr3,'Centroid','PixelList','Area');
ar=[roi.Area];
% find sort order , largest first
[as, ia]=sort(ar(1,:),'descend');
for w=1:length(roi); xy(w,:)=roi(w).Centroid;end
% use sort index to put cenrtoid list in same order
xy1=xy(ia,:);
%and pixel id list
for w=1:length(roi)
roi2(w).PixelList=roi(ia(w)).PixelList;
end
%extract centroid positions as two columns
%SAVE PIXEL LIST FOR EACH ROI IN A SEPARATE FILE
for ww=1:w
k=roi2(ww).PixelList;
%save('onion_PL', 'k');
save(['onion', num2str(ww), '_PL'], 'k'); % Store in multiple files - onion1_PL.mat, onion2_PL.mat, ... onion5_PL.mat
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear % Use clear for testing - the variables are going to be read from the mat file.
%PL is the PixelList output we got above.
a=imread('onion.png');warning('off', 'Images:initSize:adjustingMag');
nrows = size(a,1);ncols = size(a,2);
zr=ones(nrows,ncols); %matrix of ones
r=a(:,:,1);g=a(:,:,2);b=a(:,:,3); %get RGB values
rr=double(r);gg=double(g);bb=double(b);% convert to double to avoid uint8 sums
grr=rdivide(gg,rr);
PL=dir('*PL.mat'); %load file PixelList files. "dir" is a variable with directory path containing the pixelist files. In this example, we saved "onion_PL.mat"
for m = 1:length(PL)
load(PL(m).name);
ex=[]; %empty matrix to hold the extracted values
%for mm=1:length(k)
%INSERT ANSWER HERE
grr = zeros(nrows, ncols); % Initialize grr with zeros.
for mm = 1:length(k)
x = k(mm, 1); % Get the X (column) coordinate.
y = k(mm, 2); % Get the Y (row) coordinate.
grr(y, x) = gg(y, x) / rr(y, x);
end
% Instead of using a loop, it's more efficient to use sub2ind
if false
% Convert k to linear indices.
kInd = sub2ind([nrows, ncols], k(:,2), k(:,1));
% Update only the indices in the PixelList.
grr(kInd) = rdivide(gg(kInd), rr(kInd));
end
figure;imshow(grr);title(['grr of m=', num2str(m)]) % Show grr for testing.
save(['grr', num2str(m)], 'grr'); % Save grr for testing.
imwrite(imadjust(grr, stretchlim(grr)), ['grr', num2str(m), '.png']); % Store grr as image for testing
end
First two grr matrices as images (used for testing):
grr1.png:
grr2.png:

How to separately subplot a X*Y*Z (3D) matrix matlab?

I'd like to create 4 subplots each containing 16 figures. Each figure is one dimension of the matrix GW. I.e. GW(:,:,1) is the first image.
Here is my for loop for the first 16 images in first subplot. How should I modify the for loop to get 3 more subplots?
The first subplot should contain first 16 images, second subplot should contain second 16 images and so on. With the following loop I'm getting first 16 images for all the four subplots.
for i=1:4
figure(i);
hold on;
for jj = 1:16
subplot (4,4,j)
imshow (GW(:,:,j));
end
end
You just need to modify how you access the 3rd dimension of GW. Try this:
num_figures = 4; % because I dont like magic numbers in the code
subplots_per_figure = 16; % same here
for i=1:num_figures
figure(i);
hold on;
for j = 1:subplots_per_figure
subplot (4,4,j)
imshow (GW(:,:,j+(i-1)*subplots_per_figure));
end
end

How to reorientation as axial axis of raw image from brainweb

I have a raw image with the information such as
image dimensions: zspace yspace xspace
dimension name length step start
-------------- ------ ---- -----
zspace 181 1 -72
yspace 217 1 -126
xspace 181 1 -90
should be interpreted as follows:
the file scans the 3D image volume such that the 'X' coordinate changes fastest, and the 'Z' changes slowest.
the image sizes along the X-Y-Z axes are 181x217x181 voxels (pixels).
the voxel sizes along the X-Y-Z axes are 1x1x1 mm.
One (unsigned) byte is used for each voxel, and the data is scaled such that it will use the entire 0...255 range of values.
Currently, I am using below code to read that raw file. It can be read the raw image and display as right figure. However, it does not look like my expected result where image is reorientation as axial axis.
Could you help me solving it by Matlab code?
filepath=strcat('t1_icbm_normal_1mm_pn5_rf20.rawb');
fid = fopen(filepath,'r');
rima=zeros(dim(1:3));
for z=1:dim(3),
rima(:,:,z) = fread(fid,dim(1:2),'uchar');
end;
fclose(fid);
imshow(rima(:,:,91),[]); %% Show slice 91th
The reference link is http://brainweb.bic.mni.mcgill.ca/about_data_formats.html .
The input file can be downloaded from here or brainweb
The reason why is because when MATLAB reads in data, it places the data in column major order. This means that the data you read in via rows get placed in columns. Therefore, this has the appearance that your image gets rotated 90 degrees and reflected.
One easy solution would be to take your matrix and transpose each slice individually. A simple call to permute should do the trick:
rima = permute(rima, [2 1 3]);
The above code swaps the second and first dimensions over each slice of your matrix, effectively performing a transpose of each slice independently. I've also noticed that when you do this, there is a reflection across the horizontal axis. Make a call to flipdim to fix this:
rima = flipdim(permute(rima, [2 1 3]), 1);
To reproduce, I've downloaded the file and ran the code on my computer. I show the 91th slice before and after I permute and flipdim:
filepath=strcat('t1_icbm_normal_1mm_pn5_rf20.rawb');
fid = fopen(filepath,'r');
dim = [181 217 281]; %// Added for code to run
rima=zeros(dim(1:3));
for z=1:dim(3),
rima(:,:,z) = fread(fid,dim(1:2),'uchar');
end;
fclose(fid);
imshow(rima(:,:,91),[]); %% Show slice 91th
%// New - Permute dimensions and flip rows
rima = flipdim(permute(rima, [2 1 3]), 1);
figure;
imshow(rima(:,:,91),[]); %%// Show corrected slice
Here's what we get for before and after:

Resampling Matrix and restoring in one single Matrix

I am new to this forum, so please bear with me.
I have been working on this Matlab problem for a while now:
I have a digital elevation model (DEM) new_sub(x,y) in tif format. So it is a x-by-y matrix containing heights (z). I wish to resample parts of this DEM in different resolutions and restore this in another matrix. So far I have been working with for loops to change the resolution of different areas of the DEM and then wrote the results to an xyz-file:
x y z
1 1 123
1 2 233
1 3 231
2 1 235
2 2 531
2 3 452
and so forth.
Here is the code:
xmax = size(new_sub,2);
ymax = size(new_sub,1);
for k=1:200 % y
for l=1:xmax % x
fprintf(fid, '%d %d %d \n',l,xmax+1-k,new_sub(k,l));
end
end
% 1:4
for k=200/2+1:size(new_sub,1)/2
for l=1:size(new_sub,2)/2
fprintf(fid, '%d %d %d \n',l*2,ymax+2-k*2,new_sub(k*2,l*2));
end
end
This does work, but seems to be rather complicated. Moreover, it does not allow me to store the resampled areas in a single matrix within Matlab.
Is there a more efficient way of resampling certain areas of a Matrix with different resolutions, writing them into a new Matrix containg all resampled areas and then writing it to a file? I was looking into repmap, but could not think of a clever way of using it!
Your help is much appreciated!
THeo
To re-sample a matrix in Matlab:
For example matrix M:
M = [1 2 3 4 5;
6 7 8 9 10;
11 12 13 14 15;
16 17 18 19 20;
21 22 23 24 25];
If we wanted to sample on every nth pixel, it is as simple as this:
m = M(1:n:end, 1:n:end)
So for n=2
m = 1 3 5
11 13 15
21 23 25
I suggest you read up on indexing in matlab and also on using the colon operator to create vectors in matlab
Now in order to get in the "x y z" format you mentioned, first use meshgrid to generate matrices of X and Y coordinates.
[X, Y] = meshgrid(1:n:size(M,1), 1:n:size(M,2))
notice I use n to downsample X and Y. Now you just need to flatten the three matrices and combine them:
final = [X(:), Y(:), m(:)]
Finally to save as a file I suggest you type help save or help dlmwrite in the Matlab command promt and use either of those functions to save final
To me the easiest way to do looks like using imresize. You can treat your elevation map as an image I. Then you can cut sections out by indexing and rescaling as follows:
I = imread('my.tiff'); % read
section = I(1:200, :); % cut the first 200 rows and all columns
sectionResized = imresize(section, [numrows numcols]) % resample
imwrite(sectionResized, 'mynew.tiff'); % save

Loop through a 3d vector in Matlab

I've a 3D vector holding images in Matlab, its 480x640x1400. I want to loop through the 1400 images. For I want to get the median of the first 10 images (from 1-->10) and save it as a one 480x640 image then get the images from 2-->11 and get the median and save it as another image and so on (3-->12)....
So for example:
images is the 3D vector holding images with size 480x640x1400
images2 is the required 3D vector holding the median of the images with size 480x640x1400.
This is the script I'm using:
l=dir('*.mat');
filenames={l.name}';
nfiles=length(filenames)
idx=1;
strtidx=1;
endidx=nfiles;
step=1;
waitbar(0);
for i=strtidx:step:1
tmp = load(filenames{i},'images');
idx=1;
for j=strtidx:step:1000
for k=j:step:j+9
tmp2(k)=tmp(:,:,k);
end
mm=median(tmp2,3);
images2(j)=mm;
end
save(filenames{i}, 'images2', '-append');
waitbar(i/nfiles);
close all;
end
Assuming you have a matrix with the dimensions you described called Images. Firstly it could be a normal matrix of images, or a cell matrix. Are these colour images? Secondly you only have 1400 images, not 1401, Matlab indexes from 1 not from 0.
If it is a normal array of single channel images (i.e. greyscale) then you want this:
for imageNumber = 1:size(Images,3)-9 %loop along the third dimension
NewImages(:, :, imageNumber) = findMedian(Images(:,:,imageNumber:imageNumber + 9)) %findMedian is your own function that you must write that outputs the median of 10 images as a 480 x 640 matrix.
end