How does a one liner in matlab cell array works? - arrays

SUBSAMPLE = 2; % Subsample your image by this much
for person_num = 1:40
for sample_num = 1:10
filename = ['orl_faces/s' num2str(person_num) '/' num2str(sample_num) '.pgm'];
if sample_num < 8
img = imread(filename);
[m,n] = size(img);
imagetrain{person_num,sample_num} = img(1:SUBSAMPLE:m,1:SUBSAMPLE:n)(:);
else
img = imread(filename);
imagetest{person_num,sample_num} = img(1:SUBSAMPLE:m,1:SUBSAMPLE:n)(:);
end
end
end
Above is code fragment from a matlab code for facial recognition. I am new to matlab therefore I am trying to understand statements that are new to me. My question is, imagetrain and imagetest is being assigned something from img(). Can anyone explain to me what img() is being assigned to the matrices? It looks like something of oneliner to me.

img is the image loaded using imread.
The code img(1:SUBSAMPLE:m,1:SUBSAMPLE:n) subsamples the image and reduces its size. The result is a new image (i.e. a new matrix) with fewer number of rows and fewer number of columns.
The leading (:) converts (reshapes) the matrix into a column vector.
So, for example if the original image is 256*256, the subsampled image will be 128*128, and after (:) it will become a column vector with 128*128=16384 elements.

Related

How do i store sequence of 2D matrices into a 3D array in Matlab?

I have these series of 2D CT images and i have been able to read them into Matlab using "imread". The issue however is that i need the image read-in as a single 3D matrix rather than stack of several 2D matrices. I have been made aware that it is possible to store the number of 2D layers as the 3rd dimension, but i have no idea how to do this as i am still a learner.
The code i have for reading in the 2D stack are as follows:
a = dir('*.tif');
for i = 1: numel(a)
b = imread(a(i).name); %read in the image
b_threshold = graythresh(b); %apply threshold
b_binary = im2bw(b, b_threshold); %binarize image
[m, n] = size(b); %compute the size of the matrix
phi(i) = ((m*n) - sum((b_binary(:))))/(m*n); %compute the fraction of pore pixels in the image
phi(:,i) = phi(i); %store each of the above result
end
I have added just a single image although several of these are needed. Nevertheless, one can easily duplicate the image to create a stack of 2D images. For the code to work, it is however important to rename them in a numerical order.pore_image
Any help/suggestions/ideas is welcomed. Thanks!
You can simply assign along the third dimension using i as your index
stack_of_images(:,:,i) = b_binary
Well, the first advice is try to don't use the variable i and j in matlab because they are reserved (have a look here and here).
After it depends on along which dimension you want to store the 2D images:
if you want to store the images along the first dimension just use this code:
a = dir('*.tif');
for ii = 1: numel(a)
b = imread(a(ii).name); %read in the image
b_threshold = graythresh(b); %apply threshold
b_binary = im2bw(b, b_threshold); %binarize image
[m, n] = size(b); %compute the size of the matrix
phi(ii) = ((m*n) - sum((b_binary(:))))/(m*n); %compute the fraction of pore pixels in the image
phi(:,ii) = phi(ii); %store each of the above result
matrix_3D_images(ii,:,:)=b_binary; %adding a new layer
end
If you want to store the images along other dimensions it is easy to do: just change the posizion of the "pointer" ii:
matrix_3D_images(:,ii,:)=b_binary; or
matrix_3D_images(:,:,ii)=b_binary;

MATLAB - copying specific values from one 3d array to another

I need to update image 1 with rgb values from image 2 for specific coordinates.
I have two 2d matrices (im1Cart_toupdate 2x114056 and im2EstCart_tocopyfrom also 2x114056). These contain the ordered x-y pairs for which I want to copy rgb values from image 2 to image 1.
i.e. there are 114,056 pixels where I want to copy colours across.
im1 (440x1370x3) and im2 (240x320x3) are the image arrays. Note im2 is going to be stretched, so some pixels from im2 will appear more than once in im2EstCart_tocopyfrom.
I need an efficient way of doing this, as even with the above image sizes my current implementation is very slow. I had thought that there may be some approach using sub2ind - but am not sure how to do this with 3d arrays.
Here's my current code. It's the for loop that's killing me!
%Create a matrix of all pixel coordinates in im1 (homogenised form)
[im1gridx im1gridy]=meshgrid(1:im1width,1:im1height);
im1Cart = [im1gridx(:) im1gridy(:)]';
im1Hom = [im1Cart; ones(1,numel(im1gridy))];
%transform pixel positions with homography (HEst is a matrix built
%elsewhere) to find where they are in the coordinates of image 2
im2EstHom = HEst*im1Hom;
im2EstCart = im2EstHom(1:2,:)./repmat(im2EstHom(3,:),2,1);
im2EstCart = round(im2EstCart);
%check if the the transformed position is within the boundary of image 2
validCoords = im2EstCart(1,:)>0 & im2EstCart(2,:)>0 & im2EstCart(1,:)<=im2width & im2EstCart(2,:)<=im2height;
im1Cart_toupdate=im1Cart(:,validCoords);
im2EstCart_tocopyfrom=im2EstCart(:,validCoords);
%copy colour from image 2 to image 1 - currently pixel by pixel
%but CAN THIS BE VECTORISED?
for i=1:size(im1Cart_toupdate,2)
im1y=im1Cart_toupdate(1,i);
im1x=im1Cart_toupdate(2,i);
im2y=im2EstCart_tocopyfrom(1,i);
im2x=im2EstCart_tocopyfrom(2,i);
im1(im1y,im1x,:) = im2(im2y,im2x,:);
drawnow
end
Many thanks for any advice!
Approach #1
This would be one vectorized approach using linear indexing with bsxfun -
[m2,n2,r2] = size(im2);
RHS_idx1 = (im2EstCart_tocopyfrom(2,:)-1)*m2 + im2EstCart_tocopyfrom(1,:)
RHS_allidx = bsxfun(#plus,RHS_idx1(:),(0:r2-1)*m2*n2)
[m1,n1,r1] = size(im1);
LHS_idx1 = (im1Cart_toupdate(2,:)-1)*m1 + im1Cart_toupdate(1,:)
LHS_allidx = bsxfun(#plus,LHS_idx1(:),(0:r1-1)*m1*n1)
im1(LHS_allidx) = im2(RHS_allidx)
Approach #2
Here's another approach that reshapes the input 3D array to a 2D array after merging the first two dimensions, then using linear indexing for extracting and setting values and finally reshaping back to its original 3D size, like so -
[m2,n2,r2] = size(im2)
RHS_idx1 = (im2EstCart_tocopyfrom(2,:)-1)*m2 + im2EstCart_tocopyfrom(1,:)
im2r = reshape(im2,[],r2)
[m1,n1,r1] = size(im1)
LHS_idx1 = (im1Cart_toupdate(2,:)-1)*m1 + im1Cart_toupdate(1,:)
im1r = reshape(im1,[],r1)
im1r(LHS_idx1,:) = im2r(RHS_idx1,:)
im1 = reshape(im1r,size(im1));

Display a Gaussian pyramid stored in a cell array in a single figure

I'm working on a Gaussian Pyramid code for matlab. Basically it loads an image, creates a cell array and fills it with different levels of the gaussian pyramid.
I want to show the content of my cell array filled with images in one single figure,
so you can see the gaussian pyramid effect. Meaning the original image is at full size and the rest are downsampled by 2 each. And all that in one figure.
I'm quite the amateur when it comes to Matlab so I don't really know how to do that.
I already tried it somewhat with subplots but failed.
Thanks in advance.
I used a loop to add zeros at the top of all images then merged them
Sample cell,
im = imread('peppers.png');
for i = 1 : 5
I{i} = im(1 : 2*i : end, 1 : 2*i : end,:);
end
The code, I being your cell,
m = size(I{1}, 1);
newI = I{1};
for i = 2 : numel(I)
[q,p,~] = size(I{i});
I{i} = cat(1,repmat(zeros(1, p, 3),[m - q , 1]),I{i});
newI = cat(2,newI,I{i});
end
imshow(newI)
For 2D images use : I{i} = cat(1,repmat(zeros(1 , p),[m - q , 1]),I{i});
How about:
subplot(numel(YourCell), 1, 1), imshow(YourCell{1});
for k=2:5
subplot(1,numel(YourCell),k), imshow(YourCell{k})
xlim([1 size(YourCell{1},1)]);
ylim([1 size(YourCell{1},2)]);
end
Result (with dummy data):
Edit:
You can play with the arrangement of your tiles by calculating the position of the next one. Here is a quick and dirty example, you can surely do a better job:
Side by side:
border=5;
MergedImage=ones(size(YourCell{1},1), 2.5*size(YourCell{1},2));
MergedImage(1:size(YourCell{1},1), 1:size(YourCell{1},2))=YourCell{1};
Pos=[1, size(YourCell{1},1)+border];
for k=1:(numel(YourCell)-1)
MergedImage(Pos(1):Pos(1)+size(YourCell{k+1}, 1)-1, Pos(2):Pos(2)+size(YourCell{k+1}, 2)-1)=YourCell{k+1};
Pos=[Pos(1), Pos(2)+size(YourCell{k+1}, 2)+border];
end
imshow(MergedImage);
Or a tighter arrangement:
border=5;
MergedImage=ones(size(YourCell{1},1), 2*size(YourCell{1},2));
MergedImage(1:size(YourCell{1},1), 1:size(YourCell{1},2))=YourCell{1};
Pos=[1, size(YourCell{1},1)+border];
for k=1:(numel(YourCell)-1)
MergedImage(Pos(1):Pos(1)+size(YourCell{k+1}, 1)-1, Pos(2):Pos(2)+size(YourCell{k+1}, 2)-1)=YourCell{k+1};
if mod(k,2) == 0
Pos=[Pos(1)+size(YourCell{k+1}, 1)+border, Pos(2)];
else
Pos=[Pos(1), Pos(2)+size(YourCell{k+1}, 2)+border];
end
end
imshow(MergedImage);

Matlab - Cropping 2d image maps in a loop and storing in a single variable

I have a code to crop connected components of input image, input, by finding the boundary conditions from a binary image's labelled map, labelledmap ([labelledmap, labelcount] = bwlabel(hvedged, 8);)
I'm new to matlab so this might sound stupid..
The problem is, I am unable to store different cropped images in the same variable, Because matlab seems to merge the ends of the already existing image and the new cropped image, i.e, it is storing the complete map between the two cropped images, the way i see it :/
This is the output Using different variables for storing cropped image (the kind of output i want)
Output Using different variables for storing cropped image
This is the output i'm getting by storing the cropped image in the same variable(not helpful)
Output when storing cropped image in the same varible
I tried using an array of size equal to total number of labels produced but it's giving the same result.. also i tried clearvars for clearing the output token image, ltoken, after every iteration of the loop but it's not helping
So, is there any possible way to display individual cropped images.. also the number of cropped images might be in thousands so i want to use a loop to code their cropping mechanism
here is a part of the code attached.. thanks in advance ;)
for h=1:labelcount
for i=1:r
for j=1:c
if labelledmap(i,j)==h
if i<ltop
ltop=i;
end
if i>lbottom
lbottom=i;
end
if j<lleft
lleft=j;
end
if j>lright
lright=j;
end
end
end
end
if ltop>5
ltop=ltop-5;
end
if lbottom<r-5
lbottom=lbottom+5;
end
if lleft>5
lleft=lleft-5;
end
if lright<c-5
lright=lright+5;
end
lwidth=lright-lleft;
lheight=lbottom-ltop;
ltoken=imcrop(input,[lleft ltop lwidth lheight]);
figure('Name', 'Cropped Token'), imshow(ltoken);
clearvars ltoken;
end
you need to initialize ltop lbottom lleft and lright for each iteration of label h. I think this is the reason why you get the cropped images "glued" together.
It is EXTREMELY inefficient to go through all the pixels for each and every one of your labels. Especially when you are expected to have many labels.
Use regionprops to get the 'BoundingBox' property for each label.
Here's an example
st = regionprops( labelledmap, 'BoundingBox' );
imlist = cell( 1, numel(st) ); % pre-allocate
for ii=1:numel(st)
r = st(ii).BoundingBox;
% I understand you want to increase the BB by 5 pixels at each side:
r(1:2) = r(1:2) - 5; % start point moves -5
r(3:4) = r(3:4) + 10; % width and height increases by 10
imlist{ii} = imcrop( input, r );
end
I'm still a bit in shock by your code that explicitly loops through all pixels just for finding the bouding box. This is NOT the matlab way of doing things.
If you insist on NOT using regionprops here's a more Matlab-ish way of finding the ii-th bounding box:
imsk = (labeledmap == ii); % create a binary map with True for ii-th region
xFlat = any(imsk,1); % "flattening" imsk on the x-axis
lleft = find( xFlat, 1, 'first' );
lright = find( xFlat, 1, 'last' );
yFlat = any(imsk, 2);
ltop = find( yFlat, 1, 'first' );
lbottom = find( yFlat, 1, 'last' );
No loops at all over image coordinates.

MATLAB using 2D Array

i want to use a 2D array to store all the values of img1, img2 and the compared vlaue of img1 and img2,
I want to achive the algorithm likes:
% read in the images from a folder one by one:
somefolder = 'folder';
filelist = dir([somefolder '/*.jpg']);
s=numel(filelist);
C = cell(length(filelist), 1);
for k=1:s
C{k}=imread([somefolder filelist(k).name]);
end
%choose any of the two images to compare
for t=1:(s-1)
for r=(t+1):s
img1=C{r};
img2=C{t};
ssim_value[num][1]=img1; % first img
ssim_value[num][2]=img2; % second img
ssim_value[num][3]=mssim; % ssim value of these two images
end
end
So, there is error about using the 2D array (ssim_value) that I used, what is the correct way of initialization it, and how to achieve the purpose that save the values that I want to store.
Could someone help me. Thanks in advance.
I'm assuming that "num" is a number that you will supply, like 5 or something. You cannot mix types in arrays as you do in Python. Also, as #Schorsch pointed out, you use parenthesis to index arrays in Matlab.
The two-dimensional array you are trying to form needs to be a 2-D cell array. For example:
a = {{"a",3},{"two",[1,2,3]};
In this case, a{1,2} = 3, and a{2,1} = "two".
You may not know in advance how many files are in the directory, so pre-initializing the cell array may not be possible in advance. In any case, Matlab arrays only need to be pre-initialized for performance reasons, and you can easily find information on initializing arrays in Matlab.
In light of this, I'm pretty sure what you are trying to accomplish is:
%choose any of the two images to compare
ssim_value = {};
for t=1:(s-1)
for r=(t+1):s
img1=C{r};
img2=C{t};
ssim_value{num,1}=img1; % first img
ssim_value{num,2}=img2; % second img
ssim_value{num,3}=mssim; % ssim value of these two images
end
end

Resources