1
votes

I have been having problem with identifying two maximum values' position in 3D matrix (MATLAB). Say I have matrix A output as follows:

A(:,:,1) =

     5     3     5
     0     1     0


A(:,:,2) =

     0     2     0
     8     0     8


A(:,:,3) =

     3     0     0
     0     7     7


A(:,:,4) =

     6     6     0
     4     0     0

For the first A(:,:,1), I want to identify that the first row have the highest value (A=5). But I need the two index position, which in this case, 1 and 3. And this is the same as the other A(:,:,:).

I have searched through SO but since I am bad in MATLAB, I couldn't find way to work this through.

Please do help me on this. It would be better if I don't need to use for loop to get the desired output.

2
What if there is a 5 at A(2,1,1)?Divakar
@Divakar for that case, 5 is still less than 8. My aim here is to find a row for each 3D matrix with two maximum value and identify their index.loss
a row for each 3D matrix with two maximum value? I am lost here! Write down the expected output?Divakar
Sorry, I was trying out the code @Nemesis gave me. I saw you provide the alternative as well. Thumb up! =)loss
Well I figured you are looking for one of those two shots, just not sure which one.Divakar

2 Answers

1
votes

The following code gives you the column and row of the respective maximum.

The first step will obtain the maximum of each sub-matrix containing the first and second dimension. Since max works per default with the first dimension, the matrix is reshaped to combine the original first and second dimension.

max_vals = max(reshape(A,size(A,1)*size(A,2),size(A,3)));
max_vals = 
           5     8     7     6

In the second step, the index of elements equal to the respective max_vals of each sub-matrix is obtained using arrayfun over the third dimension. Since the output of arrayfun are cells, cell2mat is used to transform the output into a matrix. As a last step, the linear index from find is transformed into sub-indices by ind2sub.

[i,j] = ind2sub(size(A(:,:,1)),cell2mat(arrayfun(@(i)find(A(:,:,i)==max_vals(i)),1:size(A,3),'UniformOutput',false)))

i =
     1     2     2     1
     1     2     2     1

j =
     1     1     2     1
     3     3     3     2

Hence, the values in j are the ones you want to have.

2
votes

Shot #1 Finding the indices for maximum values across each 3D slice -

%// Reshape A into a 2D matrix
A_2d = reshape(A,[],size(A,3))

%// Find linear indices of maximum numbers for each 3D slice
idx = find(reshape(bsxfun(@eq,A_2d,max(A_2d,[],1)),size(A)))

%// Convert those linear indices to dim1, dim2,dim3 indices and
%// present the final output as a Nx3 array
[dim1_idx,dim2_idx,dim3_idx] = ind2sub(size(A),idx)
out_idx_triplet = [dim1_idx dim2_idx dim3_idx]

Sample run -

>> A
A(:,:,1) =
     5     3     5
     0     1     0
A(:,:,2) =
     0     2     0
     8     0     8
A(:,:,3) =
     3     0     0
     0     7     7
A(:,:,4) =
     6     6     0
     4     0     0

out_idx_triplet =
     1     1     1
     1     3     1
     2     1     2
     2     3     2
     2     2     3
     2     3     3
     1     1     4
     1     2     4

out_idx_triplet(:,2) is what you are looking for!


Shot #2 Finding the indices for highest two numbers across each 3D slice -

%// Get size of A
[m,n,r] = size(A)  

%// Reshape A into a 2D matrix
A_2d = reshape(A,[],r)

%// Find linear indices of highest two numbers for each 3D slice
[~,sorted_idx] = sort(A_2d,1,'descend')
idx = bsxfun(@plus,sorted_idx(1:2,:),[0:r-1]*m*n)

%// Convert those linear indices to dim1, dim2,dim3 indices
[dim1_idx,dim2_idx,dim3_idx] = ind2sub(size(A),idx(:))

%// Present the final output as a Nx3 array
out_idx_triplet = [dim1_idx dim2_idx dim3_idx]

out_idx_triplet(:,2) is what you are looking for!