I am trying to filter some 4672 by 3001 matrices with values of 0 and 1 by finding the most common value in a given window size. I.e. finding the mode in a window around each pixel. A solution is to use
colfilt(A,[3 3],'sliding',@mode)
The below link shows a solution that is very much faster for a window size of [3 3].
Matlab fast neighborhood operation
However, when I try to increase the window size (say to [9 9]) this solution becomes very slow.
Is there an alternative to do the filtering with a larger window size?
Thanks a lot!
So you have a matrix of zeros and ones, and you want to know, within each sliding block, if there are more zeros or more ones. Let m
and n
denote the number rows and columns per block.
The following does what you want using conv2
. It essentially computes the 2D convolution with the kernel ones(m,n)
, which gives the sum of all values within each block. That sum is compared to the threshold m*n/2
to know if in that block there were more zeros or ones.
Since the convolution kernel ones(m,n)
is separable, the 2D convolution can be replaced by a convolution with the column vector ones(m,1)
followed by a convolution with the row vector ones(1,n)
. This results in faster code.
A = randi(2,7,7)-1; %// example matrix with zeros and ones
m = 3; %// number of rows in a block
n = 2; %// number of cols in a block
B = conv2(ones(m,1),ones(1,n),A,'same')>m*n/2; %// result
In case of a tie this produces a 0
result. To produce 1
instead, change >
into >=
.
Also, you might want to change 'same'
into 'valid'
to consider only full blocks.
Compared to colfilt
, this gives a significant speed gain:
>> A = randi(2,4672,3001)-1;
>> m = 3; n = 3;
>> tic, B1 = colfilt(A,[m n],'sliding',@mode); toc
Elapsed time is 13.874891 seconds.
>> tic, B2 = conv2(ones(m,1),ones(1,n),A,'same')>m*n/2; toc
Elapsed time is 0.206820 seconds.
>> all(all(B1==B2))
ans =
1