`order=0` 的 `scipy.ndimage.zoom()` 的意外行为

Unexpected behavior of `scipy.ndimage.zoom()` for `order=0`

我很难理解 scipy.ndimage.zoom()order=0 时的行为。

考虑以下代码:

import numpy as np
import scipy as sp
import scipy.ndimage

arr = np.arange(3) + 1
print(arr)
for order in range(5):
    zoomed = sp.ndimage.zoom(arr.astype(float), 4, order=order)
    print(order, np.round(zoomed, 3))

其输出是:

0 [1. 1. 1. 2. 2. 2. 2. 2. 2. 3. 3. 3.]
1 [1.    1.182 1.364 1.545 1.727 1.909 2.091 2.273 2.455 2.636 2.818 3.   ]
2 [1.    1.044 1.176 1.394 1.636 1.879 2.121 2.364 2.606 2.824 2.956 3.   ]
3 [1.    1.047 1.174 1.365 1.601 1.864 2.136 2.399 2.635 2.826 2.953 3.   ]
4 [1.    1.041 1.162 1.351 1.59  1.86  2.14  2.41  2.649 2.838 2.959 3.   ]

因此,当 order=0 值(预期)不会被插值。 然而,我期待的是:

[1. 1. 1. 1. 2. 2. 2. 2. 3. 3. 3. 3.]

即每个值的元素数量完全相同,因为缩放是一个整数。 因此,我期望得到与 np.repeat():

相同的结果
print(np.repeat(arr.astype(float), 4))
[1. 1. 1. 1. 2. 2. 2. 2. 3. 3. 3. 3.]

为什么每个元素的重复次数不同?


请注意 np.repeat() 不直接与多维数组一起使用,这就是为什么我想从 scipy.ndimage.zoom().[=26= 获得 "correct" 行为的原因]


我的 NumPy 和 SciPy 版本是:

print(np.__version__)
# 1.17.4
print(sp.__version__)
# 1.3.3

我发现了这个: `scipy.ndimage.zoom` vs `skimage.transform.rescale` with `order=0` 这指向 scipy.ndimage.zoom() 的一些意外行为,但我不太确定观察到的效果是否相同。

我认为这是预期的行为。

考虑您的初始列表,[1, 2, 3]。您要求 scipy 将其放大 4 倍,从而创建一个 4x3=12 元素列表。列表的第一个元素必须是 1,最后一个元素必须是 3。然后,对于 2,我们有偶数个元素,所以将 2 作为第 6 个和第 7 个元素是有意义的。这给出 [1, , , , , 2, 2, , , , , 3]。从这里开始,您提供了 order=0 的 zoom,这意味着 zoom 将使用 0 阶样条填充缺失值。第一种情况,zoom 需要填充 1 到 2 之间的 4 个缺失值。这必须是[1, 1, 2, 2]。第二种情况,2 和 3 之间有 4 个缺失值。同样的逻辑,[2, 2, 3, 3]。最终结果[1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3].

现在考虑 5 倍缩放,它生成 15 个元素的数组。同样的故事,除了有一个 "middle" 元素,所以只有一个 2 最初放在新列表中,在第 8 个位置。在每对之间填充六个元素,我们得到相同的逻辑 [1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3].

因此,您得到的 2 比 1 或 3 多,因为 2 涉及两个插值操作,而 1 和 3 都涉及一个。

这是一个 bin/edge 数组解释问题。 scipy.ndimage.zoom() 的行为基于数组值的边缘解释,而为整数缩放因子(模仿 np.repeat())生成大小相同的块的行为基于 bin 解释。

让我们用一些 "pictures" 来说明。

斌解读

考虑数组 [1 2 3],让我们将每个值分配给一个 bin。 每个 bin 的边缘将是:01 对于 112 对于 2,等等

0 1 2 3
|1|2|3|

现在,让我们将这个数组放大 4 倍:

                    1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2
|   1   |   2   |   3   |

因此,使用 Next-door Neighbor 方法分配给 bin 的值是:

                    1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2
|1 1 1 1|2 2 2 2|3 3 3 3|

边缘解释

考虑与之前相同的数组 [1 2 3],但现在让我们将每个值分配给一条边:

0 1 2
| | |
1 2 3

现在,让我们将这个数组放大 4 倍:

                    1 1
0 1 2 3 4 5 6 7 8 9 0 1
| | | | | | | | | | | |
1          2          3

因此,使用 Next-door Neighbor 方法分配给边的值是:

                    1 1
0 1 2 3 4 5 6 7 8 9 0 1
| | | | | | | | | | | |
1 1 1 2 2 2 2 2 2 3 3 3

并且边 3 被分配给 2 因为 2 有位置 5.51 有位置 0(5.5 - 3 = 2.5) < (3 - 0 = 3). 类似地,边 8 被分配给 2 因为 (8 - 5.5 = 2.5) < (11 - 8 = 3).


评论

在物理学中,"bin array interpretation" 通常更有用,因为测量通常是 "the result of some integration over a certain bin in an appropriate domain"(特别是在给定时间间隔收集的任何形式的信号——包括图像),因此我期待 scipy.ndimage.zoom() 的 "bin interpretation" 但我承认 "edge interpretation" 同样有效(尽管我不确定哪些应用程序从中受益最多)。


(感谢@Patol75 为我指路