移位插值未给出预期行为

Shift interpolation does not give expected behaviour

提问人:bproxauf 提问时间:3/14/2018 最后编辑:Drisebproxauf 更新时间:11/18/2019 访问量:963

问:

当使用 scipy.ndimage.interpolation.shift 通过周期性边界处理 () 沿一个轴移动 numpy 数据数组时,我得到一个意外的行为。该例程尝试强制第一个像素 () 与最后一个像素 () 相同,而不是“最后一个加一 ()”。mode = 'wrap'index 0index N-1index N

最小示例:

# module import
import numpy as np
from scipy.ndimage.interpolation import shift
import matplotlib.pyplot as plt

# print scipy.__version__
# 0.18.1

a = range(10)

plt.figure(figsize=(16,12))

for i, shift_pix in enumerate(range(10)):
    # shift the data via spline interpolation
    b = shift(a, shift=shift_pix, mode='wrap')

    # plotting the data
    plt.subplot(5,2,i+1)
    plt.plot(a, marker='o', label='data')
    plt.plot(np.roll(a, shift_pix), marker='o', label='data, roll')
    plt.plot(b, marker='o',label='shifted data')
    if i == 0:
        plt.legend(loc=4,fontsize=12)
    plt.ylim(-1,10)
    ax = plt.gca()
    ax.text(0.10,0.80,'shift %d pix' % i, transform=ax.transAxes)

蓝线:移位前的数据 绿线:预期的移位
行为
红线:scipy.ndimage.interpolation.shift 的实际移位输出

我如何调用函数或如何理解它的行为是否存在一些错误?当前结果与相关 scipy 教程页面和另一篇 StackOverflow 帖子中的模式参数描述形成鲜明对比。代码中是否存在差一错误?mode = 'wrap'

使用的 Scipy 版本是 0.18.1,在 anaconda-2.2.0 中分发

enter image description here

Python Scipy 插值 ndimage

评论

0赞 bproxauf 3/14/2018
使用的 Scipy 版本是 0.18.1,在 anaconda-2.2.0 中分发
0赞 Jean-François Fabre 3/14/2018
不要发表评论以添加澄清,而是编辑(注意:已经为 YA 这样做了)
0赞 Arthur Dent 3/15/2018
它看起来像在数据移动后执行边界条件。因此,当shift_pix为 1 时,它会转换为 ,然后进行换行,带到前面。我不知道它为什么会这样做。shift()a[0, 1, 2, 3, 4, 5, 6, 7, 8]8
0赞 bproxauf 3/15/2018
@ArthurDent:我不确定是否真的是这样。请注意,输出值为 。如果我正确理解了您的建议,那么包装宁愿给出.[8, 1, 2, 3, 4, 5, 6, 7, 8, 9][8, 0, 1, 2, 3, 4, 5, 6, 7, 8]
0赞 Arthur Dent 3/16/2018
@bproxauf 你得到的不是吗?第二个图中移位数据的第二个元素等于 0,而不是 1。当我这样做时,它会产生 。此外,我花了比我愿意承认的更多的时间查看 shift 函数的源代码,但它是用 C 语言编写的,对我来说有点太复杂了,我无法破译。据我所知,它看起来应该首先进行包装,但我不确定。如果你想看看它,请告诉我。[8, 0, 1, 2, 3, 4, 5, 6, 7, 8]b = shift(a, shift=1, mode='wrap')[8, 0, 1, 2, 3, 4, 5, 6, 7, 8]

答:

1赞 Radek 3/20/2018 #1

看来你观察到的行为是故意的。

问题的原因在于 C 函数map_coordinate该函数将移位后的坐标转换为移位前的坐标:

map_coordinate(double in, npy_intp len, int mode)

该函数用作执行实际移位的子例程。它的有趣部分如下所示:NI_ZoomShift

enter image description here

示例。让我们看看(来自问题)的输出是如何计算的。output = shift(np.arange(10), shift=4, mode='wrap')

NI_ZoomShift以某种特殊方式计算边缘值,所以让我们看一下(有点简化)的计算:output[0]output[9]output[1]

# input  =         [0,1,2,3,4,5,6,7,8,9]
# output = [ ,?, , , , , , , , ]          '?' == computed position
# shift  = 4
output_index = 1

in  = output_index - shift    # -3
sz  = 10 - 1                  # 9
in += sz * ((-5 / 9) + 1)
#  +=  9 * ((     0) + 1) == 9
# in == 6

return input[in]  # 6 

很明显,这是您观察到的行为的原因。它从可追溯到 2007 年的一个暗示性命名的提交中进行了更改:修复 ndimage 边界例程中的 off-by-on 错误。更新测试。sz = len - 1sz = len

我不知道为什么要引入这样的变化。我想到的可能解释之一如下:

函数“shift”使用样条进行插值。 区间上均匀样条的结向量简单来说就是 。当我们说样条应该换行时,很自然地要求 knots 和 的值相等,这样样条的许多副本就可以粘在一起,形成一个周期函数:[0, k][0,1,2,...,k]0k

0--1--2--3-...-k              0--1--2--3-...-k              0--1-- ...
               0--1--2--3-...-k              0--1--2--3-...-k      ...

也许只是将其输入视为样条结的值列表?shift

1赞 shoyer 11/18/2019 #2

值得注意的是,此行为似乎是一个错误,如本期 SciPy 中所述:https://github.com/scipy/scipy/issues/2640

该问题似乎影响了除 之外的所有外推。modescipy.ndimagemode='mirror'