Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matlab fast neighborhood operation

Tags:

filter

matlab

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?

like image 667
user2441536 Avatar asked Jun 01 '13 09:06

user2441536


1 Answers

+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.

like image 144
horchler Avatar answered Sep 28 '22 03:09

horchler