Пересчет массива numpy, представляющего изображение
Я ищу, как пересчитать массив numpy, представляющий данные изображения в новом размере, предпочтительно с выбором метода интерполяции (ближайший, билинейный и т. д.). Я знаю, что есть
scipy.misc.imresize
который делает именно это, обертывая функцию изменения размера PIL. Единственная проблема заключается в том, что поскольку он использует PIL, массив numpy должен соответствовать форматам изображения, давая мне максимум 4 "цветных" канала.
Я хочу иметь возможность изменять произвольные изображения, с любым количеством из "цветных" каналов. Мне было интересно, есть ли простой способ сделать это в scipy/numpy, или если мне нужно свернуть свой собственный.
у меня есть две идеи о том, как состряпать себе:
- функция, которая работает
scipy.misc.imresize
на каждом канале отдельно - создать свой собственный, используя
scipy.ndimage.interpolation.affine_transform
первый, вероятно, будет медленным для больших данных, а второй, похоже, не предлагает никакого другого метода интерполяции, кроме сплайнов.
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-изображений, вы можете использовать преобразование.масштабирование и укажите множитель или масштаб, как при интерполяции.зум.