重新采样表示图像的numpy数组
我正在寻找如何以一个新的尺寸重新取样代表图像数据的numpy数组,最好有一个插值方法的select(最近的,双线性等)。 我知道有
scipy.misc.imresize
这是通过包装PIL的resizefunction来完成的。 唯一的问题是,因为它使用PIL,numpy数组必须符合图像格式,给我最多4个“彩色”通道。
我希望能够调整任意图像的大小,使用任何数量的“颜色”通道。 我想知道是否有一个简单的方法来做这个scipy / numpy,或者如果我需要推出自己的。
对于如何自己制作一个我有两个想法:
- 一个在每个通道上分别运行
scipy.misc.imresize
的函数 - 创build我自己的使用
scipy.ndimage.interpolation.affine_transform
第一个对于大数据可能会很慢,第二个似乎没有提供除了样条的其他插值方法。
基于你的描述,你想scipy.ndimage.zoom
。
双线性插值将是order=1
,最接近order=0
,而cubic是默认值( order=3
)。
zoom
是专门针对要重新采样到新分辨率的常规网格数据。
举一个简单的例子:
import numpy as np import scipy.ndimage x = np.arange(9).reshape(3,3) print 'Original array:' print x print 'Resampled by a factor of 2 with nearest interpolation:' print scipy.ndimage.zoom(x, 2, order=0) print 'Resampled by a factor of 2 with bilinear interpolation:' print scipy.ndimage.zoom(x, 2, order=1) print 'Resampled by a factor of 2 with cubic interpolation:' print scipy.ndimage.zoom(x, 2, order=3)
结果是:
Original array: [[0 1 2] [3 4 5] [6 7 8]] Resampled by a factor of 2 with nearest interpolation: [[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]] Resampled by a factor of 2 with bilinear interpolation: [[0 0 1 1 2 2] [1 2 2 2 3 3] [2 3 3 4 4 4] [4 4 4 5 5 6] [5 5 6 6 6 7] [6 6 7 7 8 8]] Resampled by a factor of 2 with cubic interpolation: [[0 0 1 1 2 2] [1 1 1 2 2 3] [2 2 3 3 4 4] [4 4 5 5 6 6] [5 6 6 7 7 7] [6 6 7 7 8 8]]
编辑:正如马特·S指出的那样,缩放多波段图像有一些注意事项。 我从我以前的答案几乎逐字抄录下面的部分:
缩放也适用于3D(和nD)数组。 但是,请注意,例如,如果您缩放2倍,则将沿所有轴缩放。
data = np.arange(27).reshape(3,3,3) print 'Original:\n', data print 'Zoomed by 2x gives an array of shape:', ndimage.zoom(data, 2).shape
这产生:
Original: [[[ 0 1 2] [ 3 4 5] [ 6 7 8]] [[ 9 10 11] [12 13 14] [15 16 17]] [[18 19 20] [21 22 23] [24 25 26]]] Zoomed by 2x gives an array of shape: (6, 6, 6)
在多波段图像的情况下,您通常不希望沿着“z”轴插入,创build新的波段。
如果您想要缩放3像素的RGB图像,可以通过指定一系列元组作为缩放因子来实现:
print 'Zoomed by 2x along the last two axes:' print ndimage.zoom(data, (1, 2, 2))
这产生:
Zoomed by 2x along the last two axes: [[[ 0 0 1 1 2 2] [ 1 1 1 2 2 3] [ 2 2 3 3 4 4] [ 4 4 5 5 6 6] [ 5 6 6 7 7 7] [ 6 6 7 7 8 8]] [[ 9 9 10 10 11 11] [10 10 10 11 11 12] [11 11 12 12 13 13] [13 13 14 14 15 15] [14 15 15 16 16 16] [15 15 16 16 17 17]] [[18 18 19 19 20 20] [19 19 19 20 20 21] [20 20 21 21 22 22] [22 22 23 23 24 24] [23 24 24 25 25 25] [24 24 25 25 26 26]]]
如果你想重新采样,那么你应该看看Scipy的食谱来重组 。 具体来说, congrid
定义的函数会支持重定义或插值(相当于IDL中具有相同名称的函数)。 如果你不想插值,这应该是最快的select。
您也可以直接使用scipy.ndimage.map_coordinates
,它将为任何types的重采样(包括非结构化网格)执行样条插值。 我发现map_coordinates对于较大的数组(nx,ny> 200)会很慢。
对于结构化网格上的插值,我倾向于使用scipy.interpolate.RectBivariateSpline
。 您可以select样条的顺序(线性,二次,立方等),甚至可以独立的为每个轴。 一个例子:
import scipy.interpolate as interp f = interp.RectBivariateSpline(x, y, im, kx=1, ky=1) new_im = f(new_x, new_y)
在这种情况下,你正在做一个双线性插值(kx = ky = 1)
。 不支持“最近”types的插值,因为所有这些都是矩形网格上的样条插值。 这也不是最快的方法。
如果在双线性或双三次插值之后,进行两次一维插值通常要快得多:
f = interp.interp1d(y, im, kind='linear') temp = f(new_y) f = interp.interp1d(x, temp.T, kind='linear') new_im = f(new_x).T
你也可以使用kind='nearest'
,但是在这种情况下,摆脱横向数组。
你看了Scikit-image ? 它的transform.pyramid_*
函数可能对你有用。
我最近刚刚发现了一个scipy.ndimage.interpolation.zoom的问题,我把它作为一个错误报告提交: https : //github.com/scipy/scipy/issues/3203
作为替代(或者至less对我来说),我发现scikit-image的skimage.transform.resize能够正常工作: http ://scikit-image.org/docs/dev/api/skimage.transform.html#skimage .transform.resize
然而,它对scipy的interpolation.zoom的作用是不同的 – 不是指定一个mutliplier,而是指定你想要的输出形状。 这适用于二维和三维图像。
对于2D图像,您可以使用transform.rescale,并像interpolation.zoom一样指定倍数或比例。