cell with multiple column to matrix in Matlab - matlab

I have a cell in Matlab composed as follow, where each entry can have multiple integer.
For instance:
A=cell(2,10);
A{1,1}=[5];
A{1,2}=[5 7];
A{1,3}=[5];
A{1,4}=[5];
A{1,5}=[5];
A{1,6}=[5];
A{1,7}=[5];
A{1,8}=[5];
A{1,9}=[5];
A{1,10}=[5];
A{2,1}=[5];
A{2,2}=[3];
A{2,3}=[1];
A{2,4}=[5];
A{2,5}=[2];
A{2,6}=[6];
A{2,7}=[2];
A{2,8}=[2];
A{2,9}=[1];
A{2,10}=[5 4];
I would obtain a Matrix which contains the elements of the cells. When the rows in the cells contain multiple entry (for example A{1,2}) the entry should be included (all of them) one time. For instance the Matrix output should be:
B=[5 5 5 5 5 5 5 5 5 5; %A{1,:}first column in the cell
5 7 5 5 5 5 5 5 5 5; %A{1,:}first column and the second element in row
A{1,2}
5 3 1 5 2 6 2 2 1 5;
5 3 1 5 2 6 2 2 1 4];
Could you help me?
Thanks in advance

This will do it:
[r,c]= size(A); %Finding the size of A for the next step
B=zeros(r*2,c); %Pre-allocating the memory
for iter=1:r
k=find(cellfun('length',A(iter,:))==2); %finding which elements have length =2
temp=cell2mat(A(iter,:)); %converting cell to matrix
k1= k+ [0:size(k,2)-1]; %finding which elements should come in the next row instead of in next column
temp1= temp(k1+1); %storing those elements in 'temp1' matrix
temp(k1+1)=[]; %removing those elements from original 'temp' matrix
B(2*(iter-1)+1:2*(iter-1)+2, :)=[temp; temp];
B(2+(iter-1)*2,k)=temp1; %replacing the elements from temp1
end
B

Related

Matlab: combining multiple matrices row-wise

I have some data in 10 matrices. Each matrix has a different number of rows, but the same number of columns.
I want to combine all 10 matrices to one matrix row-wise, interleaved, meaning the rows in that matrix will look like:
row 1 from matrix 0
...
row 1 from matrix 9
row 2 from matrix 0
...
row 2 from matrix 9
...
Example (with 3 matrices):
Matrix 1: [1 2 3 ; 4 5 6; 7 8 9]
Matrix 2: [3 2 1 ; 6 5 4]
Matrix 3: [1 1 1 ; 2 2 2 ; 3 3 3]
Combined matrix will be: [1 2 3 ; 3 2 1 ; 1 1 1 ; 4 5 6 ; 6 5 4 ; 2 2 2 ; 7 8 9 ; 3 3 3]
You can download the function interleave2 here https://au.mathworks.com/matlabcentral/fileexchange/45757-interleave-vectors-or-matrices
z = interleave2(a,b,c,'row')
you can see the way the function works in the source code of course
Here's a general solution that allows you to place however many matrices you want (with matching number of columns) into the starting cell array Result:
Result = {Matrix1, Matrix2, Matrix3};
index = cellfun(#(m) {1:size(m, 1)}, Result);
[~, index] = sort([index{:}]);
Result = vertcat(Result{:});
Result = Result(index, :);
This will generate an index vector 1:m for each matrix, where m is its number of rows. By concatenating these indices and sorting them, we can get a new index that can be used to sort the rows of the vertically-concatenated set of matrices so that they are interleaved.

Matlab Matrix Repeat Value

my matrix:
e =
1 2
2 3
3 3
4 3
5 2
i want to repeat value from first coloumn as much as number from the second coloumn in the same row. i want to make my matrix to be like:
e =
1 2
1 2
2 3
2 3
2 3
3 3
3 3
3 3
4 3
4 3
4 3
5 2
5 2
thank you for your help...
You can use repelem to repeat the row indices and then grab those rows from e:
new_e = e(repelem(1:size(e,1), e(:,2)), :);
If you're using a MATLAB version prior to 2015a that doesn't have repelem, here's another way to do it:
spacing = cumsum([1; e(:,2)]); % the rows of new_e where we change row values
row_indices(spacing) = 1; % make a vector with these elements = 1
row_indices = cumsum(row_indices); % convert to row indices, last index is invalid
new_e = e(row_indices(1:end-1), :); % select valid rows from e

Find closest element with same value in matrix in matlab

Consider the following matrix:
0 3 0 1 1 4
1 3 5 6 7 0
2 5 6 2 6 1
4 4 2 1 5 1
When I specify the position of an element, I would like to obtain the position of the nearest element with the same value.For example, if I select the element in row 3,column 3, i.e. '6', I would like to obtain the the row and column values of the nearest '6',in this case, it is at row 2, column 4.And similarly, for the '1' at row 4,column 4, the nearest is at row 4,col 5 and row 4,col 6, any one of them is are fine.I have looked up the 'bwdist' and 'find' functions but they don't give the proper result.Can anyone help me on this?
Edit:
a1 = randi(10,10,5);
disp(a1);
%// For an array of search numbers
search_array = a1(4,5);
disp(search_array);
%%// Find the linear index of the location
[~,ind] = min(abs(bsxfun(#minus,a1(:),search_array')));%//'
%%// Convert the linear index into row and column numbers
[x,y] = ind2sub(size(a1),ind)
The 'min' function will not work here as each position where the required element is present will be converted to zero and 'min' scans the matrix row-wise and gives the position of the first zero.The following is such a case:
2 6 10 9 2
6 6 7 5 3
1 8 5 2 1
8 1 9 5 5
9 7 6 4 3
10 6 6 5 3
10 2 7 9 5
6 10 4 5 2
3 6 3 4 5
2 5 6 4 8
Even though there is a '5' right next to the '5' in row 4,col 5,the '5' in row 10, column 2 is selected.
Assuming A to be the input 2D matrix, this could be one approach -
%// Row and column indices of the "pivot"
row_id = 4;
col_id = 5;
%// Get the linear index from row and column indices
lin_idx = sub2ind(size(A),row_id,col_id)
%// Logical array with ones at places with same values
search_matches = false(size(A));
search_matches(A==A(lin_idx)) = 1;
%// Create a logical array with just a single 1 at the "pivot"
A_pivot = false(size(A));
A_pivot(lin_idx) = 1;
%// Use BWDIST to find out the distances from the pivot to all the places
%// in the 2D matrix. Set the pivot place and places with non-similar
%// values as Inf, so that later on MIN could be used to find the nearest
%// same values location
distmat = bwdist(A_pivot)
distmat(lin_idx) = Inf
distmat(~search_matches)=Inf
[~,min_lin_idx] = min(distmat(:))
[closest_row_idx,closest_col_idx] = ind2sub(size(A),min_lin_idx)
This approach doesn't require any toolbox. It returns [] if no other entry with the same value exists.
A = [0 3 0 1 1 4
1 3 5 6 7 0
2 5 6 2 6 1
4 4 2 1 5 1]; %// data matrix
pos_row = 3; %// row of reference element
pos_col = 3; %// col of reference element
ref = A(pos_row,pos_col); %// take note of value
A(pos_row,pos_col) = NaN; %// remove it, to avoid finding it as closest
[ii, jj] = find(A==ref); %// find all entries with the same value
A(pos_row,pos_col) = ref; %// restore value
d = (ii-pos_row).^2+ (jj-pos_col).^2; %// compute distances
[~, ind] = min(d); %// find arg min of distances
result_row = ii(ind); %// index with that to obtain result
result_col = jj(ind);

Group matrix values into separate matrices based on values of another matrix

I am reading in images with imread which results in 768x1024x3 matrix with R,G,B values of each pixel.
I have a function that takes in an image and returns matrix of segment labels for each pixel so this matrix is 768x1024. the labels are just numbers 1,2,3,4 depending on how many different segments the function finds.
Now I want to calculate the average Red, Green and Blue value in each segment of the image. So I want to use the indices from the segment label matrix to find group all R,G,B values into separate arrays and then be able to calculate the mean.
Is there any smart way to do this? use the indices of each 1 value in the segment matrix to get the values from the imread matrix and group the segments into different arrays? I though of using for loops and brute force through this but is there a better way to do this?
Here's a code that you will get you everything without looping.
Code
%// img is your input RGB image (NxMx3)
%// L is your label matrix (NxM)
t1 = bsxfun(#eq,L,permute(unique(L),[3 2 1]));
t2 = bsxfun(#times,permute(img,[ 1 2 4 3]),t1);
t2(t2==0)=nan;
out = squeeze(nanmean(nanmean(t2)))
%// out is the desired output matrix that is (NLx3),
%// where NL is the number of labels. Thus, the mean of labels is
%// along the rows and the corresponding values for R, G and B are in the three
%// columns of it.
Explanation
Let's test out with some random values for img -
img = randi(9,3,4,3)
Giving us -
img(:,:,1) =
9 7 5 3
7 7 2 4
1 6 7 9
img(:,:,2) =
8 6 6 4
4 9 3 9
3 9 8 1
img(:,:,3) =
5 4 4 5
7 2 5 3
2 3 1 3
Some assumed values for L that goes from 1 to 8
L = [1 3 3 4;
4 5 8 8;
5 6 7 2]
The code output is -
out =
9 8 5
9 1 3
6 6 4
5 4 6
4 6 2
6 9 3
7 8 1
3 6 4
Let's see how to make sense of the output.
Looking at the input, let's choose the label 8, which is at locations (2nd row,3rd col) and (2nd row,4th col). The corresponding R values at these locations in img are [2 4], and thus the R mean/average value must be 3. Similarly for G it must be from [3 9], that is 6 and again for B would be from [5 3], that is 4.
Let's look at the 8th row of out that represents the label-8, we have [3 6 4], which are the mean values as calculated earlier. Similarly other mean values could be interpreted from out.
Edited to handle all channels at once.
Let img be your RGB image and labels the labels array.
You can mask the RGB image with the labels like this:
% create a 3-channels mask:
labelsRGB=repmat(labels, 1, 1, 3);
Segment1=img.*(labelsRGB==1);
The average values in the segment labeled as 1 is then:
avg=mean(mean(Segment1, 1), 2);
Get the average for re in avg(1), the average for green in avg(2), etc.
Idem for the other segments.
Here goes a general alternative.
In this case you do not need to loop over the different segments to get the average of each.
%simulated image and label
img=rand(10,12,3);
labeled=[ones(10,3),ones(10,3)*2,ones(10,3)*3,ones(10,3)*4];
% actual code for the mean
red_mean = regionprops(labeled, img(:,:,1), 'MeanIntensity')

Sorting Coordinate Matrix in Matlab

In Matlab I have a big matrix containing the coordinates (x,y,z) of many points (over 200000). There is an extra column used as identification. I have written this code in order to sort all coordinate points. My final goal is to find duplicated points (rows with same x,y,z). After sorting the coordinate points I use the diff function, two consecutive rows of the matrix with the same coordinates will take value [0 0 0], and then with ismember I can find which rows of that matrix resulting from applying "diff" have the [0 0 0] row. With the indices returned from ismember I can find which points are repeated.
Back to my question...This is the code I wrote to sort properly my coordintes+id matrix. I guess It could be done better. Any suggestion?
%coordinates are always positive
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 1 2 8;
1 2 4 8];
b=a; %for checking purposes
%sorting first column
a=sortrows(a,1);
%sorting second column
for i=0:max(a(:,1));
k=find(a(:,1)==i);
if not(isempty(k))
a(k,:)=sortrows(a(k,:),2);
end
end
%Sorting third column
for i=0:max(a(:,2));
k=find(a(:,2)==i);
if not(isempty(k))
%identifying rows with same value on first column
for j=1:length(k)
[rows,~] = ismember(a(:,1:2), [ a(k(j),1),i],'rows');
a(rows,3:end)=sortrows(a(rows,3:end),1);
end
end
end
%Checking that rows remain the same
m=ismember(b,a,'rows');
if length(m)~=sum(m)
disp('Error while sorting!');
end
Why don't you just use unique?
[uniqueRows, ii, jj] = unique(a(:,1:3),'rows');
Example
a = [1 2 3 5
3 2 3 6
1 2 3 9
2 2 2 8];
gives
uniqueRows =
1 2 3
2 2 2
3 2 3
and
jj =
1
3
1
2
meaning third row equals first row.
If you need the full unique rows, including the fourth column: use ii to index a:
fullUniqueRows = a(ii,:);
which gives
fullUniqueRows =
1 2 3 9
2 2 2 8
3 2 3 6
Trying to sort a based on the fourth column? Do this -
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 2 1 8;
1 2 4 8];
[x,y] = sort(a(:,4))
sorted_a=a(y,:)
Trying to get the row indices having repeated x-y-z coordinates being represented by the first three columns? Do this -
out = sum(squeeze(all(bsxfun(#eq,a(:,1:3),permute(a(:,1:3),[3 2 1])),2)),2)>1
and use it similarly for sorted_a.