【问题标题】:Unexpected behavior of `scipy.ndimage.zoom()` for `order=0``order=0` 的 `scipy.ndimage.zoom()` 的意外行为
【发布时间】:2020-04-04 12:06:56
【问题描述】:

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

考虑以下代码:

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

【问题讨论】:

  • 我不确定你想重复什么形状,但也许np.tile 适合你。
  • 如果您发布一个输入和输出的小例子,我可以帮助您弄清楚语法。
  • @Joe OP 询问的是 Python 库中函数的行为,而不是关于如何实现特定目标。
  • 我在字里行间阅读:)

标签: python numpy scipy zooming ndimage


【解决方案1】:

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

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

Bin解释

考虑数组[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.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 将我指向右侧direction

【讨论】:

    【解决方案2】:

    我认为这是预期的行为。

    考虑您的初始列表,[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 都涉及一个。

    【讨论】:

    • @norok2 我的结果是正确的,你忘了提供order=0。 ;)
    • 抱歉,我实际上是在查看np.repeat() :$ 和order > 0 的输出,一开始就无法获得整数值。
    • 其实,如果你给[1, 2, 3],意思是一个整数列表,不管order关键字的值是什么,输出也是一个整数列表。要摆脱整数,您需要提供一个浮点数列表,例如[1., 2., 3.],并给 order 一个大于或等于 1 的值。有趣吧?
    • 那是因为结果继承了输入的dtype。这就是为什么我实际上在问题中强制输入为float
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 2011-03-12
    • 2019-05-10
    • 2019-05-16
    • 1970-01-01
    相关资源
    最近更新 更多