Meet the Neighbors
Some calculations in MATLAB, including, for example, calculating local means or finite differences, or applying some other filter locally, operate on neighboring matrix elements. Doing so in an efficient manner is easy under the right conditions with MATLAB. Steve talked about neighbor indexing on his blog a few years ago.
Contents
Linear Indexing
I've talked about indexing a bunch of times previously if you want to read about the topic from different vantages. For now, let me remind you what linear indexing is.
MATLAB stores data column-wise. That is, each column of data is stacked below the previous one in a contiguous block of memory. If I have this matrix A
A = [ 1 3 5; 2 4 6]
A = 1 3 5 2 4 6
I can address the element in the 1st row, 2nd column via subscripts.
A(1,2)
ans = 3
I can also extract this element by indexing as if A was strictly a column vector. And then I could extract the same element with what we call _linear indexing.
A(3)
ans = 3
There are functions to convert between subscripts and linear indicies. Take a look at sub2ind and ind2sub.
I can also do the conversion from subscript to linear index easily myself. For a 2-D array, I simply need to know how many rows the matrix has.
nrows = size(A,1)
nrows = 2
Suppose now I have a larger matrix and I want to address some of the neighbors of a given element, located at (row,column), corresponding to linear index linidx. As long as the element is not too near an edge of the matrix, I can think about neighbors as offsets in different directions. So, the neighbor to the south of this element corresponds to (row+1,column), or linear indexing terms, linidx+1.
Table of Offsets
Here's a table of neighbor offsets for the 4 elements adject to element and not on the diagonals.
- S = ind+1
- N = ind-1
- E = ind+nrows
- W = ind-nrows
So you can easily see the correspondence, I am creating a matrix with values that are the numbers 1:30 arranged so they appear in ascending order when looked at as a 1-D vector.
nrows = 5; ncolumns = 6; B = reshape(1:30,nrows, ncolumns)
B = 1 6 11 16 21 26 2 7 12 17 22 27 3 8 13 18 23 28 4 9 14 19 24 29 5 10 15 20 25 30
If I want to find the neighbors for elements (2,4) and (3,2), I can do so in a vectorized way.
linPairs = sub2ind(size(B), [2 3], [4 2])
linPairs = 17 8
If I want the points east of these, I simply add nrows.
eastVals = B(linPairs+nrows)
eastVals = 22 13
Caution
The one cautionary comment is that you must be very sure you aren't going to go past an edge boundary from your elements of interest. If you do, you will either go outside the bounds of your array or pick up a value that wrapped around to the next row or column. If there's danger of that, you may want to pad your initial array before doing your neighbor operations, and then peel the padding back off when you are finished.
Do Your Calculations Require Addressing Neighbors?
What's your experience working with neighbors? Let me know here. Beware the edges
- Category:
- Indexing