Program Tip

이미지를 나타내는 numpy 배열 리샘플링

programtip 2020. 11. 1. 18:31
반응형

이미지를 나타내는 numpy 배열 리샘플링


새로운 크기로 이미지 데이터를 나타내는 numpy 배열을 리샘플링하는 방법을 찾고 있는데, 바람직하게는 보간 방법 (가장 가까운, 이중 선형 등)을 선택할 수 있습니다. 나는 알고있다

scipy.misc.imresize

PIL의 크기 조정 기능을 래핑하여 정확하게 수행합니다. 유일한 문제는 PIL을 사용하기 때문에 numpy 배열이 이미지 형식을 준수해야하므로 최대 4 개의 "색상"채널을 제공해야한다는 것입니다.

여러 "색상"채널을 사용하여 임의의 이미지 크기를 조정하고 싶습니다. scipy / numpy에서이 작업을 수행하는 간단한 방법이 있는지 아니면 직접 굴려야하는지 궁금합니다.

직접 만드는 방법에 대한 두 가지 아이디어가 있습니다.

  • scipy.misc.imresize모든 채널에서 개별적으로 실행되는 기능
  • 사용하여 나만의 만들기 scipy.ndimage.interpolation.affine_transform

첫 번째 방법은 대용량 데이터의 경우 속도가 느릴 수 있으며 두 번째 방법은 스플라인을 제외한 다른 보간 방법을 제공하지 않는 것 같습니다.


설명에 따라 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.가 지적했듯이 다중 대역 이미지를 확대 / 축소 할 때 몇 가지주의 사항이 있습니다. 이전 답변 중 하나에서 거의 그대로 아래 부분을 복사하고 있습니다 .

확대 / 축소는 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)

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

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:

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

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.

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).

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:

    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.

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

    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.


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


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

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

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.

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


This solution scales X and Y of the fed image without affecting RGB channels:

import numpy as np
import scipy.ndimage

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

Hope this is useful.


You can use interpolate.interp2d.

For example, considering an image represented by a numpy array arr, you can resize it to an arbitrary height and width as follows:

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

Of course, if your image has multiple channels, you have to perform the interpolation for each one.

참고URL : https://stackoverflow.com/questions/13242382/resampling-a-numpy-array-representing-an-image

반응형