重新缩放numpy数组

时间:2014-09-04 22:58:44

标签: python arrays numpy

我有一个2D numpy数组,表示来自CCD的单色图像,该CCD已经被分类为3x3(也就是说,数组中的每个值代表物理CCD上的9个像素(3x3))。

我想将其重新缩放以匹配原始CCD布局(因此我可以使用来自同一CCD的非分箱图像轻松覆盖它)。

我看到了Resampling a numpy array representing an image,但这似乎并不像我想要的那样。

假设我有一个数组g:

import numpy as np
import scipy.ndimage

 g = np.array([[0, 1, 2],
               [3, 4, 5],
               [6, 7, 8]])

当我尝试将其缩放2倍时:

o = scipy.ndimage.zoom(g, 2, order=0)

我得到了我所期望的 - 每个值现在是2x2相同的值:

array([[0, 0, 1, 1, 2, 2],
       [0, 0, 1, 1, 2, 2],
       [3, 3, 4, 4, 5, 5],
       [3, 3, 4, 4, 5, 5],
       [6, 6, 7, 7, 8, 8],
       [6, 6, 7, 7, 8, 8]])

但是当我尝试按比例缩放3倍时,我得到了这个:

o = scipy.ndimage.zoom(g, 3, order=0)

给我:

array([[0, 0, 1, 1, 1, 1, 2, 2, 2],
       [0, 0, 1, 1, 1, 1, 2, 2, 2],
       [3, 3, 4, 4, 4, 4, 5, 5, 5],
       [3, 3, 4, 4, 4, 4, 5, 5, 5],
       [3, 3, 4, 4, 4, 4, 5, 5, 5],
       [3, 3, 4, 4, 4, 4, 5, 5, 5],
       [6, 6, 7, 7, 7, 7, 8, 8, 8],
       [6, 6, 7, 7, 7, 7, 8, 8, 8],
       [6, 6, 7, 7, 7, 7, 8, 8, 8]])

我希望原始数组中的每个值都成为一组3x3值...这不是我得到的。

我该怎么办? (为什么我会得到这个不直观的结果?)

2 个答案:

答案 0 :(得分:5)

您可以使用np.kron

In [16]: g
Out[16]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [17]: np.kron(g, np.ones((3,3), dtype=int))
Out[17]: 
array([[0, 0, 0, 1, 1, 1, 2, 2, 2],
       [0, 0, 0, 1, 1, 1, 2, 2, 2],
       [0, 0, 0, 1, 1, 1, 2, 2, 2],
       [3, 3, 3, 4, 4, 4, 5, 5, 5],
       [3, 3, 3, 4, 4, 4, 5, 5, 5],
       [3, 3, 3, 4, 4, 4, 5, 5, 5],
       [6, 6, 6, 7, 7, 7, 8, 8, 8],
       [6, 6, 6, 7, 7, 7, 8, 8, 8],
       [6, 6, 6, 7, 7, 7, 8, 8, 8]])

zoom(g, 3, order=0)的输出有点令人惊讶。考虑第一行:[0, 0, 1, 1, 1, 1, 2, 2, 2]。为什么有四个1 s?

order=0缩放(实际上)计算np.linspace(0, 2, 9)时,它看起来像

In [80]: np.linspace(0, 2, 9)
Out[80]: array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,  1.5 ,  1.75,  2.  ])

然后舍入值。如果您使用np.round(),则会获得:

In [71]: np.round(np.linspace(0, 2, 9)).astype(int)
Out[71]: array([0, 0, 0, 1, 1, 1, 2, 2, 2])

请注意,np.round(0.5)代表0,但np.round(1.5)代表2np.round()使用"round half to even" tie-breaking rule。显然,zoom代码中的舍入使用了"round half down" rule:它将0.5转为0,将1.5转为1,如下所示

In [81]: [int(round(x)) for x in np.linspace(0, 2, 9)]
Out[81]: [0, 0, 1, 1, 1, 1, 2, 2, 2]

这就是为什么那里有四个1

答案 1 :(得分:2)

  

为什么我会得到这个不直观的结果?

因为zoom是样条插值函数。换句话说,它从1的中点到0的中点绘制一个三次样条曲线,其间的值将样条曲线的值设置在适当的位置。

如果您想要最近,线性或二次插值而不是立方,您可以使用order=0order=1order=2参数。但是如果你根本不想要插值 - 你不要使用插值函数。这就像问为什么使用[int(i*2.3) for i in range(10)]得到0到20的偶数给出一些奇数。获取0到20之间的偶数并不是一个函数,所以它不会这样做,但它完全符合你的要求。


  

我该怎么做?

同样,如果您想要非插值缩放,请不要使用插值函数。最简单的方法可能是使用np.kron,Kroenecker将数组乘以np.ones((scale, scale))