Fast average calculation of submatrices in large matrix

13 次查看(过去 30 天)
Hi,
I have a matrix M=1024x512 elements. What I would like to do is to calculate the average of every submatrix of a size of 4x4 and assign that average to all the elements in that submatrix. Then move on to the next submatrix and do the routine all over again. I have managed to do this by two for loops, but the problem is that I have lots of matrices of this size and this routine is very slow. How can I speed up this calculations? I have the impression that the use of for loops isn't that quick at all :(.
This is the code I used:
for i = 1:4:(1024-4)
for j = 1:4:(512-4)
average = mean(mean(M(i:(i+4-1),j:(j+4-1))));
M(i:(i+4-1),j:(j+4-1)) = average;
end
end
Your help would greatly be apreciated!

采纳的回答

Andrei Bobrov
Andrei Bobrov 2013-5-24
编辑:Andrei Bobrov 2013-5-24
PART 1
use function blockproc from Image Processing Toolbox
a1 = blockproc(M,[4,4],@(x)mean2(x.data))
or without blockproc, but with conv2
a1 = conv2(M,ones(4)/16,'valid');
a1 = a1(1:4:end,1:4:end); %CORRECT
or with cellfun
a1 = cellfun(@mean2,mat2cell(M,4*ones(size(M,1)/4,1),4*ones(size(M,2)/4,1)));
average = kron(a1,ones(4));
or
average = cell2mat(arrayfun(@(x)x*ones(4),a1,'un',0));
ADD
average = conv2(M,ones(4)/16,'valid');
  7 个评论
Stijn
Stijn 2013-6-11
can I use blockproc to shift one element in stead of a whole block?

请先登录,再进行评论。

更多回答(4 个)

Matt J
Matt J 2013-5-24
编辑:Matt J 2013-5-24
This will be faster than BLOCKPROC,
kernel=ones(1,4)/4;
M=conv2(kernel, kernel, M,'valid');

Azzi Abdelmalek
Azzi Abdelmalek 2013-5-24
To improve the speed of your code two times:
for i = 1:4:(1024-4)
for j = 1:4:(512-4)
v=M1(i:(i+4-1),j:(j+4-1));
M1(i:(i+4-1),j:(j+4-1)) =mean(v(:));
end
end

Stijn
Stijn 2013-6-11
编辑:Stijn 2013-6-11
I want to expand this question a bit. It is in the line of the previous problem, only I would like to do the following:
Suppose I have the following matrix:
m=[1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25]
What i would like to establish here is a some kind of moving average. Instead of jumping ahead with a submatrix of 3x3, I want to move only 1 element forward at the time and calculate the average again and store it a different matrix. To be more clear, suppose you pick an element (say m(2,2)), I want to get an average around that element by averaging the elements m(1:3,1:3), thus go 1 element to each side to get a average vlue of the 3x3 submatrix. (If you use 2 elements to each side you will get an average of a 5x5 submatrix). Only elements on the edges of the matrix are calculated differently.
The matrix would than be obtained like this (I hope this image clarifies it a bit)
  1 个评论
Andrei Bobrov
Andrei Bobrov 2013-6-12
m = [1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25];
[a b] = size(m);
c = true([a b]);
c(2:end-1,2:end-1) = false;
ii = bsxfun(@plus,[0 (b-1)*a],[1;a]);
d = c*6;
d(ii) = 4;
out = conv2(m,ones(3)/9);
out(c) = out(c)*9./d(d>0);

请先登录,再进行评论。


Jan
Jan 2013-7-26
With the C-Mex FEX: BlockMean:
D = rand(1024, 512);
M = BlockMean(M, 4, 4);
M = kron(M, ones(4, 4));

类别

Help CenterFile Exchange 中查找有关 Creating and Concatenating Matrices 的更多信息

Community Treasure Hunt

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

Start Hunting!

Translated by