RGB值加法颜色混合algorithm

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

是一样简单的RGB值加在一起,最多256?

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

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

如果你想

红+黑=红
红+绿=黄
红+绿+蓝=白
红+白=白 
黑+白=白

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

如果你想

红+黑=深红
红+绿=深黄
红+绿+蓝=深灰
红+白=粉红
黑+白=灰

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

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

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

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

注意:这里使用的所有variables都在[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(); rA = 1 - (1 - fg.A) * (1 - bg.A); // 0.75 rR = fg.R * fg.A / rA + bg.R * bg.A * (1 - fg.A) / rA; // 0.67 rG = fg.G * fg.A / rA + bg.G * bg.A * (1 - fg.A) / rA; // 0.33 rB = fg.B * fg.A / rA + bg.B * bg.A * (1 - fg.A) / rA; // 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 (rA - fg.A < -1.0e-6) return null; // No result -- 'fg' can't make the result more transparent if (rA - fg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important bg.A = 1 - (1 - rA) / (1 - fg.A); bg.R = (rR * rA - fg.R * fg.A) / (bg.A * (1 - fg.A)); bg.G = (rG * rA - fg.G * fg.A) / (bg.A * (1 - fg.A)); bg.B = (rB * rA - 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 (rA - bg.A < -1.0e-6) return null; // No result -- 'bg' can't make the result more transparent if (rA - bg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important fg.A = 1 - (1 - rA) / (1 - bg.A); fg.R = (rR * rA - bg.R * bg.A * (1 - fg.A)) / fg.A; fg.G = (rG * rA - bg.G * bg.A * (1 - fg.A)) / fg.A; fg.B = (rB * rA - bg.B * bg.A * (1 - fg.A)) / fg.A; 

公式会计算出背景或油漆的颜色必须是产生给定的结果颜色。


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

有趣的事实:计算机的RGB值是从光子通量的平方根衍生出来的。 所以作为一个普通的function,你的math应该考虑到这一点。 给定频道的一般function是:

 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 

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

几点:

  • 我想你想用min而不是max
  • 我想你想用255而不是256

这会给:

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

然而,混合颜色的“自然”方式是使用平均值,然后你不需要min:

(r1,g1,b1)+(r2,g2,b2)=((r1 + r2)/ 2,(g1 + g2)/ 2,(b1 + b2)/ 2)

Javascript函数来混合rgba颜色

c1,c2和结果 – JSON类似于c1 = {r:0.5,g:1,b:0,a:0.33}

  var rgbaSum = function(c1, c2){ var a = c1.a + c2.a*(1-c1.a); return { r: (c1.r * c1.a + c2.r * c2.a * (1 - c1.a)) / a, g: (c1.g * c1.a + c2.g * c2.a * (1 - c1.a)) / a, b: (c1.b * c1.a + c2.b * c2.a * (1 - c1.a)) / a, a: a } } 

是的,就这么简单。 另一种select是find平均值(用于创build渐变)。

这实际上取决于你想达到的效果。

但是,当Alpha被添加时,它变得复杂。 有一些不同的方法来使用alpha进行混合。

一个简单的alpha混合的例子: http : //en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending

通过添加 CMYK 空间中的 PYTHON 色彩 混合

一种可能的方法是首先将颜色转换为CMYK格式,将它们添加到那里,然后重新转换为RGB。

以下是Python中的一个示例代码:

 rgb_scale = 255 cmyk_scale = 100 def rgb_to_cmyk(self,r,g,b): if (r == 0) and (g == 0) and (b == 0): # black return 0, 0, 0, cmyk_scale # rgb [0,255] -> cmy [0,1] c = 1 - r / float(rgb_scale) m = 1 - g / float(rgb_scale) y = 1 - b / float(rgb_scale) # extract out k [0,1] min_cmy = min(c, m, y) c = (c - min_cmy) m = (m - min_cmy) y = (y - min_cmy) k = min_cmy # rescale to the range [0,cmyk_scale] return c*cmyk_scale, m*cmyk_scale, y*cmyk_scale, k*cmyk_scale def cmyk_to_rgb(self,c,m,y,k): """ """ r = rgb_scale*(1.0-(c+k)/float(cmyk_scale)) g = rgb_scale*(1.0-(m+k)/float(cmyk_scale)) b = rgb_scale*(1.0-(y+k)/float(cmyk_scale)) return r,g,b def ink_add_for_rgb(self,list_of_colours): """input: list of rgb, opacity (r,g,b,o) colours to be added, o acts as weights. output (r,g,b) """ C = 0 M = 0 Y = 0 K = 0 for (r,g,b,o) in list_of_colours: c,m,y,k = rgb_to_cmyk(r, g, b) C+= o*c M+=o*m Y+=o*y K+=o*k return cmyk_to_rgb(C, M, Y, K) 

结果你的问题将是(假设你的两种颜色的一半的混合物:

 r_mix, g_mix, b_mix = ink_add_for_rgb([(r1,g1,b1,0.5),(r2,g2,b2,0.5)]) 

那里的0.5是在那里说我们混合50%的第一个颜色和50%的第二个颜色。

这里有一个高度优化的独立c ++类,公共领域,带有浮点和两个不同优化的8位混合机制,包括函数和macros的格式,以及关于手头上的问题以及如何和重要性的技术讨论的,这个问题的优化:

https://github.com/fyngyrz/colorblending