Как сравнить матричный элемент со своими соседями без использования цикла в MATLAB?

У меня есть матрица в MATLAB. Я хочу проверить 4-связанных соседей (слева, справа, сверху, снизу) для каждого элемента. Если текущий элемент меньше, чем любой из соседей, тогда мы устанавливаем его на ноль, иначе он будет сохранять свое значение. Это можно легко сделать с помощью цикла, но это очень дорого, поскольку у меня есть тысячи этих матриц.

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

Ответ 1

Один из способов сделать это - это функция NLFILTER из Инструмент обработки изображений, который применяет данную функцию к каждому блоку M-by-N матрицы:

>> A = magic(6)  %# A sample matrix

A =

    35     1     6    26    19    24
     3    32     7    21    23    25
    31     9     2    22    27    20
     8    28    33    17    10    15
    30     5    34    12    14    16
     4    36    29    13    18    11

>> B = nlfilter(A,[3 3],@(b) b(5)*all(b(5) >= b([2 4 6 8])))

B =

    35     0     0    26     0     0
     0    32     0     0     0    25
    31     0     0     0    27     0
     0     0     0     0     0     0
    30     0    34     0     0    16
     0    36     0     0    18     0

Приведенный выше код определяет анонимную функцию , которая использует линейное индексирование, чтобы получить центральный элемент подматрицы 3 на 3 b(5) и сравнить его с 4-связанными соседями b([2 4 6 8]). Значение в центральном элементе умножается на логический результат, возвращаемый функцией ALL, которая равна 1, когда центральный элемент больше всех его ближайших соседей и 0 в противном случае.

Ответ 2

Если у вас есть панель инструментов обработки изображений, вы можете сделать это с помощью морфологической дилатации, чтобы найти локальные максимумы и подавить все остальные элементы.

array = magic(6); %# make some data

msk = [0 1 0;1 0 1;0 1 0]; %# make a 4-neighbour mask

%# dilation will replace the center pixel with the 
%# maximum of its neighbors
maxNeighbour = imdilate(array,msk);

%# set pix to zero if less than neighbors
array(array<maxNeighbour) = 0;

array =
    35     0     0    26     0     0
     0    32     0     0     0    25
    31     0     0     0    27     0
     0     0     0     0     0     0
    30     0    34     0     0    16
     0    36     0     0    18     0

отредактирован для использования тех же данных, что и @gnovice, и для исправления кода

Ответ 3

Если у вас нет доступа к Image Processing Toolbox, другой способ сделать это - построить четыре матрицы, представляющие верхнюю, правую, нижние и левые первые различия для каждой точки, а затем поиск соответствующих элементов во всех четырех матрицах, которые являются неотрицательными (т.е. элемент превосходит всех его соседей).

Здесь идея сломана...

Сгенерировать некоторые тестовые данные:

>> sizeA = 3;
A = randi(255, sizeA)

A =

   254   131    94
   135    10   124
   105   191    84

Поместите границы с нулевыми элементами:

>> A2 = zeros(sizeA+2) * -Inf;
A2(2:end-1,2:end-1) = A

A2 =

     0     0     0     0     0
     0   254   131    94     0
     0   135    10   124     0
     0   105   191    84     0
     0     0     0     0     0

Построить четыре матрицы с первой разницей:

>> leftDiff = A2(2:end-1,2:end-1) - A2(2:end-1,1:end-2)

leftDiff =

   254  -123   -37
   135  -125   114
   105    86  -107

>> topDiff = A2(2:end-1,2:end-1) - A2(1:end-2,2:end-1)

topDiff =

   254   131    94
  -119  -121    30
   -30   181   -40

>> rightDiff = A2(2:end-1,2:end-1) - A2(2:end-1,3:end)

rightDiff =

   123    37    94
   125  -114   124
   -86   107    84

>> bottomDiff = A2(2:end-1,2:end-1) - A2(3:end,2:end-1)

bottomDiff =

   119   121   -30
    30  -181    40
   105   191    84

Найдите элементы, которые превышают все соседи:

indexKeep = find(leftDiff >= 0 & topDiff >= 0 & rightDiff >= 0 & bottomDiff >= 0)

Создайте результирующую матрицу:

>> B = zeros(sizeA);
B(indexKeep) = A(indexKeep)

B =

   254     0     0
     0     0   124
     0   191     0

После обертывания всего этого в функцию и проверки его на 1000 случайных матриц 100x100, алгоритм выглядит довольно быстро:

>> tic;
for ii = 1:1000
A = randi(255, 100);
B = test(A);
end; toc
Elapsed time is 0.861121 seconds.