我正在寻找如何重新采样以新尺寸表示图像数据的numpy数组,最好选择插值方法(最近,双线性等)。我知道有
scipy.misc.imresize
通过包装PIL的resize函数来完成此操作。唯一的问题是,因为它使用PIL,numpy数组必须符合图像格式,给我最多4个“颜色”通道。
我希望能够使用任意数量的“颜色”通道调整任意图像的大小。我想知道在scipy / numpy中是否有一种简单的方法可以做到这一点,或者我是否需要自己动手。
我有两个关于如何自己编造一个的想法:
scipy.misc.imresize
的功能scipy.ndimage.interpolation.affine_transform
对于大数据,第一个可能会很慢,而第二个似乎不提供除样条之外的任何其他插值方法。
答案 0 :(得分:97)
根据您的说明,您需要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]]
编辑:正如Matt 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]]]
答案 1 :(得分:13)
如果您想重新取样,那么您应该查看Scipy的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'
,但在这种情况下摆脱横向阵列。
答案 2 :(得分:8)
你看过Scikit-image了吗?它的transform.pyramid_*
函数可能对您有用。
答案 3 :(得分:5)
我最近刚发现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的工作方式不同 - 您可以指定所需的输出形状,而不是指定mutliplier。这适用于2D和3D图像。
对于2D图像,您可以使用transform.rescale并指定乘数或比例,就像使用interpolation.zoom一样。
答案 4 :(得分:0)
此解决方案在不影响RGB通道的情况下缩放馈送图像的X和Y:
import numpy as np
import scipy.ndimage
matplotlib.pyplot.imshow(scipy.ndimage.zoom(image_np_array, zoom = (7,7,1), order = 1))
希望这很有用。
答案 5 :(得分:0)
您可以使用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))
当然,如果您的图像有多个通道,则必须对每个通道进行插值。