Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find the neighbors of all zeros elements in a matrix

In matlab, I have a matrix A of non-negative entries. See the following one:

A=[0 2 3 5 4 7 8
   1 8 2 7 5 2 9
   0 1 2 4 8 0 5
   2 4 8 6 0 5 8
   1 1 2 5 8 3 6];

I want to find the neighbors of all zero elements expect the zero element. This means that I want to store in a vector v the neighbors of A(1, 1), A(2, 5), A(3, 1), A(3, 6), A(4, 5), and A(5, 1) and if one of these neighbors is zero then I do not store it.

By neighbors of element (i, j) I mean the elements that are far away from (i, j) by one element, i.e., A(i, j+1), A(i, j-1), A(i-1, j), A(i-1, j-1), A(i-1, j+1), A(i+1, j), A(i+1, j-1), and A(i+1, j+1). Every element (i, j) has 7 neighbors.

I do not store repetition elements. This means that, if for example A(1, 1)=0 and A(1,3)=0 and A(1,2)=1 then I will store A(1, 2) only once.

In my previous example the vector v will be this one:

v=[2 1 8 1 2 4 5 2 9 8 5 5 8 4 6 5 8 3];

How to do this in matlab without loops?

This my code for square matrix: cl_ is the number of zero in my matrix. ix_ is the row indices of the zero elements and iy_ is the column indices of the zero elements.

for i_=1:length(cl_)
    ixn1_(1:2)=ix_(i_);
    ixn2_(1:3)=ix_(i_)-1;
    ixn3_(1:3)=ix_(i_)+1;
    iyn1_=iy_(i_)-1;
    iyn2_=iy_(i_)+1;
    iyn3_(1:3)=[iy_(i_)-1, iy_(i_), iy_(i_)+1];
    ixn_{i_}=[ixn1_, ixn2_, ixn3_];
    iyn_{i_}=[iyn1_, iyn2_, repmat(iyn3_, 1, 2)];
end
% find the neighbors
like image 264
npisinp Avatar asked Mar 25 '14 18:03

npisinp


3 Answers

If you aren't concerned about the order of the values:

mask = A==0;
neighborMask = xor(conv2(double(mask),ones(3),'same')>0,mask);
v = A(neighborMask)
like image 127
chappjc Avatar answered Nov 15 '22 06:11

chappjc


If you would like to keep the order in which you have stated in your question, this might be it -

Code

%%// Given data
A=[0 2 3 5 4 7 8
   1 8 2 7 5 2 9
   0 1 2 4 8 0 5
   2 4 8 6 0 5 8
   1 1 2 5 8 3 6];

%%// Find indices that have value zero
[indx,indy] = find(A==0);

%%// OP seems to be travelling row-wise, so sort the indices column-wise
[indx,y1] = sort(indx);
indy = indy(y1);

%%// Get the 8 neighboring row and column offsets  
row1 = bsxfun(@plus,indx,[-1 -1 -1 0 0 1 1 1]);
col1 = bsxfun(@plus,indy,[-1 0 1 -1 1 -1 0 1]);

%%// Get the valid positions
valid_pos = row1>0 & row1<=size(A,1) & col1>0 & col1<=size(A,2);

%%// Get valid row and column numbers and then valid indices
ind1 = (valid_pos.*col1-1).*size(A,1) + valid_pos.*row1;

%%// Get valid linear indices
ind1 = reshape(ind1',1,numel(ind1)); %%//'
ind1 = ind1(ind1>0);

%%// Find the unique indices without sorting
[~, idxs, ~] = unique(ind1, 'first');
ind1 = ind1(sort(idxs));

%%// Get matrix values from indices and remove the zeros themselves
OUT = A(ind1);
OUT(OUT==0) = [];

Output

OUT =

     2     1     8     1     2     4     5     2     9     8     5     5     8     4     6     5     8     3
like image 33
Divakar Avatar answered Nov 15 '22 05:11

Divakar


Well first, I'm assuming you know about the "find" command: for example topbot=find(abs(zz)==H); finds all the elements of zz which are equal to H and stores them in a long vector, "topbot".

The only unfortunate thing is that it stores matrix locations as a single number, so (3,1) is stored as 3, etc. so if you want the row and column the formula is column = ceiling((number-1)/numrows) and row = number mod numrows (no the syntax isn't right, but you get the idea). (EDIT: Whoops, math is super hard and off by one errors are everywhere)

After that it should just be a matter of removing duplicates and making sure you don't get negative rows or columns.

Finally, matrix values can be called by a single index, so if A is a 8 by 8 matrix, A(15) is the same as the call A(7,2).

like image 32
Anton Avatar answered Nov 15 '22 06:11

Anton