如何在不使用MATLAB循环的情况下比较矩阵元素与其邻居?

Sha*_*han 11 matlab image-processing matrix

我在MATLAB中有一个矩阵.我想检查每个元素的4个连接的邻居(左,右,上,下).如果当前元素小于任何邻居,那么我们将其设置为零,否则它将保持其值.它可以很容易地用循环完成,但它非常昂贵,因为我有数千个这样的矩阵.

您可能会在边缘检测后将其识别为非最大值抑制.

Jon*_*nas 9

如果您有图像处理工具箱,则可以使用形态膨胀来查找局部最大值并抑制所有其他元素.

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
Run Code Online (Sandbox Code Playgroud)

编辑使用与@gnovice相同的数据,并修复代码

  • @Shan:哎呀,是的.我修复了解决方案. (2认同)

gno*_*ice 8

这样做的一种方法是使用功能NLFILTER图像处理工具箱,它适用的给定功能的矩阵的每一M-通过-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
Run Code Online (Sandbox Code Playgroud)

上面的代码定义了一个匿名函数,它使用线性索引来获取3乘3子矩阵的中心元素,b(5)并将其与4个连接的邻居进行比较b([2 4 6 8]).中心元素中的值乘以函数ALL返回的逻辑结果,当中心元素大于其所有最近邻居时为1,否则为0.

  • 虽然我怀疑imdilate可能仍然更快,但+1在第一次尝试时才能正确使用它. (2认同)

b3.*_*b3. 5

如果您无法访问图像处理工具箱,另一种方法是通过构造四个矩阵来表示每个点的顶部,右侧,底部和左侧第一个差异,然后在所有四个非矩阵中搜索相应的元素. - 负(即元素超过其所有邻居).

这是分解的想法......

生成一些测试数据:

>> 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.

  • +1:非常好.当您可以访问花哨的工具箱时,很容易忘记这样的简单实现.;)一个建议......您可以使用[CIRCSHIFT](http://www.mathworks.com/help/techdoc/ref/circshift.html)简化代码,如下所示:`index = A2> = circshift(A2, [0 1])&A2> = circshift(A2,[0 -1])&A2> = circshift(A2,[1 0])&A2> = circshift(A2,[ - 1 0]); A2 = A2.*指数; A2 = A2(2:结束-1,2:结束-1);`此外,我认为你想使用`> =`而不是`>`. (3认同)
  • 哦,另一个使算法更通用的建议是使用`-Inf`填充矩阵而不是0,以解释矩阵中负值的可能性(即你不希望填充显示出来)作为一个局部最大值). (2认同)