RGB值加法颜色混合算法

我正在寻找一种算法来为RGB值进行加色混合。

是否像将RGB值一起添加到最大值256一样简单?

(r1, g1, b1) + (r2, g2, b2) =
    (min(r1+r2, 256), min(g1+g2, 256), min(b1+b2, 256))  

这取决于你想要什么,它可以帮助看到不同方法的结果。

如果你想

Red + Black        = Red
Red + Green        = Yellow
Red + Green + Blue = White
Red + White        = White 
Black + White      = White

然后用夹子添加工作(例如min(r1 + r2, 255) )这更像您所提到的光照模型。

如果你想

Red + Black        = Dark Red
Red + Green        = Dark Yellow
Red + Green + Blue = Dark Gray
Red + White        = Pink
Black + White      = Gray

那么您需要对这些值进行平均(例如(r1 + r2) / 2 )。这对于减轻/加深颜色和创建渐变效果更好。


要使用Alpha通道混合,您可以使用以下公式:

r = new Color();
r.A = 1 - (1 - fg.A) * (1 - bg.A);
if (r.A < 1.0e-6) return r; // Fully transparent -- R,G,B not important
r.R = fg.R * fg.A / r.A + bg.R * bg.A * (1 - fg.A) / r.A;
r.G = fg.G * fg.A / r.A + bg.G * bg.A * (1 - fg.A) / r.A;
r.B = fg.B * fg.A / r.A + bg.B * bg.A * (1 - fg.A) / r.A;

fg是油漆的颜色。 bg是背景。 r是最终的颜色。 1.0e-6只是一个非常小的数字,以补偿舍入误差。

注意:这里使用的所有变量都在[0.0,1.0]范围内。 如果要使用范围[0,255]中的值,则必须除以或乘以255。

例如,在50%绿色之上的50%红色:

// background, 50% green
var bg = new Color { R = 0.00, G = 1.00, B = 0.00, A = 0.50 };
// paint, 50% red
var fg = new Color { R = 1.00, G = 0.00, B = 0.00, A = 0.50 };
// The result
var r = new Color();
r.A = 1 - (1 - fg.A) * (1 - bg.A); // 0.75
r.R = fg.R * fg.A / r.A + bg.R * bg.A * (1 - fg.A) / r.A; // 0.67
r.G = fg.G * fg.A / r.A + bg.G * bg.A * (1 - fg.A) / r.A; // 0.33
r.B = fg.B * fg.A / r.A + bg.B * bg.A * (1 - fg.A) / r.A; // 0.00

结果颜色为: (0.67, 0.33, 0.00, 0.75)或75%棕色(或深橙色)。


你也可以反转这些公式:

var bg = new Color();
if (1 - fg.A <= 1.0e-6) return null; // No result -- 'fg' is fully opaque
if (r.A - fg.A < -1.0e-6) return null; // No result -- 'fg' can't make the result more transparent
if (r.A - fg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important
bg.A = 1 - (1 - r.A) / (1 - fg.A);
bg.R = (r.R * r.A - fg.R * fg.A) / (bg.A * (1 - fg.A));
bg.G = (r.G * r.A - fg.G * fg.A) / (bg.A * (1 - fg.A));
bg.B = (r.B * r.A - fg.B * fg.A) / (bg.A * (1 - fg.A));

要么

var fg = new Color();
if (1 - bg.A <= 1.0e-6) return null; // No result -- 'bg' is fully opaque
if (r.A - bg.A < -1.0e-6) return null; // No result -- 'bg' can't make the result more transparent
if (r.A - bg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important
fg.A = 1 - (1 - r.A) / (1 - bg.A);
fg.R = (r.R * r.A - bg.R * bg.A * (1 - fg.A)) / fg.A;
fg.G = (r.G * r.A - bg.G * bg.A * (1 - fg.A)) / fg.A;
fg.B = (r.B * r.A - bg.B * bg.A * (1 - fg.A)) / fg.A;

这些公式将计算背景或油漆颜色必须是产生给定的最终颜色。


如果你的背景不透明,结果也是不透明的。 然后前景色可以采用具有不同alpha值的一系列值。 对于每个通道(红色,绿色和蓝色),您必须检查哪个范围的alpha结果为有效值(0 - 1)。


有趣的事实:计算机RGB值来自光子通量的平方根。 所以作为一般功能,你的数学应该考虑到这一点。 对于给定频道的这一般功能是:

blendColorValue(a, b, t)
    return sqrt((1 - t) * a^2 + t * b^2)

其中,a和b是要混合的颜色,t是从0到1的数字,代表您想要在a和b之间混合的点。

Alpha通道不同; 它不代表光子强度,只是应该显示的背景的百分比; 所以在混合alpha值时,线性平均值就足够了:

blendAlphaValue(a, b, t)
    return (1-t)*a + t*b;

所以,为了处理混合两种颜色,使用这两个函数,下面的伪代码应该对你有好处:

blendColors(c1, c2, t)
    ret
    [r, g, b].each n ->
        ret[n] = blendColorValue(c1[n], c2[n], t)
    ret.alpha = blendAlphaValue(c1.alpha, c2.alpha, t)
    return ret

顺便提一句,我渴望一种编程语言和键盘,它们都允许干净地表示(或更多)数学表达式(联合的unicode字符不适用于上标,符号和大量其他字符)并正确解释它。 sqrt((1-t)* pow(a,2)+ t * pow(b,2))只是不读为干净的。

链接地址: http://www.djcxy.com/p/87023.html

上一篇: Algorithm for Additive Color Mixing for RGB Values

下一篇: Java Regex: extract a substring from a pattern occurring multiple times