2D sliding/moving/running average window

129 vues (au cours des 30 derniers jours)
Albert Zurita
Albert Zurita le 30 Juil 2022
Commenté : Bruno Luong le 25 Août 2022
Hello, I want to perform a matrix 'patch' moving average but I am not sure how to. So, for example, defining my moving window as 3 x 3. I would like, for each element in the matrix, to perform the average of the elements as in the sequence below (excerpt) for an exemplary 6 x 10 matrix. I know this can be done more efficiently through the use of conv2 or in frequency domain with fft2, using the window kernel, but I still want to do it with a for loop, as this will be later translated to another real time language code. In addition, I would like to be able to select the elements as a 1D array (a reshape of the n_rows, n_cols matrix). At the edges of the matrix I select the next row, so it probably makes more sense to do it as a 1D array. Finally, when reaching the end of the matrix I can only select a few elements in the corner, but in this case I will do the average just of those elements.
thanks!!
  2 commentaires
Matt J
Matt J le 30 Juil 2022
I know this can be done more efficiently through the use of conv2 or in frequency domain with fft2, using the window kernel, but I still want to do it with a for loop
It sounds like you already know how you're going to do it, so there doesn't seem to be a question here.
Albert Zurita
Albert Zurita le 30 Juil 2022
Yes, but I don't know how to select the elements, and especially given the 'corners' effect problem...

Connectez-vous pour commenter.

Réponse acceptée

Bruno Luong
Bruno Luong le 30 Juil 2022
Modifié(e) : Bruno Luong le 30 Juil 2022
Just some hint if your want to implement efficiently using loop :
  1. To do mean, you might do sliding sum onf the data, then divide by sliding sum on the array of size data but values are replaced with 1s (ones(size(data)).
  2. The sliding 2D sum is "separable" meaning you just need to do sliding sum along one dimension, and apply the sliding sum along other dimension.
  3. The sliding sum in 1D can be donne efficiently by simply adding sum of the previous step with the new entry element and substract the one that exits the window. If ther data is "quantified" such as multiples of the 2^power something, this method does not have cumulative error, otherwise you might have a small cumulative error compared to standard sum on the whole windows.
  20 commentaires
Bruno Luong
Bruno Luong le 25 Août 2022
Modifié(e) : Bruno Luong le 25 Août 2022
"Apad matrix does not seem to pad the number of columns correctly."
Sorry but You still get it wrong again. The correct is
Apad = [[nan(1,win(2)-1); ...
A(1:end,end-win(2)+2:end)], ...
[A; nan(1,size(A,2))], ...
[A(2:end,1:win(2)-1); ...
nan(2,win(2)-1)]];
Bpad = slidingmean(Apad, win);
B = Bpad(1:end-1,win(2):size(A,2)+win(2)-1);
Up to know you only specify the wrap around on the horizontal direction, so only win(2) matter.
You might expect something different now, and I again insist that you must pad according whatever the weird wrap around you want. It's up to you to change the pad if you change the wrap shiftting that beside you nobody know.
Bruno Luong
Bruno Luong le 25 Août 2022
Also you might change some of the hard-code first index
nan(1, ...
A(2:...
Bpad(1:end-1 ...
with expression using win(1)

Connectez-vous pour commenter.

Plus de réponses (2)

David Hill
David Hill le 30 Juil 2022
a=randi(100,15);%whatever initial size of your matrix
b=size(a,1);
m=zeros(b);
for x=1:b^2
idx=[x-b-1,x-1,x+b-1;x-b,x,x+b;x-b+1,x+1,x+b+1];
if idx(2,3)>b^2
idx(:,3)=[];
end
if mod(idx(3,2),b)==1
idx(3,:)=[];
end
if idx(2,1)<1
idx(:,1)=[];
end
if mod(idx(1,2),b)==0
idx(1,:)=[];
end
m(x)=mean(a(idx),'all');
end
  3 commentaires
Image Analyst
Image Analyst le 24 Août 2022
Albert, did you even see my answer below? Please read it. It does what you asked. You can specify the image file and window size and is 100% manual (non-vectorized). At least give it a try even if you prefer Bruno's answer (which has vectorized indexing).
Albert Zurita
Albert Zurita le 25 Août 2022
Yes, please see my comment to your reply below

Connectez-vous pour commenter.


Image Analyst
Image Analyst le 31 Juil 2022
Modifié(e) : Image Analyst le 24 Août 2022
See my attached "manual" convolution demo. It lets you pick a standard demo image (converts to gray scale if necessary) and then asks you for the number of rows and columns in the scanning filter window (kernel). Then it has a 4-nested for loop where it sums the image pixel times the kernel value. It also counts the number of pixels in the kernel that overlap the image so in essence it shrinks the window when it "leaves the image" by ignoring those pixels. So if the 3x3 kernel is centered over (1,1) only 4 pixels are considered rather than the full 9 because 5 pixels are off the image and don't overlap. The input image and output image are displayed side by side. It does not use any MATLAB convolution functions or vectorized indexing to get any of the pixels in the window so it's completely 100% manual.
  1 commentaire
Albert Zurita
Albert Zurita le 25 Août 2022
Hi, indeed your proposal looks very good. The only issue is the 'circular smooth' that Bruno has implemented as per my original post. Since there is some sort of similarity between the end of one row and the start of the next one Bruno creates that padded matrix. Perhaps your code could be adapted to work with the padded matrix, but the indexing should be changed.

Connectez-vous pour commenter.

Catégories

En savoir plus sur Images dans Help Center et File Exchange

Produits


Version

R2022a

Community Treasure Hunt

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

Start Hunting!

Translated by