Пересчет массива numpy, представляющего изображение


Я ищу, как пересчитать массив numpy, представляющий данные изображения в новом размере, предпочтительно с выбором метода интерполяции (ближайший, билинейный и т. д.). Я знаю, что есть

scipy.misc.imresize

который делает именно это, обертывая функцию изменения размера PIL. Единственная проблема заключается в том, что поскольку он использует PIL, массив numpy должен соответствовать форматам изображения, давая мне максимум 4 "цветных" канала.

Я хочу иметь возможность изменять произвольные изображения, с любым количеством из "цветных" каналов. Мне было интересно, есть ли простой способ сделать это в scipy/numpy, или если мне нужно свернуть свой собственный.

у меня есть две идеи о том, как состряпать себе:

  • функция, которая работает scipy.misc.imresize на каждом канале отдельно
  • создать свой собственный, используя scipy.ndimage.interpolation.affine_transform

первый, вероятно, будет медленным для больших данных, а второй, похоже, не предлагает никакого другого метода интерполяции, кроме сплайнов.

4 61

4 ответа:

основываясь на вашем описании, вы хотите 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]]

Edit: как отметил Мэтт С., Есть несколько предостережений для масштабирования многополосных изображений. Я копирую часть ниже почти дословно с одного из моих более ранние ответы:

масштабирование также работает для 3D (и nD) массивов. Однако имейте в виду, что если вы увеличите масштаб на 2x, например, вы будете увеличивать вдоль все топоры.

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

если вы хотите изменить разрешение, то вы должны смотреть на кулинарной составляющей на 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', но в таком случае избавьтесь от поперечных массивов.

вы смотрели Scikit-image? Его transform.pyramid_* функции могут быть полезны для вас.

недавно я обнаружил проблему с scipy.ndimage.интерполяция.zoom, который я представил как отчет об ошибке:https://github.com/scipy/scipy/issues/3203

в качестве альтернативы (или, по крайней мере, для меня), я нашел, что skimage scikit-image.преобразиться.изменение размера работает правильно: http://scikit-image.org/docs/dev/api/skimage.transform.html#skimage.transform.resize

однако он работает по-разному для интерполяции scipy.зум-скорее чем указать mutliplier, вы указываете форму вывода, которую вы хотите. Это работает для 2D и 3D изображений.

только 2D-изображений, вы можете использовать преобразование.масштабирование и укажите множитель или масштаб, как при интерполяции.зум.