`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 的边缘将是:0
和 1
对于 1
,1
和 2
对于 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.5
而 1
有位置 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 为我指路)
我很难理解 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 的边缘将是:0
和 1
对于 1
,1
和 2
对于 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.5
而 1
有位置 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 为我指路