How to divide a 2d array into blocks and create an array with the mean value of each block?

조회 수: 9 (최근 30일)
Here's an 4x8 array.Three of its values are NaNs:
B=zeros(4,8);
B(1,:) = [1 3 4 3 10 0 3 4];
B(2,:) = [5 7 2 NaN 8 2 3 4];
B(3,:) = [8 4 6 2 NaN 3 5 7];
B(4,:) = [2 2 5 5 1 NaN 4 4];
I want to divide the array into 2x2 blocks and form a new array 'C' that is the mean of each block. If the block contains one or more NaNs, I want to find the average of the numbers that are not NaNs. In this example, I would like the following output:
C =
4.0000 3.0000 5.0000 3.5000
4.0000 4.5000 2.0000 5.0000
I tried the code below but it just returns a NaN if any of the block elements are NaN. How should I amend this, please?
C=blockproc(B, [2 2], @(block_struct) mean(block_struct.data(:)))
C =
4.0000 NaN 5.0000 3.5000
4.0000 4.5000 NaN 5.0000

채택된 답변

Jan
Jan 2022년 5월 26일
편집: Jan 2022년 5월 26일
B = [1 3 4 3 10 0 3 4; ...
5 7 2 NaN 8 2 3 4; ...
8 4 6 2 NaN 3 5 7; ...
2 2 5 5 1 NaN 4 4];
B = repmat(reshape(B, 1, 4, 8), 10, 1, 1); % The test data
% Code without BLOCKPROC:
N = ~isnan(B); % Mask for the NaNs
S = size(B);
T = [S(1), 2, S(2)/2, 2, S(3)/2];
BB = reshape(B .* N, T); % Set NaNs to 0
NN = reshape(N, T);
R = sum(BB, [2, 4]) ./ sum(NN, [2, 4]); % Sum over 2x2 blocks
R = reshape(R, T([1,3,5])); % Remove singelton dimensions
  댓글 수: 2
Steve Francis
Steve Francis 2022년 5월 26일
Thanks, Jan. Is the advantage of this method (a) speed and (b) for users without the image processing toolbox? Is there any other disadvantage in using blockproc?
Jan
Jan 2022년 5월 27일
You are welcome. I do not have the image processing toolbox, so I use solutions without blockproc.
The method shown above is fast and more flexibel, if the inputs are no 2D or 3D RGB arrays and the blocks are built on the 1st 2 dmensions. Instead of ~isnan() other masks can be defined. blockproc is more powerful, when specific functions are applied to the blocks, but power costs processing time.
See also: https://www.mathworks.com/matlabcentral/fileexchange/24812-blockmean (no masking of NaNs impelemented, frist 2 dimensions processed also, dimensions do not need to be a multiple of the window size)

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

David Hill
David Hill 2022년 5월 26일
C=blockproc(B, [2 2], @(block_struct) mean(block_struct.data(:),'omitnan'))
  댓글 수: 2
Steve Francis
Steve Francis 2022년 5월 26일
Thanks for this @David Hill. Just to widen the question, if B was a 10x4x8 array (i.e. 10 'layers' of 4x8 arrays), I could create a corresponding C (10 layers of 2x4 arrays) using the following code.
C = zeros(10, 2, 4);
for n=1:10
C(n,:,:) = blockproc(squeeze(B(n,:,:)), [2 2], @(block_struct) mean(block_struct.data(:),'omitnan'));
end
Is there a way to do it without the 'for' loop?
Steve Francis
Steve Francis 2022년 5월 27일
David's solution directly answered my original question. Jan's answer introduced me to an intriguing alternative. Thanks to both.

댓글을 달려면 로그인하십시오.

제품


릴리스

R2020a

Community Treasure Hunt

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

Start Hunting!

Translated by