|
"Ken Davis" <kendavis@alum.mit.edu> wrote in
news:BED725561618F9A08233BC15D20287BD@in.WebX.raydaftYaTP:
> "AJ "no z" Johnson" <aj.jozhnson@lmco.com> wrote in message
> news:bcd2rg$iur2@cui1.lmms.lmco.com...
>> "Ken Davis" <kendavis@alum.mit.edu> wrote in message
>> news:55F969AE19647F250D8213758BB01024@in.WebX.raydaftYaTP...
>> >
>> > "Larry Schultz" <schultzl@ece.pdx.edu> wrote in message
>> > news:eebf5c2.-1@WebX.raydaftYaTP...
>> > > Hi folks,
>> > >
>> > >
>> > > I need a median filter which works on a 3D array. The bare bones
>> > > version would replace each element in the array with the median
>> > > of the 3x3x3 "cube" that surrounds that element.
>> > >
>> > >
>> > > Here's my SLOOOOOOOOW non vectorized version:
>> > >
>> > >
>> > > %******
>> > > function VM = medfilt3(V);
>> > >
>> > >
>> > > if ndims(V)~=3
>> > > error('V must be a 3D array.');
>> > > end
>> > >
>> > >
>> > > % Pad all around with zeros
>> > > sz = size(V);
>> > > szpad = sz + [2 2 2];
>> > > Vw = zeros(szpad);
>> > > VM = Vw;
>> > > Vw(2:end-1,2:end-1,2:end-1)=V;
>> > >
>> > >
>> > > % Slowly loop through all the elements, performing the filter
>> > > for i = 2:(sz(1)+1),
>> > > for j = 2:(sz(2)+1),
>> > > for k = 2:(sz(3)+1),
>> > > data = Vw((i-1):(i+1),(j-1):(j+1),(k-1:k+1));
>> > > VM(i,j,k)=median(data(:));
>> > > end
>> > > end
>> > > end
>> > >
>> > >
>> > > % Downsize the output
>> > > VM = VM(2:end-1,2:end-1,2:end-1);
>> > > %********
>> > >
>> > >
>> > > Anyone have a suggestion for speeding this up?
>> > >
>> > >
>> > > Thanks,
>> > >
>> > >
>> > > Larry Schultz
>> >
>> > I don't have a solution, but here's how I might start...
>> >
>> > I'd observe that the arrays are stored linearly so that, except at
>> > boundaries, the linear indices of subsequent blocks are offset by
>> > 1. I'd
>> use
>> > this fact to set up an indexing vector to which I'd increment an
>> > offset
> as
>> I
>> > step through the array. I've provided a simple example. You would
>> > have
> to
>> > loop through all the elements, but at least you wouldn't have to do
>> > a complex index calculation each time... It might help.
>> >
>> > You might even find a way to vectorize the whole thing by computing
>> > all
>> the
>> > indices in one giant array, use it to make a giant array with all
>> > your
>> voxel
>> > values and then use median on all the columns at once. Of course,
>> > the
>> tricky
>> > part will be to handle the boundary conditions. You may want to
>> > ignore
> the
>> > issue in your indexing and compute the wrapped-around medians with
>> > all
> the
>> > others and then remove them later.
>> >
>> > In any case, here is a very simplified example.
>> >
>> [snip]
>>
>> In my work with median filters (which can be wonderful for outlier
>> rejection!) the proper way to handle bound conditions is to reflect
>> the
> data
>> about the edges. (I should add that I like have the size of the data
> coming
>> out of a filter equal to the size of the data going into the filter.)
>> e.g. is you input data looks like:
>> [a b c d e f g h]
>> and you have a median filter window size of, say L=5, then reflect
>> (L-1)/2 points as shown:
>> [c b a b c d e f g h g f]
>> and now your filtered data will look like:
>> [median([c b a b c], ...
>> median([b a b c d], ...
>> median([b a b c d], ...
>> median([b a b c d], ...
>> median([b a b c d], ...
>> median([b a b c d], ...
>>
>>
> If you do use wrap around (which is only good for stationary/isotropic
> processes), then you might find this mod1 function helpful for
> indexing:
>
> function z=mod1(x,y)
> %MOD1 Modulo with respect to interval [1, y] instead of interval [0,
> (y-1)]. z = 1 + mod(x-1, y);
>
> if you wanted to use it to wrap around a 5-point data set with an
> extra two points at the boundary, you would use:
>
>>> data = 1:5
>
> data =
>
> 1 2 3 4 5
>
>>> data = data(mod1(-1:7,5))
>
> data =
>
> 4 5 1 2 3 4 5 1 2
>
> Ken
>
>
The reflection described, though, is 3 2 1 2 3 4 5 4 3!
--
Scott
Reverse first field of address to reply
|