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.
MedianFilter
is able to use integers (bytes) while the other two methods effectively work with floating point numbers. We can test onImage[im, "Real"]
. $\endgroup$MedianFilter
operates on each channel separately, I'm unsure whether ImageFilter has the same method for doing that $\endgroup$ColorCombine[MedianFilter[#, 5] & /@ ColorSeparate[im]]
gives me the result I expected) $\endgroup$PrintDefinitions
ing, no luck trying to find the specific behaviour. $\endgroup$