Image / Matrix binning with sum of each bin

Hi,
I'm trying to downsample an image/matrix by binning.
What I want to achieve is that each output pixel would be the sum of it's parts.
From what I understood, using the imresize would only be possible with some kind of weighted average and not summing.
Is there a bulit in function that would allow for binning with summing?
If not, what would be the best approach to do that?
Thanks!
O.

 Risposta accettata

Avoiding any sort of weighting suggests to me that this is strictly integer-factor downsampling. If that's the case, then one way might be something like this.
blocksize = [2 2]; % downsampling ratio [h w]
A = ones(10) % test array (geometry must be integer-divisible by blocksize)
A = 10×10
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
B = mat2cell(A,repmat(blocksize(1),[1 size(A,1)/blocksize(1)]),...
repmat(blocksize(2),[1 size(A,2)/blocksize(2)]));
B = cellfun(@(x) sum(x,'all'),B)
B = 5×5
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4

6 Commenti

omri r
omri r il 5 Gen 2022
Modificato: omri r il 5 Gen 2022
Thank you very much!
Does using mat2cell is the best approach in terms of speed performance?
I want to down sample a matrix ~3000X3000 elements.
Probably not. As I mentioned, this approach also limits you to integer scalings only.
Depending on your needs, you may be able to do other things. It might be cheaper to just use imresize and correct for the change in area. This would also work for non-integer factor scalings if that's desired.
A = ones(12)
A = 12×12
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
outsize = [3 4]; % size of the output array
C = imresize(A,outsize,'bilinear')*prod(size(A)./outsize)
C = 3×4
12 12 12 12 12 12 12 12 12 12 12 12
[sum(A,'all') sum(C,'all')]
ans = 1×2
144 144
I'm not really sure if the antialiasing filter is going to cause you problems, but it can be disabled.
Thank you!
The imresize is much faster and works quite good for my needs.
Examine it more, it seems that the imresize is not realy summing, but averaging and then multipy with constant number.
So in fact it does not do the summing I want.
Going back to the mat2cell approach, since the performance is low, is it possible to replace it with reshpae+permute in some way? (In which the performance sholud be better)
It always takes me forever to make reshape do what I want, but this might work.
A = kron([1 3 5; 2 4 8; 3 6 9],ones(2)) % makes it easy to follow the numbers
A = 6×6
1 1 3 3 5 5 1 1 3 3 5 5 2 2 4 4 8 8 2 2 4 4 8 8 3 3 6 6 9 9 3 3 6 6 9 9
s = size(A);
bs = [2 2]; % blocksize
B = reshape(A.',bs(1),s(1)/bs(1),[]);
B = reshape(permute(B,[1 3 2]),bs(1),bs(2),[]);
B = sum(sum(B,1),2);
B = reshape(B,s./bs)
B = 3×3
4 12 20 8 16 32 12 24 36
That should be quite a bit faster than using cell operations, even if it's pretty opaque to read.
omri r
omri r il 6 Gen 2022
Modificato: omri r il 6 Gen 2022
Thank you very much!
I found another way.
Seems even a bit faster for larege matrices (~2000x2000):
(BTW, that is matters in terms of performance single/multi line codes?)
A = 1:2100^2;
A = reshape(A,2100,[]);
binSize = 3;
% multi line code
tic
C = reshape(A,binSize,[]);
C = sum(C);
C = reshape(C,size(A,1) / binSize,[]);
C = C';
C = reshape(C,binSize,[]);
C = sum(C);
C = reshape(C,size(A,2) / binSize,[]);
C = C';
% combined line code
C = sum(reshape(A,binSize,[]));
C = reshape(C,size(A,1) / binSize,[])';
C = sum(reshape(C,binSize,[]));
C = reshape(C,size(A,2) / binSize,[])';

Accedi per commentare.

Più risposte (0)

Categorie

Prodotti

Release

R2021a

Richiesto:

il 5 Gen 2022

Modificato:

il 6 Gen 2022

Community Treasure Hunt

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

Start Hunting!

Translated by