То, что вы делаете по своей сути, требует зацикливания, но если вы сможете переместить это зацикливание в ноль, оно часто будет ускоряться в 5-20 раз.
В вашем случае вы пытаетесь сделать следующее:сравнить каждый пиксель с его соседями.Как вы можете сделать это как операцию всего массива?Просто: сравните массив с тем же массивом, смещенным на 1.
Вот более простой пример:
>>> a = np.array([1,2,4,8,16])
>>> for i in range(1, len(a)):
... print(a[i] - a[i-1], end=' ')
1 2 4 8
>>> print(a[1:] - a[:-1])
[1 2 4 8]
Итак, для двумерного массива это просто:
north = a[:-1]
ne = a[:-1,1:]
east = a[:,1:]
se = a[1:,1:]
south = a[1:]
sw = a[1:,:-1]
west = a[:,:-1]
nw = a[:-1,:-1]
Обратите внимание, что это не тратит много времени и памяти не создает 8 дополнительных массивов;он просто создает 8 представлений над одной и той же памятью.
См. этот ответ на compsci , где приведен пример использования этих сдвинутых массивов для симуляции Conway Game of Life.
Есливы хотите обрабатывать границы по-разному, вам может понадобиться «растянуть ноль» массива, но это единственная сложность, с которой вы, вероятно, столкнетесь.
Однако есть предел тому, скольковы можете получить выгоду от numpy, если храните в нем объекты Python.Обычно вы хотите хранить массивы чисел.
Я не знаю, что находится в ваших Pixel
объектах, но давайте представим, что это просто значения цвета, как три числа с плавающей запятой.В этом случае вы можете использовать 2D-массив со структурированным d-типом из трех чисел с плавающей запятой или просто 3D-массив (строка за столбцом по rgb), в любом случае используйте значения NaN вместо None
.
ЕслиВы делаете это, операции в массиве могут работать на почти машинных скоростях, включая использование SIMD-операций для параллелизма данных.Если нет, то только зацикливание происходит на родных скоростях;арифметика внутри цикла все еще такая же медленная, как в не-Numpy Python.