'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()获得"正确"行为的原因。


我的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()的一些意外行为,但我不太确定观察到的效果是否相同。

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

让我们用一些"图片"来说明。

垃圾桶解释

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

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   |

因此,使用隔壁邻居方法分配给箱的值为:

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

因此,使用隔壁邻居方法分配给边的值为:

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.5,而1具有位置0(5.5 - 3 = 2.5) < (3 - 0 = 3)。 同样,边8被分配给2,因为(8 - 5.5 = 2.5) < (11 - 8 = 3)


评论

在物理学中,"bin 数组解释"通常更有用,因为测量通常是"在适当域中对某个 bin 进行某种积分的结果"(特别是以给定时间间隔收集的任何形式的信号 - 包括图像(,因此我期待scipy.ndimage.zoom()的"bin 解释",但我承认"边缘解释"同样有效(尽管我不确定哪些应用程序从中受益最大(。


(感谢@Patol75为我指出正确的方向(

我认为这是预期的行为。

考虑您的初始列表,[1, 2, 3]。你要求 scipy 放大它 4 次,从而创建一个 4x3=12 元素列表。列表的第一个元素必须是 1,最后一个元素必须是 3。然后,对于 2,我们有偶数个元素,因此将 2 作为第 6 个和第 7 个元素是有意义的。这给了[1, , , , , 2, 2, , , , , 3].从这里开始,您使用 order=0 提供了缩放,这意味着缩放将使用顺序为 0 的样条填充缺失值。第一种情况,缩放需要填写 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 个元素的数组。同样的故事,除了有一个"中间"元素,所以只有一个 2 最初被放置在新列表中,在第 8 位。每对之间要填充六个元素,我们得到相同的逻辑[1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3].

因此,你得到的 2 比 1 或 3 多,因为 2 涉及两个插值运算,而不是一个插值运算用于 1 和 3。

最新更新