像调色一样将颜色混合在一起(蓝色+黄色=绿色等),这是关于IT技术的一个问题标题。

6

我正在使用cocos2d库制作iOS游戏。

假设你有两个具有不同颜色的对象-以RGB定义为准:

Blue:    0,0,255
Yellow:  255,255,0

我想添加蓝色和黄色来制造绿色。
为了使事情变得复杂,假设蓝色物体比黄色物体大(为了论证的目的,假设比例为2:1),我添加了两倍于黄色的蓝色 - 如何正确计算这种新的(浅绿色)颜色。
我知道LAB * Color Space对于这种“自然颜色”非常有用,但我不确定如何使用它 - 特别是在cocos2d对象的上下文中,该对象(据我所知)仅限于使用RGB颜色方案。
我真的很感激关于如何实现这一点的实用帮助。非常感谢!

4月21日更新:在LAB*颜色空间中,蓝色+黄色≠绿色(当你看到它们位于同一频道的相反端点时,这是有道理的)。这实际上是一个非常棘手的问题,在SO上有一些讨论建议。似乎最终的答案是使用Kubelka-Munk方法,这是一个名为Krita的开源软件使用的方法。我无法找到任何相关内容(无论是公式还是代码本身)。

这个问题有一个链接,使用HSL的方式来类比绘画。我将尝试验证它是否有效,并在此处反馈结果。

同时,如果有人知道如何实现Kubelka-Munk或者在哪里可以找到代码,或者其他解决方案,我会非常非常高兴!


1
“蓝色+黄色”永远不等于绿色,虽然你在幼儿园就学过这个。实际上,这是指一个简单的减色模型,比如CMYK,其中的“1-青色-黄色≈绿色”(其中“青色≈蓝色”)。 - leftaroundabout
6个回答

5

没有一种色彩模式可以通过混合蓝色和黄色来得到绿色。你可以用水粉试试,唯一有效的方法是青色和黄色混合。这就是为什么你应该考虑从RGB转换到CMYK,需要时再转回来。以下是操作方法:

void toCMYK(float red, float green, float blue, float* cmyk)
{
  float k = MIN(255-red,MIN(255-green,255-blue));
  float c = 255*(255-red-k)/(255-k); 
  float m = 255*(255-green-k)/(255-k); 
  float y = 255*(255-blue-k)/(255-k); 

  cmyk[0] = c;
  cmyk[1] = m;
  cmyk[2] = y;
  cmyk[3] = k;
}

void toRGB(float c, float m, float y, float k, float *rgb)
{
  rgb[0] = -((c * (255-k)) / 255 + k - 255);
  rgb[1] = -((m * (255-k)) / 255 + k - 255);
  rgb[2] = -((y * (255-k)) / 255 + k - 255);
}

然后在您的代码中混合青色和黄色

float cmyk1[4];
toCMYK(255, 255, 0, cmyk1);  // yellow

float cmyk2[4];
toCMYK(0, 255, 255, cmyk2);  // cyan

// Mixing colors is as simple as adding
float cmykMix[] = { cmyk1[0] + cmyk2[0], cmyk1[1] + cmyk2[1], cmyk1[2] + cmyk2[2], cmyk1[3] + cmyk2[3] };

float rgb[3];
toRGB(cmykMix[0], cmykMix[1], cmykMix[2], cmykMix[3], rgb);  

NSLog(@"RGB mix = (%f, %f, %f)", rgb[0], rgb[1], rgb[2]);

运行代码将会产生:RGB混合 = (0.000000,255.000000,0.000000)

非常感谢您的回答,特别是提供的代码。我认为这将适用于黄色加蓝色 - 但我不知道它是否适用于其他颜色算术。我一直在研究这个问题,像这样的答案:https://dev59.com/dHRC5IYBdhLWcg3wJNgN#398268 让人觉得LAB是最好的选择。 - glenstorey
我用黄色和蓝色模型颜料完成了它,其中蓝色是一种深蓝色,不是“绿色”的 - 绝对不是“青色”,结果肯定是绿色的。这种情况不会发生在印刷染料中,但很容易发生在颜料中,有时也可能发生在染料中。(有关更多信息,请参见我的答案) - supercat

2

请查看此网站上的公式:http://www.easyrgb.com/index.php?X=MATH

我一直在做类似的事情,可以通过将RGB->XYZ->Lab进行转换来实现。然而,如果您要对大量像素进行操作,则计算成本相当高。

如果您想获得类似于人眼的混色效果,请不要使用RGB数学方法。


那么objectA和objectB都使用RGB进行着色 - 将RGB转换为XYZ,然后转换为LAB,将这两种颜色相加,然后再将它们转换回XYZ和RGB? - glenstorey
是的,正如我所写的那样,它需要大量的计算(我逐像素分析了整个图像),但可以得到不错的结果。 - Michał Zygar
当您在LAB空间中将两种颜色混合在一起时,应该如何正确地进行操作呢?只需要执行以下计算:L10.5 + L20.5, A10.5 + A20.5 和 B10.5 + B20.5 即可。 - Christoffer

2

我认为值得尝试使用HSL颜色空间。在添加颜色时,我们会插值它们的色相值(甚至考虑对象的权重)。如果颜色是100%饱和的,则亮度和饱和度值将相等。


1
染料在现实世界中的表现并不完全像减色模型所建议的那样。用于CYMK印刷的染料相当接近,因为它们是为此目的而配制的,但许多由天然物质制成的染料可能会表现出一些奇怪的行为。困难在于,虽然白光被感知为红、绿和蓝的组合,但它实际上由许多不同的波长组成——字面上是“彩虹的所有颜色”——每种波长将以不同的程度刺激眼中的红、绿和蓝受体。两种看起来相同的颜色实际上可能包含不同的波长组合;同样,两种染料在白光中观察时可能看起来相同,但吸收不同的波长组合。这样的染料在单独使用时可能看起来相同,但与其他物质结合使用时可能产生非常不同的结果。

尽管染料有时可能会有些棘手,但是油漆更糟糕。油漆中含有反射颗粒,并且击中油漆表面的一些光线将被第一个颗粒反射回来;从这个角度来看,它们就像加法颜色混合。例如,如果油漆含有20%的绿色颗粒,则无论它还包含什么其他颜色,都会反射大量的绿色光线。另一方面,击中油漆表面的某些光线将会反弹并击中多个颗粒。如果其中任何一个颗粒吸收了某种颜色的光子,则该光子不会被反射。在这方面,油漆的行为更像是减法颜色。实际上,油漆的行为有点像加性颜色,有点像减性颜色,有时则像是奇怪而古怪的东西,与两者都完全不同。


1
如果您查看HSL颜色空间轮,您会发现“混合”颜色位于两个原色之间。您可以利用这一点,通过像以下伪代码示例一样使用"Add"方法,实际上是一种"混合"方法:

如果您查看HSL颜色空间轮,您会发现“混合”颜色位于两个原色之间。您可以利用这一点,通过像以下伪代码示例一样使用"Add"方法,实际上是一种"混合"方法:

function int GetMixedHue(int firstHue, int secondHue, int firstWeight, int secondWeight) {
    int hueDiff = absolute(firstHue - secondHue);
    int proportionHue = hueDiff / (firstWeight + secondWeight);
    proportionHue = proportionHue * firstWeight;
    if (firstHue < secondHue)
        return firstHue + proportionHue;
    else
        return secondHue + proportionHue;
}

可能需要一些微调,而且我显然没有测试过。但基本的东西都在那里。我对加权方法有点不确定,但希望这能给你一个很好的起点。

请记住,这只是一种方法,还有其他方法,这只是我选择的其中一种。 HSL Color Wheel

编辑:

最终我用C#自己编写了以下方法。我决定不使用绝对值,因为这实际上使比例计算更容易。

public HSLColor MixColors(HSLColor colourA, HSLColor colourB, int proportionA, int proportionB)
{
//This is important so that colours mix correctly.So that Red + Blue = Magenta, not Green.
    int AHue = colourA.Hue;
    int BHue = colourB.Hue;
    if (colourA.Hue == 0 && colourB.Hue > 180)
    {
        AHue = 360;
    }
    else if (colourB.Hue == 0 && colourA.Hue > 180)
    {
        BHue = 360;
    }
//Get the total difference between all three aspects of the colours
    int hueDiff = BHue - AHue;
    double satDiff = colourB.Saturation - colourA.Saturation;
    double lumDiff = colourB.Luminance - colourA.Luminance;
    HSLColor newColour;
//Scale the amount of each difference proportional to the ratio.
    hueDiff = hueDiff / (proportionA + proportionB) * proportionA;
    satDiff = satDiff/ (proportionA + proportionB) * proportionA;
    lumDiff = lumDiff / (proportionA + proportionB) * proportionA;
    newColour = colourA.AddHue(hueDiff).AddSaturation(satDiff).AddLuminance(lumDiff);
    return newColour;
}

0

实际上,将RGB->XYZ->LAB转换似乎与RGB->LAB完全相同。


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