恢复表示图像的numpy数组

56lgkhnf  于 12个月前  发布在  其他
关注(0)|答案(7)|浏览(81)

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

scipy.misc.imresize

它通过 Package PIL的resize函数来实现这一点。唯一的问题是,由于它使用PIL,numpy数组必须符合图像格式,最多只能有4个“颜色”通道。
我希望能够调整任意图像的大小,与任何数量的“颜色”通道。我想知道在scipy/numpy中是否有一种简单的方法来做到这一点,或者我是否需要自己滚动。
我有两个想法如何炮制一个自己:

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

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

lnvxswe2

lnvxswe21#

根据您的描述,您需要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)

结果是:

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.指出,对于缩放多波段图像有几个注意事项。我几乎是从我的一个earlier answers中逐字复制下面的部分:

缩放也适用于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”轴沿着插值,从而创建新波段。
如果您想要缩放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]]]
yks3o0rb

yks3o0rb2#

如果你想重新采样,那么你应该看看Scipy的cookbook for rebinning。特别是,最后定义的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)

在这个例子中,你正在做一个双线性插值(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

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

zbq4xfa0

zbq4xfa03#

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

ukqbszuj

ukqbszuj4#

我最近发现scipy.ndimage.interpolation.zoom有一个问题,我已经提交了一份bug报告: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
zoom -不是指定一个乘法器,而是指定你想要的输出形状。这适用于2D和3D图像。
对于2D图像,您可以使用transform.rescale并指定乘数或比例,就像使用interpolation. zoom一样。

91zkwejq

91zkwejq5#

可以使用interpolate.interp2d
例如,考虑由numpy数组arr表示的图像,您可以将其调整为任意高度和宽度,如下所示:

W, H = arr.shape[:2]
new_W, new_H = (600,300)
xrange = lambda x: np.linspace(0, 1, x)

f = interp2d(xrange(W), xrange(H), arr, kind="linear")
new_arr = f(xrange(new_W), xrange(new_H))

当然,如果你的图像有多个通道,你必须为每个通道执行插值。

lztngnrs

lztngnrs6#

最近的插值可以通过numpy.repeat实现

import numpy as np

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

size = 2
a = np.repeat(a, size, axis=0)
a = np.repeat(a, size, axis=1)
[[1, 1, 2, 2, 3, 3],
 [1, 1, 2, 2, 3, 3],
 [4, 4, 5, 5, 6, 6],
 [4, 4, 5, 5, 6, 6],
 [7, 7, 8, 8, 9, 9],
 [7, 7, 8, 8, 9, 9]]

对于RGB图像,我们还需要重复通道尺寸

e3bfsja2

e3bfsja27#

此解决方案缩放输入图像的X和Y,而不影响RGB通道:

import numpy as np
import scipy.ndimage

matplotlib.pyplot.imshow(scipy.ndimage.zoom(image_np_array, zoom = (7,7,1), order = 1))

希望这是有用的。

相关问题