# Is there something wrong with MedianFilter?

Note: Wolfram Support confirmed that the behaviour of MedianFilter is as intended, but the description in the documentation in incorrect. M11.1 and earlier have the correct description:

For multichannel images, MedianFilter[image,...] replaces each pixel by a pixel in its neighborhood that has the median total intensity, averaged over all channels.

Original post:

MedianFilter does not give the result I expect, or the result I computed using other methods. Is it buggy?

Example:

im = ExampleData[{"TestImage", "Sailboat"}];

m1 = MedianFilter[im, 5]


Look at the pepper-like pinkish noise at the middle of the image. I'd expect a median filter to give a smooth result.

Let's implement median filtering through ImageFilter.

m2 = ImageFilter[Median@*Flatten, im, 5]


It looks much better. I have a small personal library to access SimpleITK. Let's try that.

m3 = obj@"median"[im, 5]


Not only does the ITK result look identical to the ImageFilter result, it is identical, as confirmed with ImageAdjust[m2-m3]. m1 is quite different, even in the middle (differences near edges could be due to different padding).

What's going on? Why does MedianFilter give a different result than other methods of computing the same? As far as I can tell, the neighbourhood range specification works identically for all three methods: 5 means using an 11 by 11 rectangle window.

Is there a bug?

Update: I am now convinced that this is a bug because if I manually filter each channel separately with MedianFilter, I get the expected result (the same as with ImageFilter and ITK, except around the edges).

ColorCombine[MedianFilter[#, 5] & /@ ColorSeparate[im]]


The documentation says that it should operate separately on each channel of multi-channel images.

• For multichannel images and audio signals, MedianFilter operates separately on each channel.

But it clearly doesn't.

Update 2: It seems like it's not a bug after all (rather a documentation bug). As Niki says, there are ways to compute a "colour median", e.g. sort the neighbourhood pixels based on their luminance and pick the "middle one". One possible direct implementation of this is

ImageFilter[
With[{flat = Join @@ #},
SortBy[flat, {0.299, 0.587, 0.114}.# &][[Round[Length[flat]/2]]]
] &,
im, 5, Interleaving -> True
]


which gives a comparable but non-identical result.

• I did test that this is not because MedianFilter is able to use integers (bytes) while the other two methods effectively work with floating point numbers. We can test on Image[im, "Real"]. – Szabolcs Aug 27 '18 at 12:12
• MedianFilter operates on each channel separately, I'm unsure whether ImageFilter has the same method for doing that – Carl Lange Aug 27 '18 at 12:23
• @CarlLange It should operate on each channel separately, but it does not (I just tested that ColorCombine[MedianFilter[#, 5] & /@ ColorSeparate[im]] gives me the result I expected) – Szabolcs Aug 27 '18 at 12:25
• Ah, very good. That's a weird one! Unfortunately I hit a dead end after a bit of PrintDefinitionsing, no luck trying to find the specific behaviour. – Carl Lange Aug 27 '18 at 12:36

This looks like a documentation bug. Apparently, MedianFilter doesn't process each channel separately. Instead, it applies a proper color median filter, like e.g. the one from the IPP. Example:

img = Image[
Table[
Mod[i*84 + j*83 + {0, 85, 170}, 255], {i, 16}, {j, 16}], "Byte"]


And the median filter results:

The per-channel median is more or less gray. But there isn't a single gray pixel in the image. MedianFilter always seems to choose an RGB value from the filter window, i.e.:

ContainsAll[Union[Flatten[ImageData[img], 1]],
Union[Flatten[ImageData[MedianFilter[img, 3]], 1]]]
`

True

• "the one from the IPP" link is broken. I need to look up how a colour median works. Could you perhaps provide a reference? – Szabolcs Aug 27 '18 at 12:59
• I found the answer (I did not know what IPP was). software.intel.com/en-us/ipp-dev-reference-filtermediancolor – Szabolcs Aug 27 '18 at 13:11
• I tried to fix the link, please edit if incorrect. However, I have to say that the "median" concept described in that link is quite different from the usual statistical meaning. I find it misleading that MedianFilter does this by default, especially considering that it can also operate on arrays, time series and audio, where (I assume) it uses the usual median. – Szabolcs Aug 27 '18 at 13:11
• This page has a more reasonable idea of how a colour median might work: itk.org/ITKExamples/src/Filtering/Smoothing/… It simply needs a comparison operator. – Szabolcs Aug 27 '18 at 13:27
• @Szabolcs: The common statistical definition for the median is that it's the value that minimizes the L1 distance metric. That's exactly what the IPP median function does, isn't it? (I only skimmed it, to be honest) – Niki Estner Aug 27 '18 at 13:30