Фильтрация определенных цветов при использовании генератора случайных цветов - PullRequest
0 голосов
/ 20 июня 2019

В настоящее время у меня генерируется случайный цвет, которым я очень доволен.Цвета, по большей части, привлекательны, и часть данных о посеве работает так, как задумано.

Проблема в том, что мне нужно предотвратить появление цветов белого и черного.На самом деле, я бы хотел опустить все оттенки белого и любые цвета, которые балансируют, будучи черными.

Вот моя функция:

seededColorGenerator = (id, delivery_id) => {
if (delivery_id) {
    return '#' + Math.floor((Math.abs(Math.sin(delivery_id) * 16777215)) % 16777215).toString(16)
} else{
    return '#' + Math.floor((Math.abs(Math.sin(id) * 16777215)) % 16777215).toString(16)
      }
}

Я думал о том, чтобы явно выбратьЗначения цвета и сохранение их в массиве, затем циклически просматривая их, чтобы проверить, был ли возвращен указанный цвет, и если да, то снова вызвать алгоритм, чтобы получить другой случайный цвет.Я не уверен, что это лучшая практика для этого.

Есть идеи?Я знаю, что есть много разговоров о генераторах случайных цветов, но мне еще предстоит увидеть хороший процесс фильтрации, связанный с ними.

Ответы [ 3 ]

1 голос
/ 20 июня 2019

Один простой способ - реализовать генератор псевдослучайных чисел (PRNG) и генерировать три числа от 0 до 255 с этим PRNG до тех пор, пока среднее из этих чисел больше 30 (не близко). до черного) и менее 220 (не близко к белому). Это не лучший алгоритм для избежания «белых» или «черных» цветов (mx-mn) / (mx+mn) меньше 0,2 (близко к серому), где mn и mx - самые маленькие и самый большой из этих чисел. Это не лучший алгоритм для избежания «серых» цветов (поскольку он не учитывает сложные вопросы восприятия цвета человеком и цветовых пространств), но он может быть «достаточно хорошим» для ваших целей. В этом смысле измените значения 30 и 220 , значение 0,2 , в зависимости от ваших потребностей. См. эту статью для лучшего алгоритма, чтобы найти цветность цвета (относительное насыщение).

Обратите внимание, что существуют определенные проблемы:

  • Если id или delivery_id не могут покрывать пространство состояний более 24 бит (т. Е. Существует более 2 ^ 24 возможных значений для id или delivery_id), есть некоторые цвета, которые вы не сможет генерировать с какой-либо заданной PRNG или хэш-функцией.
  • Ваш существующий код для seededColorGenerator может генерировать строку длиной менее 6 цифр от 16 до 16, если генерируемое им «случайное» число меньше 2 ^ 20, что может произойти с вероятностью 1/16. Это связано с тем, что toString(16) не выполняет добавление нуля при преобразовании числа в основание 16.

РЕДАКТИРОВАТЬ (24 июня): отредактировано из-за уточнения автора.

1 голос
/ 20 июня 2019

Похоже, вы используете шестнадцатеричное значение для цветового кода? Если вы разделите шестнадцатеричное значение на три две части, у вас будет R G B.

Затем сравните компоненты R G B друг с другом. Для белого / черного цвета все они будут одинаковыми либо FFFFFF, либо 000000. Темные цвета или, по существу, черные цвета будут близки к 0, и при достаточно похожих значениях вы можете добавить дополнительную проверку, чтобы эти значения не проходили.

Например, если все они ниже 30, найдите новый номер. Кроме того, если вы заинтересованы в удалении сероватых цветов, эти цвета также будут иметь аналогичные значения RGB А1-В2-С2 - голубовато-серый. Однако по мере приближения этих значений друг к другу они будут казаться менее насыщенными. Например. А1-В2-В2. Немного возиться с числами, и вы сможете понять, насколько они насыщенные / яркие.

Большая часть этого может быть выполнена с помощью операторов if или switch, небольшая рекурсия для повторного вызова функции и повторения поиска другого цвета, если вы хотите.

Наиболее раздражающей частью этого процесса будет преобразование в шестнадцатеричное число, получение последних двух цифр, а затем обратное преобразование в десятичное число для работы с соответствующими значениями. У кого-то еще может быть более простой подход.


x = Math.floor((Math.abs(Math.sin(delivery_id) * 16777215)) % 16777215).toString(16)
a = parseInt(x.slice(-2), 16)
b = parseInt(x.slice(2, 4), 16)
c = parseInt(x.slice(0,2),16) 

Это даст вам три десятичных значения для RGB. Вы можете работать с ними в их оригинальном гексе, хотя я еще не играл с этим в Javascript. Вы можете преобразовать их обратно в hex так же, как вы уже использовали toString (16), затем объединить строку и добавить символ # в начало.

Вот пример структуры if, которую вы можете использовать:

#Check for values too close to each other (unsaturated colors)
if (Math.abs(a-b)>30 && Math.abs(a-c) > 30 && Math.abs(b-c) > 30)
{
    seededColorGenerator(Math.random())
}
#check for colors that are too bright or too dark
else if ((a < 30 && b < 30 && c < 30) || (a < 225 && b < 225 && c > 225))
{
    seededColorGenerator(Math.random())
}
#Assuming the color was not dark/bright or unsaturated return it. 
else
{
    return '#' + x.toString(16)
}

1 голос
/ 20 июня 2019

Если у вас не так много цветов (<1000), я бы предложил использовать статический массив цветов, который можно легко отфильтровать, чтобы избежать математических вычислений для такой тривиальной операции. </p>

Конечно, вы можете использовать свою математикучтобы инициализировать этот массив в первый раз.

...