用JavaScript编写查找哪两种颜色混合成第三种颜色的算法

4
我正在寻找一个库/算法/技术,可以使用三个加性或减性颜色,并确定哪两种组合会生成某种颜色x
这不是一个正确的例子(因为我对颜色理论了解不多),但这是为了说明这一点。假设你有一种颜色,像绿褐色#45512b。要解决的问题是,针对两个系统(加性和减性),找出能够生成绿褐色(给定颜色)的颜色对。
所以你有“绿褐色”#45512b的值,并想知道混合在一起形成这种颜色的颜料。也许是#fff123#bbb456通过减法混合形成绿褐色(只是举个例子)。然后对于加性混合,找出用于计算模型中的3种基本光颜色的两种光阴影,它们结合起来形成绿褐色。
基本上就是寻找这个:
function additiveComponents(color) {
  return [ a, b ]
}

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

输入颜色不需要以十六进制格式,任何颜色空间都可以使用。但最终我希望将两个输出值转换回十六进制值。
我能想象的一种天真的方法是采用反向算法(混合两种颜色生成第三种颜色的算法),并尝试每种颜色的组合,直到找到正确的颜色。但那将非常低效,想知道是否有更好的方法或标准技术。

我是否漏掉了什么,难道不是有许多颜色可以相加形成一种颜色吗? - dwjohnston
无论如何 - xolor 对你是否有效? - dwjohnston
我完全不知道,哈哈,但我能看得出来。 - Lance
不错!它有这个功能: xolorObject.add(otherColor) - 返回两种颜色的加性混合。 xolorObject.subtractive(otherColor) - 返回两种颜色的减法混合。但是,仍然存在同样的问题,如何执行该操作的_reverse_。 - Lance
唉,它没有我要找的功能 :/ - Lance
1个回答

2

使用RGB颜色模型。我假设您拥有每个通道8位的颜色c0 =(r0,g0,b0),并且想要知道混合回c0c1,c2

加色混合(光源)

Original Answer翻译成"最初的回答"

  1. chose one color c1

    to be able to mix up to c0 the c1 must be less or equal to c0 on per channel bases. So for example random lesser color:

    r1 = Random(r0);
    g1 = Random(g0);
    b1 = Random(b0);
    
  2. compute the missing color c2

    simply use the additive logic:

    c0 = c1 + c2
    

    so

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

减法混合(滤镜、颜料)

  1. chose one color c1

    this time c1 must be c1>=c0 so again random such color example:

    r1 = r0 + Random(255-r0);
    g1 = g0 + Random(255-g0);
    b1 = b0 + Random(255-b0);
    
  2. compute the missing color c2

    simply use the substractive logic:

    c0 = c1 - c2
    

    so

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

[编辑1] 示例

我刚刚编写了一个简单的C++/VCL应用程序来测试这个功能。因此,我有3个滚动条来选择目标颜色的RGB值,然后一些面板来显示及其混合以视觉上验证其正常工作。以下是代码:

//$$---- 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 事件,该事件在任何一个滚动条更改时均会被调用。它计算添加逻辑和减法逻辑的 c1,c2 颜色,并将颜色输出到面板。

它可以在没有任何问题的情况下运行...顺便说一句,您是正确的,即使我的 Random(x) 也生成了 x,所以限制应该是 255(我已经修复了答案)。

以下是完整的源代码(BDS2006 C++/VCL/Win32) 和 Win32 二进制文件:

注:保留html标签。


@LancePollard 这是一个简单的线性方程式... A + B = C 或者 A - B = C,其中 A,B,C 不能为负数,这就是为什么你需要选择比目标值 C 更小或更大的颜色作为 A。除此之外,你可以选择任何 A 并计算出 B,使它们组合成 C - Spektre
还有一个问题,就是有多少种颜色可以混合成第三种颜色,是只有几种,还是成千上万,甚至是数百万。 - Lance
@LancePollard 在整数上,你的限制是可能的计数,以总结给定颜色(如果你有每个通道的8位,那么可供选择的可能颜色只有256^3,并且由于约束<或>,你只能使用其中的一部分……越接近白/黑色,可选择的颜色就越少......但在浮点数上,你几乎没有限制,直到遇到精度限制为止。 - Spektre
请你看一下我的 fiddle,我现在尝试的时候得到了错误的混合结果。 - Lance
@LancePollard 看看编辑1,这样你就有比较的东西了...我在那里没有使用浮点数,只用整数运算...我敢打赌你正在错误地混合使用浮点数和整数运算。不幸的是,我不会编写JAVASCRIPT代码,所以我无法调试,但我希望代码中有一些入口点或事件,或者至少有硬编码的测试用例和一些输出,但我在你的代码中没有看到任何这样的东西... - Spektre
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接