开发者

How to compare a matrix element with its neighbours without using a loop in MATLAB?

开发者 https://www.devze.com 2023-02-12 09:35 出处:网络
I have a matrix in MATLAB. I want to check the 4-connected neighbours (left, right, top, bottom) for every element. If the current element is less than any of the neighbours then we se开发者_Go百科t i

I have a matrix in MATLAB. I want to check the 4-connected neighbours (left, right, top, bottom) for every element. If the current element is less than any of the neighbours then we se开发者_Go百科t it to zero otherwise it will keep its value. It can easily be done with loop, but it is very expensive as I have thousands of these matrices.

You might recognize it as nonmaxima suppression after edge detection.


If you have the image processing toolbox, you can do this with a morpological dilation to find local maxima and suppress all other elements.

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

edited to use the same data as @gnovice, and to fix the code


One way to do this is with the function NLFILTER from the Image Processing Toolbox, which applies a given function to each M-by-N block of a matrix:

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

The above code defines an anonymous function which uses linear indexing to get the center element of a 3-by-3 submatrix b(5) and compare it to its 4-connected neighbors b([2 4 6 8]). The value in the center element is multiplied by the logical result returned by the function ALL, which is 1 when the center element is larger than all of its nearest neighbors and 0 otherwise.


If you don't have access to the Image Processing Toolbox, another way to accomplish this is by constructing four matrices representing the top, right, bottom and left first differences for each point and then searching for corresponding elements in all four matrices that are non-negative (i.e. the element exceeds all of its neighbours).

Here's the idea broken down...

Generate some test data:

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

A =

   254   131    94
   135    10   124
   105   191    84

Pad the borders with zero-elements:

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

Construct the four first-difference matrices:

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

Find the elements that exceed all of the neighbours:

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

Create the resulting matrix:

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

B =

   254     0     0
     0     0   124
     0   191     0

After wrapping this all into a function and testing it on 1000 random 100x100 matrices, the algorithm appears to be quite fast:

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

精彩评论

暂无评论...
验证码 换一张
取 消