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.
精彩评论