Search code examples
matlabfilteringmodelarge-data

Mode filter for large matrices


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!


Solution

  • 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