Алгоритм поиска, какие два цвета смешиваются, чтобы сформировать третий цвет (в JavaScript)

Я ищу библиотеку / алгоритм / метод, чтобы взять 3 аддитивных или вычитающих цвета и определить, какая комбинация из двух приводит к некоторому цвету x.

Это неправильный пример (так как я еще не очень разбираюсь в теории цвета), но я хочу проиллюстрировать суть дела. Допустим, у вас зеленовато-коричневый цвет #45512b. Задача, которую необходимо решить, состоит в том, чтобы определить - для двух систем (аддитивной и вычитающей) - пару цветов, которые будут генерировать зеленовато-коричневый (данный цвет).

Итак, у вас есть значение "зеленовато-коричневый" #45512b, и вы хотите знать, какие краски смешиваются вместе, чтобы сформировать этот цвет. Может быть, это #fff123 и #bbb456, которые объединяются субтрактивно, образуя зеленовато-коричневый цвет (просто придумывая это). Затем для аддитивного смешивания, выяснение двух оттенков света из трех основных цветов света, используемых в вычислительных моделях, которые в сочетании образуют зеленовато-коричневый цвет.

В основном просто ищу это:

function additiveComponents(color) {
  return [ a, b ]
}

function subtractiveComponents(color) {
  return [ a, b ]
}

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

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


person Lance Pollard    schedule 05.06.2019    source источник
comment
Я что-то упускаю, но разве нет множества цветов, которые можно добавить для создания единого цвета?   -  person dwjohnston    schedule 05.06.2019
comment
В любом случае - работает ли xolor для вас?   -  person dwjohnston    schedule 05.06.2019
comment
Понятия не имею, лол, но я мог это видеть.   -  person Lance Pollard    schedule 05.06.2019
comment
Отлично! Он имеет следующее: xolorObject.add (otherColor) - возвращает аддитивное сочетание двух цветов. xolorObject.subtractive (otherColor) - возвращает вычитающее сочетание двух цветов. Однако все та же проблема, как сделать обратное этой операции.   -  person Lance Pollard    schedule 05.06.2019
comment
Увы, у него нет той функциональности, которую я ищу: /   -  person Lance Pollard    schedule 05.06.2019


Ответы (1)


используйте цветовую модель RGB. Я предполагаю, что у вас есть 8 бит на канал цвета c0=(r0,g0,b0) и вы хотите знать c1,c2, что смешивается с c0.

Аддитивное смешивание (источники света)

  1. выбрал один цвет c1

    чтобы иметь возможность смешивать до c0, c1 должно быть меньше или равно c0 для каждого канала. Так, например, случайный меньший цвет:

    r1 = Random(r0);
    g1 = Random(g0);
    b1 = Random(b0);
    
  2. вычислить недостающий цвет c2

    просто используйте аддитивную логику:

    c0 = c1 + c2
    

    so

    c2 = c0 - c1
    
    r2 = r0 - r1
    g2 = g0 - g1
    b2 = b0 - b1
    

Субстракционное смешение (фильтры, краски)

  1. выбрал один цвет c1

    на этот раз c1 должно быть c1>=c0, поэтому снова случайный пример такого цвета:

    r1 = r0 + Random(255-r0);
    g1 = g0 + Random(255-g0);
    b1 = b0 + Random(255-b0);
    
  2. вычислить недостающий цвет c2

    просто используйте вычитающую логику:

    c0 = c1 - c2
    

    so

    c2 = c1 - c0
    
    r2 = r1 - r0
    g2 = g1 - g0
    b2 = b1 - b0
    

[Edit1] пример

Я просто закодировал простое приложение C ++ / VCL, чтобы проверить это. Итак, у меня есть 3 полосы прокрутки, чтобы выбрать RGB целевого цвета c0, а затем несколько панелей, чтобы показать c1,c2 и их сочетание, чтобы визуально убедиться, что он работает должным образом. Вот код:

//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
const int _r=0; // channel order
const int _g=1;
const int _b=2;
const int _a=3;
union color
    {
    BYTE db[4]; // channel access
    DWORD dd;   // all 32 bit of color
    TColor c;   // VCL/GDI color  (you can ignore this)
    };
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    sb_rgbChange(this);
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::sb_rgbChange(TObject *Sender)
    {
    int i;
    color c0,c1,c2,c;
    Randomize();
    // get c0 color from R,G,B sliders
    c0.db[_r]=255-sb_r->Position;
    c0.db[_g]=255-sb_g->Position;
    c0.db[_b]=255-sb_b->Position;
    c0.db[_a]=0;
    pan_c0->Color=c0.c;     // just show color on some panel
    // additive
    for (i=0;i<3;i++) c1.db[i]=Random(c0.db[i]);  c1.db[_a]=0;  // generate c1 <= c0
    for (i=0;i<3;i++) c2.db[i]=c0.db[i]-c1.db[i]; c2.db[_a]=0;  // compute c2 = c0 - c1
    for (i=0;i<3;i++)  c.db[i]=c1.db[i]+c2.db[i]; c.db[_a]=0;   // verify  c  = c1 + c2
    pan_add_c1->Color=c1.c; // just show colors on some panels
    pan_add_c2->Color=c2.c;
    pan_add_c ->Color= c.c;
    // substractive
    for (i=0;i<3;i++) c1.db[i]=c0.db[i]+Random(255-c0.db[i]); c1.db[_a]=0;  // generate c1 >= c0
    for (i=0;i<3;i++) c2.db[i]=c1.db[i]-c0.db[i];             c2.db[_a]=0;  // compute c2 = c1 - c0
    for (i=0;i<3;i++)  c.db[i]=c1.db[i]-c2.db[i];              c.db[_a]=0;  // verify  c  = c1 - c2
    pan_sub_c1->Color=c1.c; // just show colors on some panels
    pan_sub_c2->Color=c2.c;
    pan_sub_c ->Color= c.c;
    }
//---------------------------------------------------------------------------

А вот скриншот:

скриншот

Единственный важный элемент кода - это событие sb_rgbChange, которое вызывается при любом изменении любой из 3 полос прокрутки. Он вычисляет c1,c2 цвета как для аддитивной, так и для вычитающей логики и выводит цвета на панели.

Он работает без проблем ... Кстати, вы правы, даже мой Random(x) генерирует x, поэтому предел должен быть 255 (я уже исправил ответ).

Вот полный исходный код (BDS2006 C ++ / VCL / Win32) и двоичный файл Win32:

person Spektre    schedule 05.06.2019
comment
Святая корова, я не думал, что это возможно! Мне понадобится немного времени, чтобы переварить это! Спасибо. - person Lance Pollard; 05.06.2019
comment
Не могли бы вы объяснить на более высоком уровне, как это работает :). Значит, это говорит о том, что вы можете смешать любые два цвета, и получится третий цвет? - person Lance Pollard; 06.06.2019
comment
@LancePollard - это простое линейное уравнение ... A + B = C или A - B = C с понятием, что A,B,C не может быть отрицательным, поэтому вам нужно выбрать A как меньший или больший цвет, чем целевой C. Кроме того, вы можете выбрать любой A и вычислить B, чтобы они объединялись с C. - person Spektre; 06.06.2019
comment
Хотите знать, правильно ли я понял: jsfiddle.net/oh3bpcgw/1. В основном интересно, является ли использование 255 правильным выбором вместо 256. - person Lance Pollard; 06.06.2019
comment
Также интересно, могу ли я сказать, хорошо, я хочу выяснить, какие 2 цвета генерируют x, и я хочу, чтобы один из компонентов / цветов был этим конкретным синим, поэтому другой должен быть y, или если есть только подмножество цвета, из которых я могу выбирать (т.е. значение startingWith). - person Lance Pollard; 06.06.2019
comment
Также есть вопрос, сколько пар цветов может смешаться с третьим цветом, если их всего несколько, или тысячи, или даже миллионы. - person Lance Pollard; 06.06.2019
comment
@LancePollard для целого числа, вы ограничены возможными подсчетами для суммирования заданных цветов (вы знаете, что если у вас 8 бит на канал, тогда есть только 256 ^ 3 возможных цветов для выбора и из-за ограничения ‹или›, которое вы можете использовать только часть из них ... чем ближе к белому / черному, тем меньше цветов на выбор ...), но на поплавках вы практически безграничны, пока не достигнете прецизионного барьера грубой очистки. - person Spektre; 07.06.2019
comment
@LancePollard 255/256 зависит от реализации Random. Тот, который я получил в моей среде C ++ Random(X), генерирует числа <0,X-1> и никогда X, следовательно, 256, но если ваш генерирует <0,X>, то 255 является правильным ... посмотрите в документации к своей среде, чтобы уточнить, какой из них ... или просто сгенерируйте и распечатайте 100 раз Random(5) и посмотрите, сгенерировал ли он 5 или нет .... - person Spektre; 07.06.2019
comment
Не могли бы вы проверить мою скрипку, когда я пробую это сейчас, получаю неверные результаты микширования. - person Lance Pollard; 12.06.2019
comment
@LancePollard См. Правку 1, так что вам есть с чем сравнивать ... Я не использую числа с плавающей запятой, только целочисленную математику ... Держу пари, вы неправильно смешиваете математику с плавающей запятой и целочисленную. К сожалению, я не кодирую JAVASCRIPT, поэтому я не могу отлаживать, но я бы ожидал некоторой точки входа или событий в коде или, по крайней мере, жестко закодированного тестового примера и некоторого вывода, но я не вижу ничего из этого в вашем коде ... - person Spektre; 12.06.2019