I have a Problem. I have a Matrix A with integer values between 0 and 5. for example like:
x=randi(5,10,10)
Now I want to call a filter, size 3x3, which gives me the the most common value
I have tried 2 solutions:
fun = @(z) mode(z(:));
y1 = nlfilter(x,[3 3],fun);
which takes very long...
and
y2 = colfilt(x,[3 3],'sliding',@mode);
which also takes long. I have some really big matrices and both solutions take a long time. Is there any faster way?
+1 to @Floris for the excellent suggestion to use hist
. It's very fast. You can do a bit better though. hist
is based on histc
, which can be used instead. histc
is a compiled function, i.e., not written in Matlab, which is why the solution is much faster.
Here's a small function that attempts to generalize what @Floris did (also that solution returns a vector rather than the desired matrix) and achieve what you're doing with nlfilter
and colfilt
. It doesn't require that the input have particular dimensions and uses im2col
to efficiently rearrange the data. In fact, the the first three lines and the call to im2col
are virtually identical to what colfit
does in your case.
function a=intmodefilt(a,nhood)
[ma,na] = size(a);
aa(ma+nhood(1)-1,na+nhood(2)-1) = 0;
aa(floor((nhood(1)-1)/2)+(1:ma),floor((nhood(2)-1)/2)+(1:na)) = a;
[~,a(:)] = max(histc(im2col(aa,nhood,'sliding'),min(a(:))-1:max(a(:))));
a = a-1;
Usage:
x = randi(5,10,10);
y3 = intmodefilt(x,[3 3]);
For large arrays, this is over 75 times faster than colfilt
on my machine. Replacing hist
with histc
is responsible for a factor of two speedup. There is of course no input checking so the function assumes that a
is all integers, etc.
Lastly, note that randi(IMAX,N,N)
returns values in the range 1:IMAX
, not 0:IMAX
as you seem to state.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With