2
votes

I have a 3 dimensional matrix (3rd dimension represents multiple copies of an M x N grayscale image).

I'm taking the max value of each pixel across the images, giving me a max_val and max_ix matrix (2x2).

I want to reference the original test matrix by the max_ix values.

Example: my_max_val = test(max_ix,:) should equal:

     5     1
     1     1

Obviously I can just use max_val in this simplified example, but not in the real use case. I'm altering max_ix, so I need to reference the original 3-dimensional matrix by the new index values I create (not depicted in this simplified example).

>> test

test(:,:,1) =

     1     1
     1     1


test(:,:,2) =

     1     1
     1     1


test(:,:,3) =

     5     1
     1     1


test(:,:,4) =

     1     1
     1     1

>> [max_val, max_ix] = max(test, [], 3)

max_val =

     5     1
     1     1


max_ix =

     3     1
     1     1

How do I recreate max_val just from test and max_ix?

2

2 Answers

2
votes

One approach -

%// Get size of 3D input array
[m,n,~] = size(test);     

%// Calculate 2D starting, offset & finally actual indices array
start_idx = bsxfun(@plus,[1:m]',[0:n-1]*m);  %//'
offset_idx = m*n*(max_ix-1);
actual_idx = start_idx + offset_idx;

%// Index into 3D input array to extract specific elements, for desired output
max_val = test(actual_idx)

Thus, essentially giving us a two-liner solution, if you are into compact codes -

[m,n,~] = size(test);     
max_val = test( bsxfun(@plus,[1:m]',[0:n-1]*m) + m*n*(max_ix-1) )

Please note that bsxfun(@plus,[1:m]',[0:n-1]*m) could be replaced by reshape(1:m*n,m,n).

Sample run

Inputs:

test(:,:,1) =
    12    66    75    98
    65    75    24    87
    33    59    74     9
test(:,:,2) =
    37    60    21    21
    37    79     9    39
    69    37    78    56
test(:,:,3) =
    23    16    30    10
    65    79    24    41
    49    11    54    11
test(:,:,4) =
    12    61    70    66
    79    97    76    11
    30    44    44    94
max_ix =
     1     2     2     2
     2     4     1     2
     4     2     3     3

Output:

max_val =
    12    60    21    21
    37    97    24    39
    30    37    54    11
1
votes

Here's one way to do it.

%// Generate matrix test
test = randi(50,4,4,4);

%// Get maximum value and indices
[max_val, max_ix] = max(test, [], 3);

%// We don't know the size in general so this is the Cartesian product
[y, x] = meshgrid(1:size(test, 1), 1:size(test,2));

%// sub2ind provide the single value indices for a matrix of size(test) 
%// at positions [x(:), y(:), max_ix(:)] and reshape brings it back to the correct shape
max_val2 = reshape(test(sub2ind(size(test), x(:) , y(:), max_ix(:))), size(x));