Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

How to average a multidimensional array with surroundings

Asked by Evan on 14 Mar 2013

Hello

Say I have a 3x3 array. I want to average the values dim1 and dim2 so that the center value is the average of the center value, value above and below, and value left and right, but not the values diagonal. The same applies for all values, except in the case of the edges, the mirror values should be used: for example, on the left side, the right values are the center column, and the left side values should also be the center column because a mirror image is imposed. The same should apply for the above and below values. To clarify, when no value for averaging is present, use the mirror value.

So for example, on value (1,1), the average would be (1,1), 2 * (1,2), and 2 * (2,1) because the left and top values have to be mirror values. The center value (2,2) is the average of (2,2), (1,2), (2,1), (2,3), (3,2). Hope this clarifies the issue.

Now, take this concept and use it on 5 x 4 arrays. And now take it even further and use it on multidimensional arrays like 10 x 9 x 8, or 120 x 200 x 300 x 5.

Is there an easy algorithm for this?

Thank you

0 Comments

Evan

Products

No products are associated with this question.

2 Answers

Answer by Andrei Bobrov on 14 Mar 2013
Edited by Andrei Bobrov on 14 Mar 2013
k = reshape(1:9,3,[]) % your array
k1 = [k(:,2),k,k(:,end-1)];
k1 = [k1(2,:);k1;k1(end-1,:)]
out = conv2(k1,[0 1 0;1 1 1;0 1 0]*.2,'valid')

for 3-D arrays use convn

0 Comments

Andrei Bobrov
Answer by Teja Muppirala on 14 Mar 2013
Edited by Teja Muppirala on 14 Mar 2013

This would be much simpler if it were not for that weird edge case. Anyways, this is how you would do it in the case of an arbitrary sized matrix:

A = rand(3,4,5,6); %<-- Your input matrix of any size
d=ndims(A);
C = cell(1,d);
[C{:}] = ndgrid([1 0 1]);
K = sum(cat(d+1,C{:}),d+1) <= 1;
K = K/nnz(K); %<-- Get the convolution kernel
% Reflect the edges for each dimension
Ac = A;
for n = 1:d
    sz = size(A,n);
    edge1 = [repmat({':'},1,n-1) {2} repmat({':'},1,d-n)];
    edge2 = [repmat({':'},1,n-1) {sz-1} repmat({':'},1,d-n)];
    Ac = cat(n,Ac(edge1{:}), Ac, Ac(edge2{:}));
end
% Do the calculation
B = convn(Ac,K,'valid') %<-- Your answer
clear('Ac'); %<-- Don't need this anymore

3 Comments

Evan on 15 Mar 2013

How about a function f(data, shift) where data is matrix of any size, and shift is how much to convolve - that is, if shift = 1, then average just 1 value up,down,left,right (not diagonal), but is shift = 2, then average both values up, both values down, both values left, both values right, but not diagonal?

Thanks!

Evan on 15 Mar 2013

Actually, I guess not doing the diagonal is not so important.

Evan on 20 Mar 2013

The code works perfectly. Is there a way to edit this code so that I can specify "n", where n is the number of values to average over? So the default in this code is n = 1, where 1 value top/bottom/left/right/etc are averaged. But what if I want to average 2 (n = 2) so that I average the value itself, the value above, the value above that value, the left value, value 2 left, value 1 right, value 2 right, etc?

What if 3? Is there a function that you can make like this? Thank you

Teja Muppirala

Contact us