我有一个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值...这不是我得到的。
我该怎么办? (为什么我会得到这个不直观的结果?)
答案 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)
代表2
。 np.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=0
或order=1
或order=2
参数。但是如果你根本不想要插值 - 你不要使用插值函数。这就像问为什么使用[int(i*2.3) for i in range(10)]
得到0到20的偶数给出一些奇数。获取0到20之间的偶数并不是一个函数,所以它不会这样做,但它完全符合你的要求。
我该怎么做?
同样,如果您想要非插值缩放,请不要使用插值函数。最简单的方法可能是使用np.kron
,Kroenecker将数组乘以np.ones((scale, scale))
。