Функция создания цветовых кругов

Это то, что я псевдо-решал много раз, но так и не нашел решения.

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

В последний раз я проверял, что у JFreeChart есть этот точный алгоритм, и, поскольку это открытый исходный код, вы можете проверить, что он делает. Я знаю, что цвета, которые я получаю, не кажутся случайными расположенными по кругу или сфере, а скорее выбраны более конкретно.

Kathy Van Stone 30.09.2009 22:00
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
69
1
17 613
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Я где-то читал, что человеческий глаз не может различить менее 4 значений. так что об этом нужно помнить. Следующий алгоритм этого не компенсирует.

Я не уверен, что это именно то, что вам нужно, но это один из способов случайной генерации неповторяющихся значений цвета:

(будьте осторожны, впереди непоследовательный псевдокод)

//colors entered as 0-255 [R, G, B]
colors = []; //holds final colors to be used
rand = new Random();

//assumes n is less than 16,777,216
randomGen(int n){
   while (len(colors) < n){
      //generate a random number between 0,255 for each color
      newRed = rand.next(256);
      newGreen = rand.next(256);
      newBlue = rand.next(256);
      temp = [newRed, newGreen, newBlue];
      //only adds new colors to the array
      if temp not in colors {
         colors.append(temp);
      }
   }
}

Один из способов оптимизировать это для лучшей видимости - сравнить расстояние между каждым новым цветом и всеми цветами в массиве:

for item in color{
   itemSq = (item[0]^2 + item[1]^2 + item[2]^2])^(.5);
   tempSq = (temp[0]^2 + temp[1]^2 + temp[2]^2])^(.5);
   dist = itemSq - tempSq;
   dist = abs(dist);
}
//NUMBER can be your chosen distance apart.
if dist < NUMBER and temp not in colors {
   colors.append(temp);
}

Но такой подход значительно замедлит ваш алгоритм.

Другой способ - отказаться от случайности и систематически перебирать каждые 4 значения и добавлять цвет в массив в приведенном выше примере.

Разве это не фактор, в котором вы устанавливаете цвета?

Например, если вы используете идею Dillie-Os, вам нужно как можно больше смешивать цвета. 0 64 128 256 - от одного к другому. но 0 256 64 128 в колесе было бы больше "отдельно"

Имеет ли это смысл?

Ответ принят как подходящий

Моя первая мысль об этом - «как сгенерировать N векторов в пространстве, максимально удаленных друг от друга».

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

Если подумать над этой проблемой, было бы лучше отобразить цвета линейным образом, возможно (0,0,0) → (255,255,255) лексикографически, а затем распределить их равномерно.

Я действительно не знаю, насколько хорошо это будет работать, но так должно быть, скажем так:

n = 10

мы знаем, что у нас есть 16777216 цветов (256 ^ 3).

Мы можем использовать Пряжки Алгоритм 515, чтобы найти лексикографически проиндексированный цвет. Вероятно, вам придется отредактировать алгоритм, чтобы избежать переполнения, и, возможно, добавить некоторые незначительные улучшения скорости.

Это неверно, потому что цветовое пространство RGB не является однородным по восприятию.

adrienlucca.wordpress.com 13.01.2015 20:24

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

aliential 14.09.2015 15:46

Пожалуйста, рассмотрите возможность голосования / подписки на сайт StackExchange Color Theory: area51.stackexchange.com/proposals/110687/color-theory

Adi Shavit 22.06.2017 11:14

Было бы лучше найти цвета, максимально далекие от «перцептуально однородного» цветового пространства, например CIELAB (используя евклидово расстояние между координатами L *, a *, b * в качестве метрики расстояния) с последующим преобразованием в цветовое пространство по вашему выбору. Единообразие восприятия достигается за счет настройки цветового пространства для аппроксимации нелинейностей в зрительной системе человека.

Это, вероятно, лучшее решение, поскольку оно довольно простое. Однако есть и другие формулы цветового различия, которые следует учитывать, например, CIE2000 или даже CIECAM.

adrienlucca.wordpress.com 13.01.2015 20:25

Некоторые связанные ресурсы:

ColorBrewer - Наборы цветов, предназначенные для максимального различения для использования на картах.

Выход из RGBland: выбор цветов для статистической графики - технический отчет, описывающий набор алгоритмов для создания хороших (т.е. максимально различимых) наборов цветов в цветовом пространстве hcl.

Экранирование RGBland является обязательным к прочтению справочником по выбору воспринимаемых различимых цветовых палитр.

Drake Guan 19.07.2013 13:16

Вот код для равномерного распределения цветов RGB по цветовому кругу HSL указанной яркости.

class cColorPicker
{
public:
    void Pick( vector<DWORD>&v_picked_cols, int count, int bright = 50 );
private:
    DWORD HSL2RGB( int h, int s, int v );
    unsigned char ToRGB1(float rm1, float rm2, float rh);
};
/**

  Evenly allocate RGB colors around HSL color wheel

  @param[out] v_picked_cols  a vector of colors in RGB format
  @param[in]  count   number of colors required
  @param[in]  bright  0 is all black, 100 is all white, defaults to 50

  based on Fig 3 of http://epub.wu-wien.ac.at/dyn/virlib/wp/eng/mediate/epub-wu-01_c87.pdf?ID=epub-wu-01_c87

*/

void cColorPicker::Pick( vector<DWORD>&v_picked_cols, int count, int bright )
{
    v_picked_cols.clear();
    for( int k_hue = 0; k_hue < 360; k_hue += 360/count )
        v_picked_cols.push_back( HSL2RGB( k_hue, 100, bright ) );
}
/**

  Convert HSL to RGB

  based on http://www.codeguru.com/code/legacy/gdi/colorapp_src.zip

*/

DWORD cColorPicker::HSL2RGB( int h, int s, int l )
{
    DWORD ret = 0;
    unsigned char r,g,b;

    float saturation = s / 100.0f;
    float luminance = l / 100.f;
    float hue = (float)h;

    if (saturation == 0.0) 
    {
      r = g = b = unsigned char(luminance * 255.0);
    }
    else
    {
      float rm1, rm2;

      if (luminance <= 0.5f) rm2 = luminance + luminance * saturation;  
      else                     rm2 = luminance + saturation - luminance * saturation;
      rm1 = 2.0f * luminance - rm2;   
      r   = ToRGB1(rm1, rm2, hue + 120.0f);   
      g = ToRGB1(rm1, rm2, hue);
      b  = ToRGB1(rm1, rm2, hue - 120.0f);
    }

    ret = ((DWORD)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)));

    return ret;
}


unsigned char cColorPicker::ToRGB1(float rm1, float rm2, float rh)
{
  if      (rh > 360.0f) rh -= 360.0f;
  else if (rh <   0.0f) rh += 360.0f;

  if      (rh <  60.0f) rm1 = rm1 + (rm2 - rm1) * rh / 60.0f;   
  else if (rh < 180.0f) rm1 = rm2;
  else if (rh < 240.0f) rm1 = rm1 + (rm2 - rm1) * (240.0f - rh) / 60.0f;      

  return static_cast<unsigned char>(rm1 * 255);
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<DWORD> myCols;
    cColorPicker colpick;
    colpick.Pick( myCols, 20 );
    for( int k = 0; k < (int)myCols.size(); k++ )
        printf("%d: %d %d %d\n", k+1,
        ( myCols[k] & 0xFF0000 ) >>16,
        ( myCols[k] & 0xFF00 ) >>8,
        ( myCols[k] & 0xFF ) );

    return 0;
}

AFAIK легко перенести код с C++ на Java.

ravenspoint 14.01.2013 17:29

нет, когда я не понимаю всех вещей, связанных с сдвигом битов, среди прочего: /

CodeGuy 15.01.2013 09:15

Я предоставил URL-адреса, которые ссылаются на объяснения того, что делает код.

ravenspoint 15.01.2013 16:39

что, если я хочу указать, чтобы цвета отличались от цвета фона, который я предоставляю?

CodeGuy 16.01.2013 08:58

Рассчитайте «расстояние» между сгенерированными цветами и цветом фона. Не используйте цвет, наиболее близкий к вашему фону.

ravenspoint 16.01.2013 17:18

Возможно, это немного сработает, но это даст плохие результаты, CIELAB лучше

adrienlucca.wordpress.com 13.01.2015 20:26

function random_color($i = null, $n = 10, $sat = .5, $br = .7) {
    $i = is_null($i) ? mt_rand(0,$n) : $i;
    $rgb = hsv2rgb(array($i*(360/$n), $sat, $br));
    for ($i=0 ; $i<=2 ; $i++) 
        $rgb[$i] = dechex(ceil($rgb[$i]));
    return implode('', $rgb);
}

function hsv2rgb($c) { 
    list($h,$s,$v)=$c; 
    if ($s==0) 
        return array($v,$v,$v); 
    else { 
        $h=($h%=360)/60; 
        $i=floor($h); 
        $f=$h-$i; 
        $q[0]=$q[1]=$v*(1-$s); 
        $q[2]=$v*(1-$s*(1-$f)); 
        $q[3]=$q[4]=$v; 
        $q[5]=$v*(1-$s*$f); 
        return(array($q[($i+4)%6]*255,$q[($i+2)%6]*255,$q[$i%6]*255)); //[1] 
    } 
}

Поэтому просто вызовите функцию random_color(), где $i определяет цвет, $n - количество возможных цветов, $sat - насыщенность, а $br - яркость.

Вы можете объяснить, что в данном случае означает «я»? Вопрос задан для N номеров. Что такое параметр "i"?

CodeGuy 14.01.2013 11:39

В random_color()$i является «семенем» для генерации оттенка, должно быть числом от 0 до $n, если вы не вводите начальное значение (NULL), функция выбирает случайное значение. $n - это количество возможных цветов для заданной насыщенности и яркости, то есть количества цветов в палитре. Мы в основном разделяем 360 градусов оттенка на $n и используем $i в качестве множителя. Другими словами, более высокий $n даст вам больше цветов, более низкий $n даст вам меньше цветов, но больше будет отличаться друг от друга. $i определит цвет и всегда будет таким же, если вы продолжите использовать эту функцию. Надеюсь, это поможет.

Mauro 14.01.2013 22:35

Я понимаю! Спасибо за объяснение. Еще одна вещь ... какие-либо предложения о том, что делать, если у меня есть цвет фона, и я хочу быть как можно дальше от него для всех цветов?

CodeGuy 15.01.2013 09:16

Вам нужно добавить 180 градусов к оттенку вашего цвета, сохраняя насыщенность и ценность. Задайте для этого новый вопрос, вставьте ссылку сюда, и я объясню дальше!

Mauro 15.01.2013 20:37

Для достижения «наиболее различимого» нам необходимо использовать перцептивное цветовое пространство, такое как Lab (или любое другое перцептивно линейное цветовое пространство), отличное от RGB. Кроме того, мы можем квантовать это пространство, чтобы уменьшить его размер.

Сгенерируйте полное трехмерное пространство со всеми возможными квантованными записями и запустите алгоритм K-средних с K=N. Полученные центры / «средства» должны быть примерно максимально различимы друг от друга.

Другие вопросы по теме