Конечно, можно векторизовать последний цикл for в вашем коде, поскольку каждая итерация не зависит от значений, вычисленных в итерации ранее.
Но, честно говоря, это было не так просто, как я думал, что это будет ...
Мой подход примерно в 800-1000 раз быстрее вашего текущего цикла. Я заменил массив и имена переменных в верхнем регистре на имена в нижнем регистре, используя подчеркивания. Верхний регистр обычно зарезервирован для классов в Python. Вот причина странной раскраски кода в вашем вопросе.
if sensor_num > 0:
mask = ( # create a mask where the condition is True
((shadows[:, :, 0] == 255) & # R=255
(shadows[:, :, 1] == 255) & # G=255
(shadows[:, :, 2] == 255)) & # B=255
((final[:, :, 0] == 0) & # R=0
(final[:, :, 1] == 0) & # G=0
(final[:, :, 2] == 255))) # B=255
final[mask] = np.array([255, 255, 255]) # set Final to white where mask is True
else:
final = copy.deepcopy(shadows)
RGB-значения, конечно, могут быть заменены поиском предопределенных значений, таких как colours
dict
. Но я бы предложил использовать массив для хранения цветов, особенно если вы планируете индексировать его с помощью чисел:
colours = np.array([[255, 255, 255], [0, 0, 255]])
так что маска будет выглядеть так:
mask = ( # create a mask where the condition is True
((shadows[:, :, 0] == colours[0, 0]) & # R=255
(shadows[:, :, 1] == colours[0, 1]) & # G=255
(shadows[:, :, 2] == colours[0, 2])) & # B=255
((final[:, :, 0] == colours[1, 0]) & # R=0
(final[:, :, 1] == colours[1, 1]) & # G=0
(final[:, :, 2] == colours[1, 2]))) # B=255
final[mask] = colours[0] # set Final to white where mask is True
Конечно, это также работает с использованием dict
.
Чтобы ускорить этот процесс, вы можете заменить сравнение RGC в маскировании некоторым сравнением с самим массивом (вычисление по трафарету). Это примерно на 5% быстрее для вашего размера массива, при этом разница в скорости увеличивается с увеличением размера массива, но вы теряете гибкость сравнения других цветов, просто изменяя записи в colours
array / dict.
Маска с трафаретными операциями выглядит так:
mask = ( # create a mask where the condition is True
((shadows[:, :, 0] == shadows[:, :, 1]) & # R=G
(shadows[:, :, 1] == shadows[:, :, 2]) & # G=B
(shadows[:, :, 2] == colours[0, 2])) & # R=G=B=255
((final[:, :, 0] == final[:, :, 1]) & # R=G
(final[:, :, 1] == colours[1, 1]) & # G=0
(final[:, :, 2] == colours[1, 2]))) # B=255
Это должно существенно ускорить ваши вычисления.
Части другого кода также могут быть оптимизированы. Но, конечно, это того стоит, только если это не узкое место.
Только один пример: вместо вызова random.randint
каждого цикла вы можете вызвать его один раз и создать случайный массив (а также массивы + - DotRadius), а затем выполнить цикл по этому массиву:
ypos = np.random.randint(DotRadius, h-DotRadius, size=NumberOfDots)
ypos_plus_dot_radius = ypos + DotRadius
ypos_minus_dot_radius = ypos - DotRadius
xpos = np.random.randint(DotRadius, w-DotRadius, size=NumberOfDots)
xpos_plus_dot_radius = xpos + DotRadius
xpos_minus_dot_radius = xpos - DotRadius
for dot in range(NumberOfDots):
yrange = np.arange(ypos_minus_dot_radius[dot], ypos_plus_dot_radius[dot]) # make range instead of looping
# looping over xrange imho can't be avoided without further matrix operations
for i in range(xpos_minus_dot_radius[dot], xpos_plus_dot_radius[dot]):
# make a mask for the y-positions where the condition is true and
# index the y-axis of Shadows with this mask:
Shadows[yrange[np.sqrt((xpos[dot] - i)**2 + (ypos[dot] - yrange)**2) < DotRadius], i] = colours[1]
# colours[1] can of course be replaced with any 3-element array or single integer/float