Home > Software design >  How scipy.ndimage.median_filter works for even sizes
How scipy.ndimage.median_filter works for even sizes

Time:07-27

Has someone found/understood how works scipy.ndimage.median_filter for even sizes? Because I tested a lot of theories and tried to read the source code, but I haven't an explanation

(Of course it's better to use odd sizes to avoid shifts, but it's just interesting how exactly median_filter counts it for even numbers...)

Problem definition:

from scipy.ndimage import median_filter
import numpy as np

arr = np.array([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]])
print('Size 3:')
print(median_filter(arr, size=3, cval=0, mode='constant'))
print('Size 2:')
print(median_filter(arr, size=2, cval=0, mode='constant'))
#with cval=0, mode='constant' we set that input array is extended with zeros 
#when window overlaps edges, just for visibility and ease of calculation

Output

Size 3
[[0. 2. 0.]
 [2. 5. 3.]
 [0. 5. 0.]]
Size 2
[[0. 1. 2.]
 [1. 4. 5.]
 [4. 7. 8.]]

As we can see for size 3 all values are like expected, but values for size 2 are not obvious. If suppose that window has shape (2, 2) let's, for example, define and count all possible windows and medians for array element "9". We can cover "9" (or any other value from array) with window of shape (2, 2) in 4 different variants as shown below,

enter image description here

And corresponding median values would be: for red rectangle - 3, yellow - 7, green - 0, blue - 4... But the output value is 8. Even if imagine that afterwards some additional operations are applied to these medians (mean, median etc.), these operation are not obvious.

Interesting fact #1
It seems that for 1d median_filter just takes size-1 (so, odd) number. Example:

arr = np.array([1., 2., 3., 4., 5.])
print('1 - ', median_filter(arr, size=1, cval=0, mode='constant'))
print('2 - ', median_filter(arr, size=2, cval=0, mode='constant'))
print('3 - ', median_filter(arr, size=3, cval=0, mode='constant'))
print('4 - ', median_filter(arr, size=4, cval=0, mode='constant'))
print('5 - ', median_filter(arr, size=5, cval=0, mode='constant'))
print('6 - ', median_filter(arr, size=6, cval=0, mode='constant'))

Output

1 - [1. 2. 3. 4. 5.]
2 - [1. 2. 3. 4. 5.]
3 - [1. 2. 3. 4. 4.]
4 - [1. 2. 3. 4. 4.]
5 - [1. 2. 3. 3. 3.]
6 - [1. 2. 3. 3. 3.]

Interesting fact #2
In general median_filter with even numbers works quite well, blurs images, it's even hard to determine some difference or shifts

CodePudding user response:

In scipy.ndimage.median_filter, a special case occurs when size = 2. Take a look at the source code at enter image description here

Blue window for element "1", sorted [0 0 0 1], the second element of the sorted array - 0
Red window for element "2", sorted [0 0 1 2], the second element of the sorted array - 1
Green window for element "3", sorted [0 0 2 3], the second element of the sorted array - 2
And so on... So, the first raw of the output array [0, 1, 2]

Now answers match the output!

  • Related