Найти массив вокруг максимальных значений массива - PullRequest
2 голосов
/ 06 марта 2019

У меня здесь довольно сложный вопрос, над которым я работаю. Это чрезвычайно сложно описать словами, поэтому я попытаюсь объяснить это на примере.

Предположим, у меня есть матрица значений:

A = 

[31 85 36 71 51] 
[12 33 74 39 12]
[67 11 13 14 18]
[35 36 84 33 57]

Теперь я хочу сначала найти максимальный вектор в первом измерении, что легко:

[max_vector,~] = max(A,[],1);


max_vector=[67,85, 84, 71,57]

Теперь я хочу получить «уменьшенную» матрицу со значениями вокруг максимумов (периодические индексы):

Desired_Matrix =

 [12 36 36 33 18]
 [67 85 84 71 57]
 [35 33 13 39 51]

Это матрица с векторами вокруг максимальных значений матрицы А. Может кто-нибудь сказать мне, как это сделать без использования двойного цикла for?

Спасибо!

Ответы [ 4 ]

5 голосов
/ 06 марта 2019
% Input.
A = [31 85 36 71 51; 12 33 74 39 12; 67 11 13 14 18; 35 36 84 33 57]

% Dimensions needed.
nRows = size(A, 1);
nCols = size(A, 2);

% Get maxima and corresponding indices in input.
[max_vector, ind] = max(A);

% Get neighbouring indices.
ind = [ind - 1; ind; ind + 1];

% Modulo indices to prevent dimension overflow.
ind = mod(ind, nRows);

% Correct zero indices.
ind(ind == 0) = nRows;

% Calculate correct indices in A.
temp = repmat(0:nRows:nRows*(nCols-1), 3, 1);
ind = ind + temp;

% Output.
B = A(ind)

Поскольку у нас есть максимум индексов на столбец, но позже мы хотим получить доступ к этим элементам в исходном массиве A, нам нужны линейные индексы для A. Здесь хитрость заключается в том, чтобы добавить количество строк, умноженное на индекс столбца (начиная с 0). Самым простым способом понять это может быть удаление точек с запятой и проверка промежуточных значений ind.

4 голосов
/ 06 марта 2019

@ Ответ HansHirse более эффективен, поскольку не создает промежуточную матрицу.


Попробуйте:

[~, ind_max] = max(A,[],1);
A_ext = A([end 1:end 1],:);
ind_lin = bsxfun(@plus, bsxfun(@plus, ind_max, (0:2).'), (0:size(A_ext,2)-1)*size(A_ext,1));
result = reshape(A_ext(ind_lin), 3, []);

Для Matlab R2016b или новее вы можете упростить третью строку:

[~, ind_max] = max(A,[],1);
A_ext = A([end 1:end 1],:);
ind_lin = ind_max + (0:2).' + (0:size(A_ext,2)-1)*size(A_ext,1);
result = reshape(A_ext(ind_lin), 3, []);
3 голосов
/ 06 марта 2019

Вот еще одно решение.Это похоже на ответ HansHirse с двумя улучшениями:

  • Чуть более элегантно обрабатывает модульное индексирование
  • Более гибко для указания, какие соседи вам нужны

Код:

% Input
A = [31 85 36 71 51; 
    12 33 74 39 12; 
    67 11 13 14 18; 
    35 36 84 33 57];

% Relative rows of neighbours, i.e. this is [-1, 0, 1] for +/- one row
p = -1:1;
% Get A row and column counts for ease
[nr, nc] = size(A);
% Get max indices
[~,idx] = max( A, [], 1 );
% Handle overflowing indices to wrap around rows
% You don't have to redefine "idx", could use this directly in the indexing line
idx = mod( idx + p.' - 1, nr ) + 1;
% Output B. The "+ ... " is to convert to linear indices, as "idx"
% currently just refers to the row number.
B = A(idx + (0:nr:nr*nc-1));
0 голосов
/ 06 марта 2019

Вы можете использовать панель инструментов обработки изображений, чтобы сгенерировать результат, но он менее эффективен, чем другие решения.

[~,idx] = max(A, [], 1);
d = imdilate( idx == (1:size(A,1) ).', [1;1;1], 'full');
p = padarray(A, 1, 'circular');
Desired_Matrix = reshape(p(d), 3, []);
...