Averaging every element with nearby elements

16 ビュー (過去 30 日間)
Perturabo
Perturabo 2019 年 2 月 13 日
コメント済み: Perturabo 2019 年 2 月 15 日
I want to average each element of an m by n matrix with surrounding w elements, for example, if w = 1, the element would be the mean of the 3x3 submatrix with the element in the middle, i.e, if the matrix is
a = [1:10;2:11;3:12;4:13;5:14;6:15;7:16]
and w = 1, each element would be average of nearby eight elements and itself.
I tried using 3 loops, i = 1:w, 1 = w+1:end-w, i = end-w+1:end, but there must be a quicker way to do this.
  3 件のコメント
Perturabo
Perturabo 2019 年 2 月 13 日
for a smaller matrix
a = [1:4;2:5;3:6]
output = [2,2.53.5,4;3,2.67,4,5;3,3.5,4.5,5]
John D'Errico
John D'Errico 2019 年 2 月 13 日
I don't think you were that careful in how you computed your example. Or if you were, then you need to explain far better what you want.

サインインしてコメントする。

採用された回答

John D'Errico
John D'Errico 2019 年 2 月 13 日
編集済み: John D'Errico 2019 年 2 月 13 日
A simple solution is to use conv2. It works quite well inside the domain. But then you will need to be careful around the edges. However, that is quite easily fixed. Even trivial, once you see the trick. All it requires is TWO calls to conv2. Lets see how this trick works. First, I'll do it the wrong way, and we can see what happens.
A = magic(5)
A =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Now lets use w = 1. So 1 element in each direction. That means we need to use a convolution kernel that is 3x3.
w = 1;
K = ones(2*w+1)/(2*w+1)^2;
K
K =
0.11111 0.11111 0.11111
0.11111 0.11111 0.11111
0.11111 0.11111 0.11111
So the convolution kernel is just an array that forms anaverage at every point. If w were 2, then each element would be 1/25, or 0.04.
Aave = conv2(A,K,'same')
ans =
7.6667 8.5556 6.5556 6.7778 5.8889
8.7778 11.111 10.889 12.889 10.556
6.6667 11 13 15 10.667
6.7778 13.111 15.111 14.889 8.5556
5.6667 10.556 10.778 8.7778 3.8889
If we look at the inside elements of the array Aave, say the (2,2) element, it should be 11.111, thus
mean(mean(A(1:3,1:3)))
ans =
11.111
So that worked. If I had used the valid option for conv, then every element computed would have been correct.
But what is Aave(1,1)? For that, we need to do it as:
mean(mean(A(1:2,1:2)))
ans =
17.25
and we got 7.6667 instead. The problem is, conv2 substitues 0 in for the elements that fell outside. So all of the edge elements in the average will be wrong. You COULD fix it, by going back afterwards, then patching those edge elements that were wrongly computed. But then you need to be careful with the elements at or near the corner. It gets worse if w is 2 or 3, because then when what is near the edge gets more complex. There is a trick however that works VERY nicely.
Are you seeing the trick now that I will use? I said you need to do TWO calls to conv2.
What would happen if you wrote the convolution kernel as
K = ones(2*w+1);
Aave = conv2(A,K,'same')./conv2(ones(size(A)),K,'same')
Aave =
17.25 12.833 9.8333 10.167 13.25
13.167 11.111 10.889 12.889 15.833
10 11 13 15 16
10.167 13.111 15.111 14.889 12.833
12.75 15.833 16.167 13.167 8.75
Think about why this works. It is a neat trick that is applicable in multiple circumstances. The first call to conv2 is a SUM. Then the second call to conv counts how many elements were involved with that sum. When you divide them, you get a mean, thus the average as desired.
It clearly applies for larger values of w too.
It even works for a 1-dimensional array, although then it may make more sense to use two calls to conv instead of conv2.
  1 件のコメント
Perturabo
Perturabo 2019 年 2 月 15 日
That's a neat trick. Thanks for the help.

サインインしてコメントする。

その他の回答 (1 件)

KSSV
KSSV 2019 年 2 月 13 日
Read about knnsearch. With this you can get your desired number of nearest neighbors indices.....with the indices you can get your mean.

カテゴリ

Help Center および File ExchangeMatrix Indexing についてさらに検索

製品


リリース

R2018a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by