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
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)
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
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)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With