Как "масштабировать" массив numpy?
Я хотел бы масштабировать массив формы (h, w) с коэффициентом n, получая массив формы (h*n, w*n) с помощью.
Скажи, что у меня есть массив 2x2:
array([[1, 1],
[0, 1]])
Я хотел бы масштабировать массив, чтобы он стал 4х4:
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1]])
То есть значение каждой ячейки в исходном массиве копируется в 4 соответствующие ячейки в результирующем массиве. Предполагая произвольный размер массива и коэффициент масштабирования, каков наиболее эффективный способ сделать это?
4 ответа
Вы должны использовать продукт Kronecker, numpy.kron:
Вычисляет произведение Кронекера, составной массив, состоящий из блоков второго массива, масштабированный по первому
import numpy as np
a = np.array([[1, 1],
[0, 1]])
n = 2
np.kron(a, np.ones((n,n)))
который дает то, что вы хотите:
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1]])
Вы могли бы использовать repeat
:
In [6]: a.repeat(2,axis=0).repeat(2,axis=1)
Out[6]:
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1]])
Я не уверен, есть ли аккуратный способ объединить две операции в одну.
scipy.misc.imresize
можно масштабировать изображения. Он также может быть использован для масштабирования массивов NumPy:
#!/usr/bin/env python
import numpy as np
import scipy.misc
def scale_array(x, new_size):
min_el = np.min(x)
max_el = np.max(x)
y = scipy.misc.imresize(x, new_size, mode='L', interp='nearest')
y = y / 255 * (max_el - min_el) + min_el
return y
x = np.array([[1, 1],
[0, 1]])
n = 2
new_size = n * np.array(x.shape)
y = scale_array(x, new_size)
print(y)
Чтобы эффективно масштабировать, я использую следующий подход. Работает в 5 раз быстрее чем repeat
и в 10 раз быстрее, чем kron
, Сначала инициализируйте целевой массив, чтобы заполнить масштабированный массив на месте. И заранее определить ломтики, чтобы выиграть несколько циклов:
K = 2 # scale factor
a_x = numpy.zeros((h * K, w *K), dtype = a.dtype) # upscaled array
Y = a_x.shape[0]
X = a_x.shape[1]
myslices = []
for y in range(0, K) :
for x in range(0, K) :
s = slice(y,Y,K), slice(x,X,K)
myslices.append(s)
Теперь эта функция будет делать масштаб:
def scale(A, B, slices): # fill A with B through slices
for s in slices: A[s] = B
Или то же самое просто в одной функции:
def scale(A, B, k): # fill A with B scaled by k
Y = A.shape[0]
X = A.shape[1]
for y in range(0, k):
for x in range(0, k):
A[y:Y:k, x:X:k] = B