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

时间:2022-01-20 18:17:19

I am looking for how to resample a numpy array representing image data at a new size, preferably having a choice of the interpolation method (nearest, bilinear, etc.). I know there is

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

scipy.misc.imresize

which does exactly this by wrapping PIL's resize function. The only problem is that since it uses PIL, the numpy array has to conform to image formats, giving me a maximum of 4 "color" channels.

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

I want to be able to resize arbitrary images, with any number of "color" channels. I was wondering if there is a simple way to do this in scipy/numpy, or if I need to roll my own.

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

I have two ideas for how to concoct one myself:

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

  • a function that runs scipy.misc.imresize on every channel separately
  • 一个在每个通道上分别运行scipy.misc.imresize的函数
  • create my own using scipy.ndimage.interpolation.affine_transform
  • 使用scipy.ndimage.interpolation.affine_transform创建我自己的

The first one would probably be slow for large data, and the second one does not seem to offer any other interpolation method except splines.

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

4 个解决方案

#1


90  

Based on your description, you want scipy.ndimage.zoom.

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

Bilinear interpolation would be order=1, nearest is order=0, and cubic is the default (order=3).

双线性插值将是order = 1,最接近的是order = 0,而cubic是默认值(order = 3)。

zoom is specifically for regularly-gridded data that you want to resample to a new resolution.

zoom专门用于要重新采样到新分辨率的常规网格化数据。

As a quick example:

作为一个简单的例子:

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)

And the result:

结果如下:

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]]

Edit: As Matt S. pointed out, there are a couple of caveats for zooming multi-band images. I'm copying the portion below almost verbatim from one of my earlier answers:

编辑:正如Matt S.指出的那样,对于缩放多波段图像有几点需要注意。我正在从我之前的一个答案中逐字逐句地复制下面的部分:

Zooming also works for 3D (and nD) arrays. However, be aware that if you zoom by 2x, for example, you'll zoom along all axes.

缩放也适用于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

This yields:

这会产生:

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)

In the case of multi-band images, you usually don't want to interpolate along the "z" axis, creating new bands.

在多波段图像的情况下,您通常不希望沿“z”轴进行插值,从而创建新的波段。

If you have something like a 3-band, RGB image that you'd like to zoom, you can do this by specifying a sequence of tuples as the zoom factor:

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

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

This yields:

这会产生:

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]]]

#2


10  

If you want to resample, then you should look at Scipy's cookbook for rebinning. In particular, the congrid function defined at the end will support rebinning or interpolation (equivalent to the function in IDL with the same name). This should be the fastest option if you don't want interpolation.

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

You can also use directly scipy.ndimage.map_coordinates, which will do a spline interpolation for any kind of resampling (including unstructured grids). I find map_coordinates to be slow for large arrays (nx, ny > 200).

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

For interpolation on structured grids, I tend to use scipy.interpolate.RectBivariateSpline. You can choose the order of the spline (linear, quadratic, cubic, etc) and even independently for each axis. An example:

对于结构化网格的插值,我倾向于使用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)

In this case you're doing a bi-linear interpolation (kx = ky = 1). The 'nearest' kind of interpolation is not supported, as all this does is a spline interpolation over a rectangular mesh. It's also not the fastest method.

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

If you're after bi-linear or bi-cubic interpolation, it is generally much faster to do two 1D interpolations:

如果您正在进行双线性或双三次插值,那么进行两次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

You can also use kind='nearest', but in that case get rid of the transverse arrays.

你也可以使用kind ='nearest',但在这种情况下摆脱横向数组。

#3


7  

Have you looked at Scikit-image? Its transform.pyramid_* functions might be useful for you.

你看过Scikit-image吗?它的transform.pyramid_ *函数可能对您有用。

#4


4  

I've recently just found an issue with scipy.ndimage.interpolation.zoom, which I've submitted as a bug report: https://github.com/scipy/scipy/issues/3203

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

As an alternative (or at least for me), I've found that scikit-image's skimage.transform.resize works correctly: http://scikit-image.org/docs/dev/api/skimage.transform.html#skimage.transform.resize

作为替代方案(或者至少对我而言),我发现scikit-image的skimage.transform.resize正常工作:http://scikit-image.org/docs/dev/api/skimage.transform.html#skimage .transform.resize

However it works differently to scipy's interpolation.zoom - rather than specifying a mutliplier, you specify the the output shape that you want. This works for 2D and 3D images.

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

For just 2D images, you can use transform.rescale and specify a multiplier or scale as you would with interpolation.zoom.

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

#1


90  

Based on your description, you want scipy.ndimage.zoom.

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

Bilinear interpolation would be order=1, nearest is order=0, and cubic is the default (order=3).

双线性插值将是order = 1,最接近的是order = 0,而cubic是默认值(order = 3)。

zoom is specifically for regularly-gridded data that you want to resample to a new resolution.

zoom专门用于要重新采样到新分辨率的常规网格化数据。

As a quick example:

作为一个简单的例子:

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)

And the result:

结果如下:

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]]

Edit: As Matt S. pointed out, there are a couple of caveats for zooming multi-band images. I'm copying the portion below almost verbatim from one of my earlier answers:

编辑:正如Matt S.指出的那样,对于缩放多波段图像有几点需要注意。我正在从我之前的一个答案中逐字逐句地复制下面的部分:

Zooming also works for 3D (and nD) arrays. However, be aware that if you zoom by 2x, for example, you'll zoom along all axes.

缩放也适用于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

This yields:

这会产生:

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)

In the case of multi-band images, you usually don't want to interpolate along the "z" axis, creating new bands.

在多波段图像的情况下,您通常不希望沿“z”轴进行插值,从而创建新的波段。

If you have something like a 3-band, RGB image that you'd like to zoom, you can do this by specifying a sequence of tuples as the zoom factor:

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

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

This yields:

这会产生:

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]]]

#2


10  

If you want to resample, then you should look at Scipy's cookbook for rebinning. In particular, the congrid function defined at the end will support rebinning or interpolation (equivalent to the function in IDL with the same name). This should be the fastest option if you don't want interpolation.

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

You can also use directly scipy.ndimage.map_coordinates, which will do a spline interpolation for any kind of resampling (including unstructured grids). I find map_coordinates to be slow for large arrays (nx, ny > 200).

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

For interpolation on structured grids, I tend to use scipy.interpolate.RectBivariateSpline. You can choose the order of the spline (linear, quadratic, cubic, etc) and even independently for each axis. An example:

对于结构化网格的插值,我倾向于使用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)

In this case you're doing a bi-linear interpolation (kx = ky = 1). The 'nearest' kind of interpolation is not supported, as all this does is a spline interpolation over a rectangular mesh. It's also not the fastest method.

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

If you're after bi-linear or bi-cubic interpolation, it is generally much faster to do two 1D interpolations:

如果您正在进行双线性或双三次插值,那么进行两次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

You can also use kind='nearest', but in that case get rid of the transverse arrays.

你也可以使用kind ='nearest',但在这种情况下摆脱横向数组。

#3


7  

Have you looked at Scikit-image? Its transform.pyramid_* functions might be useful for you.

你看过Scikit-image吗?它的transform.pyramid_ *函数可能对您有用。

#4


4  

I've recently just found an issue with scipy.ndimage.interpolation.zoom, which I've submitted as a bug report: https://github.com/scipy/scipy/issues/3203

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

As an alternative (or at least for me), I've found that scikit-image's skimage.transform.resize works correctly: http://scikit-image.org/docs/dev/api/skimage.transform.html#skimage.transform.resize

作为替代方案(或者至少对我而言),我发现scikit-image的skimage.transform.resize正常工作:http://scikit-image.org/docs/dev/api/skimage.transform.html#skimage .transform.resize

However it works differently to scipy's interpolation.zoom - rather than specifying a mutliplier, you specify the the output shape that you want. This works for 2D and 3D images.

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

For just 2D images, you can use transform.rescale and specify a multiplier or scale as you would with interpolation.zoom.

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