重新采样表示图像的numpy数组

Gus*_*son 70 python numpy image-processing scipy python-imaging-library

我正在寻找如何重新采样以新尺寸表示图像数据的numpy数组,最好选择插值方法(最近,双线性等).我知道有

scipy.misc.imresize
Run Code Online (Sandbox Code Playgroud)

这通过包装PIL的调整大小功能来完成这一点.唯一的问题是,因为它使用PIL,numpy数组必须符合图像格式,给我最多4个"颜色"通道.

我希望能够使用任意数量的"颜色"通道调整任意图像的大小.我想知道是否有一种简单的方法可以在scipy/numpy中执行此操作,或者如果我需要自己滚动.

关于如何自己编造一个我有两个想法:

  • 一个scipy.misc.imresize分别在每个通道上运行的函数
  • 创建我自己的使用 scipy.ndimage.interpolation.affine_transform

对于大数据,第一个可能会很慢,而第二个似乎不提供除样条之外的任何其他插值方法.

Joe*_*ton 102

根据您的描述,您想要scipy.ndimage.zoom.

双线性插值order=1最接近order=0,而立方体是默认值(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)
Run Code Online (Sandbox Code Playgroud)

结果如下:

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]]
Run Code Online (Sandbox Code Playgroud)

编辑:正如Matt 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
Run Code Online (Sandbox Code Playgroud)

这会产生:

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)
Run Code Online (Sandbox Code Playgroud)

在多波段图像的情况下,您通常不希望沿"z"轴插值,从而创建新的波段.

如果您想要缩放的3波段RGB图像,可以通过将一系列元组指定为缩放因子来实现:

print 'Zoomed by 2x along the last two axes:'
print ndimage.zoom(data, (1, 2, 2))
Run Code Online (Sandbox Code Playgroud)

这会产生:

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]]]
Run Code Online (Sandbox Code Playgroud)

  • @MattS. - 正如你所描述的那样,没有必要单独将它用于每个乐队.只需指定一个元组作为缩放系数.例如`scipy.ndimage.zoom(data,(3,3,1))`沿着x和y维度将3d数组缩放3倍,同时保留第三个维度. (7认同)

tia*_*ago 14

如果你想重新取样,那么你应该看看Scipy的菜谱进行重组.特别是,最后congrid定义的函数将支持重组或插值(相当于IDL中具有相同名称的函数).如果您不想插值,这应该是最快的选项.

您也可以直接使用scipy.ndimage.map_coordinates,它将为任何类型的重采样(包括非结构化网格)执行样条插值.我发现map_coordinates对于大型数组来说很慢(nx,ny> 200).

对于结构化网格的插值,我倾向于使用scipy.interpolate.RectBivariateSpline.您可以选择样条的顺序(线性,二次,立方等),甚至可以为每个轴单独选择.一个例子:

    import scipy.interpolate as interp
    f = interp.RectBivariateSpline(x, y, im, kx=1, ky=1)
    new_im = f(new_x, new_y)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您正在进行双线性插值(kx = ky = 1).不支持"最近"的插值类型,因为所有这些都是矩形网格上的样条插值.它也不是最快的方法.

如果您正在进行双线性或双三次插值,那么进行两次1D插值通常要快得多:

    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
Run Code Online (Sandbox Code Playgroud)

您也可以使用kind='nearest',但在这种情况下摆脱横向阵列.


Pet*_*ang 8

你看过Scikit-image吗?它的transform.pyramid_*功能可能对你有用.


小智 6

我最近刚发现scipy.ndimage.interpolation.zoom有问题,我已将其提交为错误报告:https : //github.com/scipy/scipy/issues/3203

作为一种选择(或者至少对我来说),我发现scikit-image的skimage.transform.resize可以正常工作:http ://scikit-image.org/docs/dev/api/skimage.transform.html#skimage .transform.resize

但是,它与scipy的interpolation.zoom的工作方式有所不同-您无需指定多个,而是指定所需的输出形状。这适用于2D和3D图像。

对于仅2D图像,您可以使用transform.rescale并指定一个乘数或比例,就像使用interpolation.zoom一样。