scipy.ndimage.median_filter如何处理偶数大小的图像

7rtdyuoh  于 2022-11-10  发布在  其他
关注(0)|答案(2)|浏览(145)

有人发现/理解了scipy.ndimage.median_filter对于偶数大小是如何工作的吗?因为我测试了很多理论,并试图阅读源代码,但我没有一个解释
(Of当然,最好使用奇数大小以避免移位,但有趣的是median_filter如何准确地计算偶数的大小...)
问题定义:

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

输出量

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

如我们所见,size 3的所有值都与预期值相同,但size 2的值并不明显。例如,假设窗口形状为(2,2),让我们定义并计算数组元素“9”的所有可能窗口和中值。我们可以用形状为(2,2)的窗口覆盖“9”(或数组中的任何其他值),具体有4种不同变体,如下所示:

相应的中值为:为红色矩形-3、黄色-7、绿色-0、蓝色-4......但输出值为8。即使设想在此之后对这些中值应用一些附加运算(平均值、中值等),这些运算也不明显。
有趣的事实#1
看起来,对于1d median_filter,仅取size-1(因此,奇数)数。示例:

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'))

输出量
有趣的事实#2
一般情况下,使用偶数的中值滤波器效果很好,但会使图像模糊,甚至很难确定一些差异或偏移

iswrvxsc

iswrvxsc1#

在scipy.ndimage.median_filter中,当size = 2时会出现一种特殊情况。https://github.com/scipy/scipy/blob/v1.8.1/scipy/ndimage/_filters.py#L1351-L1396
中值滤波器调用函数_rank_filter,可在此处找到:https://github.com/scipy/scipy/blob/4cf21e753cf937d1c6c2d2a0e372fbc1dbbeea81/scipy/ndimage/_filters.py#L1244
在函数中,您将找到代码:

if rank < 0:
    rank += filter_size
if rank < 0 or rank >= filter_size:
    raise RuntimeError('rank not within filter footprint size')
if rank == 0:
    return minimum_filter(input, None, footprint, output, mode, cval,
                          origins)
elif rank == filter_size - 1:
    return maximum_filter(input, None, footprint, output, mode, cval,
                          origins)

此外,在前面的函数rank=size//2中。
在这种情况下,程序执行的是最小值滤波器,而不是真正的中值滤波器(将涉及求平均值)。
条件rank==0rank==size-1都为真,但控制流优先考虑rank==0,它对应于代码中的最小过滤器。
大小〉=4可能会有不同的效果。

tf7tbtn2

tf7tbtn22#

多亏了Michael Sohnen的回答,现在我明白了它是如何工作的!
我将在我的问题中针对size=2的“问题定义”中的示例逐步描述计算过程
由于源代码https://github.com/scipy/scipy/blob/4cf21e753cf937d1c6c2d2a0e372fbc1dbbeea81/scipy/ndimage/_filters.py#L1244-L1307
1.首先,footprintsize计算得出。在我们的例子size=2中,footprint将是一个用True填充的形状为(2,2)的数组(第1252-1258行)。
1.然后,计算filter_size(第1267行)

filter_size = numpy.where(footprint, 1, 0).sum()

numpy.where(footprint, 1, 0)在数组元素为True时返回1,在数组元素为False时返回0,所有占用空间元素均为True,这意味着filter_size等于4
1.计算rank(第1268-1279行)

if operation == 'median':   <---- our case
  rank = filter_size // 2

这意味着在我们的例子中秩等于2
1.找到适当的条件(第1280-1307行)

if rank < 0:                            #<---- not our case
      rank += filter_size
  if rank < 0 or rank >= filter_size:     #<---- not our case
      raise RuntimeError('rank not within filter footprint size')
  if rank == 0:                           #<---- not our case
      return minimum_filter(input, None, footprint, output, mode, cval,
                    origins)
  elif rank == filter_size - 1:           #<---- not our case
      return maximum_filter(input, None, footprint, output, mode, cval,
                    origins)
  else:                                   #<---- our case!
      ...
      _nd_image.rank_filter(input, rank, footprint, output, mode, cval,
                    origins)
      ...

所以rank_filter将被应用到数组中。秩过滤器是如何工作的?
它对给定窗口中的值进行排序,然后从排序后的数组中取一个索引为rank的元素。

4 3 
2 1

排序窗口为[1,2,3,4],第二个索引(* 从零开始 *)上的元素为3。
秩过滤器的特殊情况是最小过滤器(在这种情况下秩=0)、最大过滤器(秩=length_of_an_array)和中值过滤器
1.最后,将秩过滤器应用于原始数组

元素“1”的蓝色窗口,已排序[0 0 0 1],已排序数组的第二个元素- 0
元素“2”的红色窗口,已排序[0 0 1 2],已排序数组的第二个元素- 1
元素“3”的绿色窗口,已排序[0 0 2 3],已排序数组的第二个元素- 2
依此类推......所以,输出数组的第一个原始值[0,1,2]
现在答案与输出相符!

相关问题