RGB值的加色混合算法

Gai*_*din 63 algorithm colors

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

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

(r1, g1, b1) + (r2, g2, b2) =
    (min(r1+r2, 256), min(g1+g2, 256), min(b1+b2, 256))  
Run Code Online (Sandbox Code Playgroud)

Mar*_*rot 80

要使用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;
Run Code Online (Sandbox Code Playgroud)

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

注意:此处使用的所有变量都在[0.0,1.0]范围内.如果要使用[0,255]范围内的值,则必须除以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
Run Code Online (Sandbox Code Playgroud)

产生的颜色为:(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));
Run Code Online (Sandbox Code Playgroud)

要么

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;
Run Code Online (Sandbox Code Playgroud)

公式将计算背景或油漆颜色必须产生给定的结果颜色.


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


Dan*_*ant 56

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

如果你想

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)这对于减轻/变暗颜色和创建渐变效果更好.

  • @AlfonsoNishikawa不,它不是减法-第二种选择最好描述为“颜色混合”。减法仅在您在CMYK工作时才适用。 (2认同)

For*_*rdi 49

有趣的事实:计算机RGB值来自光子通量的平方根.因此,作为一般功能,您的数学应考虑到这一点.给定频道的一般功能是:

blendColorValue(a, b, t)
    return sqrt((1 - t) * a^2 + t * b^2)
Run Code Online (Sandbox Code Playgroud)

其中a和b是要混合的颜色,t是0-1中的数字,表示a和b之间所需混合的点.

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

blendAlphaValue(a, b, t)
    return (1-t)*a + t*b;
Run Code Online (Sandbox Code Playgroud)

因此,要使用这两个函数来处理混合两种颜色,以下伪代码应该对您有益:

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
Run Code Online (Sandbox Code Playgroud)

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

  • 如果可以的话,我会支持这十次. (4认同)
  • 平方根不太正确.在我们的程序中操作的数字已经受到[*gamma correction*](https://en.wikipedia.org/wiki/Gamma_correction),因为我们的眼睛非线性地响应光线,这样可以更好地利用有限的光线.范围.典型的伽玛校正是2.2,这与你在这个答案中推荐的2.0接近但不完全相同.在某些情况下,最好在伽马校正的空间中工作,例如生成灰度梯度. (4认同)

Dan*_*eer 9

几点:

  • 我想你想用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)


Ned*_*udi 6

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
       }
     } 
Run Code Online (Sandbox Code Playgroud)


pat*_*_ai 5

PYTHON 彩色 混音 THROUGH 加成 CMYK 空间

一种可行的方法是先将颜色转换为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)
Run Code Online (Sandbox Code Playgroud)

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

r_mix, g_mix, b_mix = ink_add_for_rgb([(r1,g1,b1,0.5),(r2,g2,b2,0.5)])
Run Code Online (Sandbox Code Playgroud)

0.5表示我们将第一种颜色的50%与第二种颜色的50%混合在一起。


nor*_*ius 5

在这里找到 Fordi 和 Markus Jarderot 在一个 Python 函数中建议的混合方法,该函数逐渐混合或混合两种颜色 A 和 B。

\n\n

“混合”模式对于在两种颜色之间进行插值很有用。t=0如果一种半透明颜色绘制在另一种(可能是半透明)颜色之上,“混合”模式(带有)对于计算结果颜色很有用。gamma校正会带来更好的结果,因为它考虑到物理光强度和(人类)感知的亮度是非线性相关的事实。

\n\n
\n\n
import numpy as np\n\ndef mix_colors_rgba(color_a, color_b, mode="mix", t=None, gamma=2.2):\n    """\n    Mix two colors color_a and color_b.\n\n    Arguments:\n        color_a:    Real-valued 4-tuple. Foreground color in "blend" mode.\n        color_b:    Real-valued 4-tuple. Background color in "blend" mode.\n        mode:       "mix":   Interpolate between two colors.\n                    "blend": Blend two translucent colors.\n        t:          Mixing threshold.\n        gamma:      Parameter to control the gamma correction.\n\n    Returns: \n        rgba:       A 4-tuple with the result color.\n\n    To reproduce Markus Jarderot\'s solution:\n            mix_colors_rgba(a, b, mode="blend", t=0, gamma=1.)\n    To reproduce Fordi\'s solution:\n            mix_colors_rgba(a, b, mode="mix", t=t, gamma=2.)\n    To compute the RGB color of a translucent color on white background:\n            mix_colors_rgba(a, [1,1,1,1], mode="blend", t=0, gamma=None)\n    """\n    assert(mode in ("mix", "blend"))\n    assert(gamma is None or gamma>0)\n    t = t if t is not None else (0.5 if mode=="mix" else 0.)\n    t = max(0,min(t,1))\n    color_a = np.asarray(color_a)\n    color_b = np.asarray(color_b)\n    if mode=="mix" and gamma in (1., None):\n        r, g, b, a = (1-t)*color_a + t*color_b\n    elif mode=="mix" and gamma > 0:\n        r,g,b,_ = np.power((1-t)*color_a**gamma + t*color_b**gamma, 1/gamma)\n        a = (1-t)*color_a[-1] + t*color_b[-1]\n    elif mode=="blend":\n        alpha_a = color_a[-1]*(1-t)\n        a = 1 - (1-alpha_a) * (1-color_b[-1])\n        s = color_b[-1]*(1-alpha_a)/a\n        if gamma in (1., None):\n            r, g, b, _ = (1-s)*color_a + s*color_b\n        elif gamma > 0:\n            r, g, b, _ = np.power((1-s)*color_a**gamma + s*color_b**gamma,\n                                  1/gamma)\n\n    return tuple(np.clip([r,g,b,a], 0, 1))\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

请参阅下面如何使用它。在“混合”模式下,左右颜色完全匹配color_acolor_b。在“混合”模式下,左侧的颜色是混合后t=0产生的颜色(和白色背景)。在该示例中,then 变得越来越半透明,直到到达。color_acolor_bcolor_acolor_b

\n\n

请注意,如果 alpha 值为 1.0,则混合和混合是等效的。

\n\n

结果

\n\n
\n\n

为了完整起见,这里是重现上述情节的代码。

\n\n
import matplotlib.pyplot as plt\nimport matplotlib as mpl\n\ndef plot(pal, ax, title):\n    n = len(pal)\n    ax.imshow(np.tile(np.arange(n), [int(n*0.20),1]),\n              cmap=mpl.colors.ListedColormap(list(pal)),\n              interpolation="nearest", aspect="auto")\n    ax.set_xticks([])\n    ax.set_yticks([])\n    ax.set_xticklabels([])\n    ax.set_yticklabels([])\n    ax.set_title(title)\n\n_, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=4,ncols=1)\n\nn = 101\nts = np.linspace(0,1,n)\ncolor_a = [1.0,0.0,0.0,0.7] #\xc2\xa0transparent red\ncolor_b = [0.0,0.0,1.0,0.8] # transparent blue\n\nplot([mix_colors_rgba(color_a, color_b, t=t, mode="mix", gamma=None)\n      for t in ts], ax=ax1, title="Linear mixing")\nplot([mix_colors_rgba(color_a, color_b, t=t, mode="mix", gamma=2.2)\n      for t in ts], ax=ax2, title="Non-linear mixing (gamma=2.2)")\nplot([mix_colors_rgba(color_a, color_b, t=t, mode="blend", gamma=None)\n      for t in ts], ax=ax3, title="Linear blending")\nplot([mix_colors_rgba(color_a, color_b, t=t, mode="blend", gamma=2.2)\n      for t in ts], ax=ax4, title="Non-linear blending (gamma=2.2)")\nplt.tight_layout()\nplt.show()\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n
Formulas:\n    Linear mixing (gamma=1):\n                r,g,b,a:    (1-t)*x + t*y\n    Non-linear mixing (gama\xe2\x89\xa01):\n                r,g,b:      pow((1-t)*x**gamma + t*y**gamma, 1/gamma)\n                a:          (1-t)*x + t*y\n    Blending (gamma=1):\n                a:          1-(1-(1-t)*x)*(1-y)\n                s:          alpha_b*(1-alpha_a)*a\n                r,g,b:      (1-s)*x + s*y\n    Blending (gamma\xe2\x89\xa01):\n                a:          1-(1-(1-t)*x)*(1-y)\n                s:          alpha_b*(1-alpha_a)/a\n                r,g,b:      pow((1-s)*x**gamma + s*y**gamma, 1/gamma)\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后,这是关于伽玛校正的有用读物。

\n