Вы хотите, чтобы цвета были равноудалены и как можно дальше друг от друга, при этом уже использовался белый и черный цвета.
Простой и удивительно хороший показатель для использования - среднее значениекрасный :
Если вы делаете это на лету, вам придется пересчитывать позиции ваших цветов с каждым новым добавляемым цветом, и если вы заранее знаете, сколько цветов, вы можете рассчитать их позициивсе сразу.
Вот пример реализации в python:
import numpy as np
from itertools import combinations
from scipy.optimize import minimize, Bounds
BLACK_AND_WHITE = np.array((0.0, 0.0, 0.0, 255.0, 255.0, 255.0))
мы рассматриваем три последовательных числа в массиве как представляющие цвет, заданные двумя такими триплетами, и используя расстояние, как определеновыше, наша функция расстояния -
def distance(c1, c2):
r = (c1[0] + c2[0]) / 2.0
coeffs = np.array(((2.0 + r/256), 4, (2.0 + (255 - r)/256.0)))
diff = c1 - c2
return np.sqrt(np.sum(coeffs * diff ** 2))
Мы хотим максимизировать минимальное расстояние между всеми парами цветов, что аналогично минимизации отрицательного минимального расстояния. Чтобы получить пары, мы используем combinations(..., 2)
, который делает именно это, и чтобы сделать итерацию по триплетам, мы изменяем массив цветов так, чтобы каждая строка содержала цвет:
def cost_function(x):
colors = np.concatenate((BLACK_AND_WHITE, x)).reshape(-1, 3)
return -min(mean_red_distance(color_pairs[0], color_pairs[1]) for color_pairs in combinations(colors, 2))
Теперь пришло времясворачивая нашу функцию стоимости, цвета могут варьироваться от 0 до 255:
def get_new_colors_after_adding(existing_colors):
if len(existing_colors):
guess = np.mod(existing_colors.reshape(-1, 3)[0] + np.array((100, 100, 100)), 256)
else:
guess = np.array((0, 255, 255))
guess = np.concatenate((guess, existing_colors))
# let all colors range between 0 and 255
result = minimize(cost_function, guess, bounds=Bounds(0, 255))
if not result.success:
raise ValueError('Failed adding new color')
return result.x
И, наконец, мы добавляем 10 цветов на каждом шаге и печатаем получившиеся триплеты:
if __name__ == '__main__':
# start with no colors
existing_colors = np.empty(0, dtype=np.int32)
# example of consequently adding colors.
for i in range(10):
existing_colors = get_new_colors_after_adding(existing_colors)
print(np.round(existing_colors.reshape(-1, 3)).astype(np.int))