如何使用 SciPy 图像应用统一过滤器,其中不计算边界外的数据?

How to apply a uniform filter using SciPy Image where the data outside the boundary is not tallied?

我在这上面花了很多时间,我知道如何通过对边界进行切片和索引来手动完成 rows/cols,但是 SciPy 必须有更简单的方法。

我需要将 CVAL(当 mode=constant 时填充超过边缘的值)设置为 NaN,但是,这将 return NaN。

我会用代码和数字来解释它:

import numpy as np
from scipy import ndimage
m = np.reshape(np.arange(0,100),(10,10)).astype(np.float)

使用SciPy ndimage 均匀过滤器使用 3x3 内核计算均值:

filter = ndimage.uniform_filter(m, size=3, mode='constant')
print(filter[1][1]) # equal to 11
print(filter[9][9]) # I need 93.5, however it gets 41.55 due to zeros

如您所见,第一个值为 11,符合预期, 但是,对于沿边界的任何单元格,它将用零填充值(我也尝试了所有其他模式)。

这是我需要实现的(左)vs mode=constantCVAL=0(默认 0)

这个建议不太理想,因为它会比 uniform_filter 慢,但它会做你想做的事。

根据您使用 nan 作为常量值的想法,您可以使用 ndimage.generic_filter 而不是 uniform_filter 来实现统一过滤器,其中 numpy.nanmean 作为通用过滤功能。

例如,这是您的示例数组 m:

In [102]: import numpy as np

In [103]: m = np.reshape(np.arange(0,100),(10,10)).astype(np.float)

应用generic_filter,以numpy.nanmean为要应用的函数:

In [104]: from scipy.ndimage import generic_filter

In [105]: generic_filter(m, np.nanmean, mode='constant', cval=np.nan, size=3)
Out[105]: 
array([[ 5.5,  6. ,  7. ,  8. ,  9. , 10. , 11. , 12. , 13. , 13.5],
       [10.5, 11. , 12. , 13. , 14. , 15. , 16. , 17. , 18. , 18.5],
       [20.5, 21. , 22. , 23. , 24. , 25. , 26. , 27. , 28. , 28.5],
       [30.5, 31. , 32. , 33. , 34. , 35. , 36. , 37. , 38. , 38.5],
       [40.5, 41. , 42. , 43. , 44. , 45. , 46. , 47. , 48. , 48.5],
       [50.5, 51. , 52. , 53. , 54. , 55. , 56. , 57. , 58. , 58.5],
       [60.5, 61. , 62. , 63. , 64. , 65. , 66. , 67. , 68. , 68.5],
       [70.5, 71. , 72. , 73. , 74. , 75. , 76. , 77. , 78. , 78.5],
       [80.5, 81. , 82. , 83. , 84. , 85. , 86. , 87. , 88. , 88.5],
       [85.5, 86. , 87. , 88. , 89. , 90. , 91. , 92. , 93. , 93.5]])

一种简单的方法是使用 Normalized Convolution:

import numpy as np
from scipy import ndimage
m = np.reshape(np.arange(0,100),(10,10)).astype(np.float)

filter = ndimage.uniform_filter(m, size=3, mode='constant')    # normal filter result

weights = ndimage.uniform_filter(np.ones(m.shape), size=3, mode='constant')
filter = filter / weights    # normalized convolution result

print(filter[1][1]) # equal to 11
print(filter[9][9]) # equal to 93.49999999999994 -- rounding error! :)

如果所有数据点都是 1 (weights),我们计算了过滤器的结果。这显示每个过滤器 window 中有多少数据元素,并且 returns 除了边界附近以外的所有地方的值为 1,该值按比例减小。通过将过滤结果除以这些权重,我们校正了将数据域外的零考虑在内的平均值。