Вы можете почти напрямую использовать ваш индексный массив благодаря удачному расположению индексов внутри:
import numpy as np
# set up dummy input
M,N = 300,400
J = np.random.rand(M, N, 3)
T = np.array([np.random.randint(0, M, M*N), np.random.randint(0, N, M*N)])
# original
new_image = np.empty_like(J)
for r in range(0,M):
for s in range(0,N):
x, y = T[:,r*N+s]
new_image[r,s] = J[x,y]
# vectorized new
new_image_vect = J[tuple(T)].reshape(J.shape)
Проверка:
>>> np.array_equal(new_image, new_image_vect)
True
То, как работает вышеупомянутое, не совсем тривиально, потому что расширенная индексация - переменчивая вещь . То, что я написал выше, эквивалентно
J[(T[0,...], T[1,...])].reshape(J.shape) -> J[T[0,...], T[1,...]].reshape(J.shape)
Теперь первая часть более понятна: возьмите каждый элемент в первой строке T
и используйте его в качестве первого индекса J
, затем возьмите соответствующий элемент во второй строке T
и используйте его как соответствующий второй индекс J
. Эта часть вроде обложек J[x,y]
в зацикленной версии.
Но тогда, поскольку мы по существу индексируем массив с 1d массивами длины M*N
, форма полученного массива также будет иметь форму M*N
вдоль его первого измерения (и конечного измерения размера 3). Таким образом, нам нужно reshape
результат вернуться к (M,N,3)
.
Все это работает только напрямую, потому что индексы в T
хранятся в соответствии с C-смежным порядком памяти. Если бы это было не так, нам пришлось бы transpose
наших массивов туда и сюда, чтобы сгенерировать результирующий массив с правильной компоновкой.