89

I'm looking for an algorithm to do additive color mixing for RGB values.

Is it as simple as adding the RGB values together to a max of 256?

(r1, g1, b1) + (r2, g2, b2) =
    (min(r1+r2, 256), min(g1+g2, 256), min(b1+b2, 256))  
casperOne
  • 73,706
  • 19
  • 184
  • 253
Gaidin
  • 1,381
  • 3
  • 13
  • 19

13 Answers13

99

To blend using alpha channels, you can use these formulas:

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 is the paint color. bg is the background. r is the resulting color. 1.0e-6 is just a really small number, to compensate for rounding errors.

NOTE: All variables used here are in the range [0.0, 1.0]. You have to divide or multiply by 255 if you want to use values in the range [0, 255].

For example, 50% red on top of 50% green:

// 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

Resulting color is: (0.67, 0.33, 0.00, 0.75), or 75% brown (or dark orange).


You could also reverse these formulas:

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));

or

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;

The formulas will calculate that background or paint color would have to be to produce the given resulting color.


If your background is opaque, the result would also be opaque. The foreground color could then take a range of values with different alpha values. For each channel (red, green and blue), you have to check which range of alphas results in valid values (0 - 1).

Markus Jarderot
  • 86,735
  • 21
  • 136
  • 138
  • 1
    What can you do about the "division by zero" problem, if fg.A and bg.A is both 0.0? This results is f.A = 0. And then I got a division by zero problem i.e. here: r.R = fg.R * fg.A / r.A + bg.R * bg.A * (1 - fg.A) / r.A; – nodepond Mar 07 '14 at 15:31
  • 1
    How do these formulas needed to be adjusted to blend a fg color with alpha onto an opaque bg? I have my desired result color and the bg color and with that information I need to determine what the fg color needs to be. – ubiquibacon Jul 17 '15 at 18:50
78

It depends on what you want, and it can help to see what the results are of different methods.

If you want

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

then adding with a clamp works (e.g. min(r1 + r2, 255)) This is more like the light model you've referred to.

If you want

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

then you'll need to average the values (e.g. (r1 + r2) / 2) This works better for lightening/darkening colors and creating gradients.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
Daniel LeCheminant
  • 50,583
  • 16
  • 120
  • 115
  • Am I wrong, or your second option is not an "Additive Color Mixing" but a "Substractive Color Mixing"? (and the title of the question is wrong, but doesn't matter) – Alfonso Nishikawa Oct 19 '17 at 18:37
  • 5
    @AlfonsoNishikawa no, it's not subtractive - the second option would best be described as "Color Blending". Subtractive would only be appropriate if you were working in CMYK. – Mark Ransom Nov 03 '17 at 03:35
68

Fun fact: Computer RGB values are derived from the square root of photon flux. So as a general function, your math should take that into account. The general function for this for a given channel is:

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

Where a and b are the colors to blend, and t is a number from 0-1 representing the point in the blend you want between a and b.

The alpha channel is different; it doesn't represent photon intensity, just the percent of background that should show through; so when blending alpha values, the linear average is enough:

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

So, to handle blending two colors, using those two functions, the following pseudocode should do you good:

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

Incidentally, I long for a programming language and keyboard that both permits representing math that (or more) cleanly (the combining overline unicode character doesn't work for superscripts, symbols, and a vast array of other characters) and interpreting it correctly. sqrt((1-t)*pow(a, 2) + t * pow(b, 2)) just doesn't read as clean.

Downgoat
  • 13,771
  • 5
  • 46
  • 69
Fordi
  • 2,798
  • 25
  • 20
  • 1
    Thank you, this was what I was looking for when searching for color mixing algorithm. The problem with the answers above (using linear mixing of rgb-values) is that they yield unnatural looking transitions between colours, with spots that are too dark. – James Apr 19 '15 at 10:48
  • 9
    Square root is not quite correct. The numbers being manipulated in our programs have been subjected to [*gamma correction*](https://en.wikipedia.org/wiki/Gamma_correction) because our eyes respond to light non-linearly, and this makes better use of the limited range. The typical gamma correction is 2.2, which is close to but not quite the same as the 2.0 you recommend in this answer. And in some cases it's better to work in gamma-corrected space, to generate a gray-scale gradient for example. – Mark Ransom Nov 02 '17 at 22:48
  • I've been playing with a toy that alternates two colors in rapid succession until they converge on a single color, and this mixing algorithm looks perfect! Clearly this is the correct math, I never knew it! Thank you!! – luqui May 18 '18 at 00:56
9

Few points:

  • I think you want to use min instead of max
  • I think you want to use 255 instead of 256

This will give:

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

However, The "natural" way of mixing colors is to use the average, and then you don't need the min:

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

Dani van der Meer
  • 6,169
  • 3
  • 26
  • 45
7

Javascript function to blend rgba colors

c1,c2 and result - JSON's like 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
       }
     } 
Community
  • 1
  • 1
Nedudi
  • 5,639
  • 2
  • 42
  • 37
5

PYTHON COLOUR MIXING THROUGH ADDITION IN CMYK SPACE

One possible way to do this is to first convert the colours to CMYK format, add them there and then reconvert to RGB.

Here is an example code in 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)

The result to your question would then be (assuming a half-half mixture of your two colours:

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

where the 0.5's are there to say that we mix 50% of the first colour with 50% of the second colour.

patapouf_ai
  • 17,605
  • 13
  • 92
  • 132
4

Find here the mixing methods suggested by Fordi and Markus Jarderot in one python function that gradually mixes or blends between two colors A and B.

The "mix" mode is useful to interpolate between two colors. The "blend" mode (with t=0) is useful to compute the resulting color if one translucent color is painted on top of another (possibly translucent) color. gamma correction leads to nicer results because it takes into consideration the fact that physical light intensity and perceived brightness (by humans) are related non-linearly.


import numpy as np

def mix_colors_rgba(color_a, color_b, mode="mix", t=None, gamma=2.2):
    """
    Mix two colors color_a and color_b.

    Arguments:
        color_a:    Real-valued 4-tuple. Foreground color in "blend" mode.
        color_b:    Real-valued 4-tuple. Background color in "blend" mode.
        mode:       "mix":   Interpolate between two colors.
                    "blend": Blend two translucent colors.
        t:          Mixing threshold.
        gamma:      Parameter to control the gamma correction.

    Returns: 
        rgba:       A 4-tuple with the result color.

    To reproduce Markus Jarderot's solution:
            mix_colors_rgba(a, b, mode="blend", t=0, gamma=1.)
    To reproduce Fordi's solution:
            mix_colors_rgba(a, b, mode="mix", t=t, gamma=2.)
    To compute the RGB color of a translucent color on white background:
            mix_colors_rgba(a, [1,1,1,1], mode="blend", t=0, gamma=None)
    """
    assert(mode in ("mix", "blend"))
    assert(gamma is None or gamma>0)
    t = t if t is not None else (0.5 if mode=="mix" else 0.)
    t = max(0,min(t,1))
    color_a = np.asarray(color_a)
    color_b = np.asarray(color_b)
    if mode=="mix" and gamma in (1., None):
        r, g, b, a = (1-t)*color_a + t*color_b
    elif mode=="mix" and gamma > 0:
        r,g,b,_ = np.power((1-t)*color_a**gamma + t*color_b**gamma, 1/gamma)
        a = (1-t)*color_a[-1] + t*color_b[-1]
    elif mode=="blend":
        alpha_a = color_a[-1]*(1-t)
        a = 1 - (1-alpha_a) * (1-color_b[-1])
        s = color_b[-1]*(1-alpha_a)/a
        if gamma in (1., None):
            r, g, b, _ = (1-s)*color_a + s*color_b
        elif gamma > 0:
            r, g, b, _ = np.power((1-s)*color_a**gamma + s*color_b**gamma,
                                  1/gamma)

    return tuple(np.clip([r,g,b,a], 0, 1))

See below how this can be used. In "mix" mode the left and right colors match exactly color_a and color_b. In "blend" mode, the left color at t=0 is the color that results if color_a is blended over color_b (and a white background). In the example, color_a then is made increasingly translucent until one arrives at color_b.

Note that blending and mixing are equivalent if the alpha values are 1.0.

Results


For completeness, here the code to reproduce the above plot.

import matplotlib.pyplot as plt
import matplotlib as mpl

def plot(pal, ax, title):
    n = len(pal)
    ax.imshow(np.tile(np.arange(n), [int(n*0.20),1]),
              cmap=mpl.colors.ListedColormap(list(pal)),
              interpolation="nearest", aspect="auto")
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    ax.set_title(title)

_, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=4,ncols=1)

n = 101
ts = np.linspace(0,1,n)
color_a = [1.0,0.0,0.0,0.7] # transparent red
color_b = [0.0,0.0,1.0,0.8] # transparent blue

plot([mix_colors_rgba(color_a, color_b, t=t, mode="mix", gamma=None)
      for t in ts], ax=ax1, title="Linear mixing")
plot([mix_colors_rgba(color_a, color_b, t=t, mode="mix", gamma=2.2)
      for t in ts], ax=ax2, title="Non-linear mixing (gamma=2.2)")
plot([mix_colors_rgba(color_a, color_b, t=t, mode="blend", gamma=None)
      for t in ts], ax=ax3, title="Linear blending")
plot([mix_colors_rgba(color_a, color_b, t=t, mode="blend", gamma=2.2)
      for t in ts], ax=ax4, title="Non-linear blending (gamma=2.2)")
plt.tight_layout()
plt.show()

Formulas:
    Linear mixing (gamma=1):
                r,g,b,a:    (1-t)*x + t*y
    Non-linear mixing (gama≠1):
                r,g,b:      pow((1-t)*x**gamma + t*y**gamma, 1/gamma)
                a:          (1-t)*x + t*y
    Blending (gamma=1):
                a:          1-(1-(1-t)*x)*(1-y)
                s:          alpha_b*(1-alpha_a)*a
                r,g,b:      (1-s)*x + s*y
    Blending (gamma≠1):
                a:          1-(1-(1-t)*x)*(1-y)
                s:          alpha_b*(1-alpha_a)/a
                r,g,b:      pow((1-s)*x**gamma + s*y**gamma, 1/gamma)

And finally, here a useful read about gamma correction.

normanius
  • 8,629
  • 7
  • 53
  • 83
3

When I came here I didn't find the "additive color mixing" algorithm I was actually looking for, which is also available in Photoshop and is described as "Screen" on Wikipedia. (Aka "brighten" or "invert multiply".) It produces a result similar to two light sources being combined.

With Screen blend mode the values of the pixels in the two layers are inverted, multiplied, and then inverted again. This yields the opposite effect to multiply. The result is a brighter picture.

Here it is:

// (rgb values are 0-255)
function screen(color1, color2) {
    var r = Math.round((1 - (1 - color1.R / 255) * (1 - color2.R / 255)) * 255);
    var g = Math.round((1 - (1 - color1.G / 255) * (1 - color2.G / 255)) * 255);
    var b = Math.round((1 - (1 - color1.B / 255) * (1 - color2.B / 255)) * 255);
    return new Color(r, g, b);
}
marsze
  • 15,079
  • 5
  • 45
  • 61
  • I hope this is what I am looking for, would this work for blending two different shades / tones of colors? For example, two blue values defined as: blue1= (17, 43, 154) and blue2 = (22, 56, 186) – Mohd Jun 19 '20 at 14:33
  • 1
    @Mohd Depends on what result you expect. Since this is additive mixing, the result color will always be brighter, because it adds both colors. If you want to "blend" the colors, resulting in a tone that is somewhere in-between, then no. For that, maybe use `b3 = {r: (b1.r + b2.r) / 2, g: (b1.g + b2.g) /2, ...` – marsze Jun 20 '20 at 09:17
  • You are correct; indeed the average over each channel did the job. – Mohd Jun 23 '20 at 13:51
3

Yes, it is as simple as that. Another option is to find the average (for creating gradients).

It really just depends on the effect you want to achieve.

However, when Alpha gets added, it gets complicated. There are a number of different methods to blend using an alpha.

An example of simple alpha blending: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending

John Gietzen
  • 48,783
  • 32
  • 145
  • 190
2

Have written/used something like @Markus Jarderot's sRGB blending answer (which is not gamma corrected since that is the default legacy) using C++

//same as Markus Jarderot's answer
float red, green, blue;
alpha = (1.0 - (1.0 - back.alpha)*(1.0 - front.alpha));
red   = (front.red   * front.alpha / alpha + back.red   * back.alpha * (1.0 - front.alpha));
green = (front.green * front.alpha / alpha + back.green * back.alpha * (1.0 - front.alpha));
blue  = (front.blue  * front.alpha / alpha + back.blue  * back.alpha * (1.0 - front.alpha));

//faster but equal output
alpha = (1.0 - (1.0 - back.alpha)*(1.0 - front.alpha));
red   = (back.red   * (1.0 - front.alpha) + front.red   * front.alpha);
green = (back.green * (1.0 - front.alpha) + front.green * front.alpha);
blue  = (back.blue  * (1.0 - front.alpha) + front.blue  * front.alpha);

//even faster but only works when all values are in range 0 to 255
int red, green, blue;
alpha = (255 - (255 - back.alpha)*(255 - front.alpha));
red   = (back.red   * (255 - front.alpha) + front.red   * front.alpha) / 255;
green = (back.green * (255 - front.alpha) + front.green * front.alpha) / 255;
blue  = (back.blue  * (255 - front.alpha) + front.blue  * front.alpha) / 255;

more info: what-every-coder-should-know-about-gamma

Top-Master
  • 7,611
  • 5
  • 39
  • 71
1

I was working on a similar problem and ended up here, but had to write my own implementation in the end. I wanted to basically "overlay" the new foreground color over the existing background color. (And without using an arbitrary midpoint like t. I believe my implementation is still "additive.") This also seems to blend very cleanly in all of my test-cases.

Here, new_argb just converts the int into a struct with 4 unsigned char so I can reduce the amount of bit-shifts.

int blend_argb(int foreground, int background)
{
    t_argb fg;
    t_argb bg;
    t_argb blend;
    double ratio;

    fg = new_argb(foreground);
    bg = new_argb(background);

    // If background is transparent,
    // use foreground color as-is and vice versa.
    if (bg.a == 255)
        return (foreground);
    if (fg.a == 255)
        return (background);

    // If the background is fully opaque,
    // ignore the foreground alpha. (Or the color will be darker.)
    // Otherwise alpha is additive.
    blend.a = ((bg.a == 0) ? 0 : (bg.a + fg.a));

    // When foreground alpha == 0, totally covers background color.
    ratio = fg.a / 255.0;
    blend.r = (fg.r * (1 - ratio)) + (bg.r * ratio);
    blend.g = (fg.g * (1 - ratio)) + (bg.g * ratio);
    blend.b = (fg.b * (1 - ratio)) + (bg.b * ratio);

    return (blend.a << 24 | blend.r << 16 | blend.g << 8 | blend.b);
}

For context, in my environment I'm writing color ints into a 1D pixel array, which is initialized with 0-bytes and increasing the alpha will make the pixel tend towards black. (0 0 0 0 would be opaque black and 255 255 255 255 would be transparent white... aka black.)

ngontjar
  • 111
  • 3
0

Here's a highly optimized, standalone c++ class, public domain, with floating point and two differently optimized 8-bit blending mechanisms in both function and macro formats, as well as a technical discussion of both the problem at hand and how to, and the importance of, optimization of this issue:

https://github.com/fyngyrz/colorblending

fyngyrz
  • 2,458
  • 2
  • 36
  • 43
  • Link-only answers aren't a good idea, links go bad and you're left with something worthless. If you can't post the code here, at least describe and summarize it. – Mark Ransom Jan 30 '16 at 05:20
  • 1
    I'd be happy to post the code here if SO had even _slightly_ as good a mechanism as Github does. But it doesn't. Not to mention SO's obnoxious licensing policies. As for a link to Github going bad, that's about as likely as a link to SO going bad. Links are what the web is all about. What I posted is 100% relevant to this question, and a superb set of solutions to this specific problem, which I have placed in the public domain. You are not being in *any* way helpful or useful with your remarks, you're just trying to make trouble. – fyngyrz Jan 30 '16 at 10:59
  • 1
    No, I'm trying to establish that StackOverflow has *answers*, not *links to* the answers. Google already has plenty of those. – Mark Ransom Jan 31 '16 at 15:41
  • 4
    I gave an answer relevant to the question. The answer contains a link to the code. SO doesn't have a mechanism to include a significant c class, nor does it have acceptable licensing for code that appears on the site, so what you want simply isn't possible. The choice is between answering including a link, or not answering at all. The latter does no one any good. The former is relevant, informative, and highly useful. As for Google, results there are a cesspit of irrelevancy and ads. So perhaps you should consider rethinking your position. Last word is yours. I'm content with my answer. – fyngyrz Jan 31 '16 at 17:04
  • 2
    It does seem a bit superficial to downvote a guy for posting a link to a solution residing in his own github repository. – BobRodes Mar 14 '18 at 05:16
0

Thank you Markus Jarderot, Andras Zoltan and hkurabko; here is the Python code for blending a list of RGB images.

Using Markus Jarderot's code we can generate RGBA color, then i use Andras Zoltan and hkurabko's method to trans RGBA to RGB.

Thank you!

import numpy as np
def Blend2Color(C1,C2):
    c1,c1a=C1
    c2,c2a=C2
    A = 1 - (1 - c1a) * (1 - c2a);
    if (A < 1.0e-6): 
        return (0,0,0) #Fully transparent -- R,G,B not important
    Result=(np.array(c1)*c1a+np.array(c2)*c2a*(1-c1a))/A
    return Result,A
def RGBA2RGB(RGBA,BackGround=(1,1,1)):# whilt background
    A=RGBA[-1]
    RGB=np.add(np.multiply(np.array(RGBA[:-1]),A),
               np.multiply(np.array(BackGround),1-A))
    return RGB

def BlendRGBList(Clist,AlphaList=None,NFloat=2,ReturnRGB=True,
                 RGB_BackGround=(1,1,1)):
    N=len(Clist)
    if AlphaList==None:
        ClistUse=Clist.copy()
    else:
        if len(AlphaList)==N:
            AlphaListUse=np.multiply(AlphaList,10**NFloat).astype(int)
            ClistUse=np.repeat(np.array(Clist), AlphaListUse, axis=0)
        else:
            raise('len of AlphaList must equal to len of Clist!')
    while N!=1:
        temp=ClistUse.copy()
        ClistUse=[]
        for C in temp[:-1]:
            c1,a1=C
            c2,a2=temp[-1]
            ClistUse.append(Blend2Color(C1=(c1,a1*(1-1/N)),C2=(c2,a2*1/N)))
        N=len(ClistUse)
    Result=np.append(ClistUse[0][0],ClistUse[0][1])
    if ReturnRGB:
        Result=RGBA2RGB(Result,BackGround=RGB_BackGround)

    return Result

Test

BlendRGBList([[(1,0,0),1],[(0,1,0),1]],ReturnRGB=True)
#array([0.75, 0.5 , 0.25])
BlendRGBList([[(1,0,0),1],[(0,1,0),1]],ReturnRGB=False)
#array([0.66666667, 0.33333333, 0.        , 0.75      ])
Ningrong Ye
  • 1,117
  • 11
  • 10