Algorithmus zum additiven Farbmischen für RGB-Werte

74

Ich suche nach einem Algorithmus zum additiven Farbmischen für RGB-Werte.

Ist es so einfach wie das Addieren der RGB-Werte zu maximal 256?

(r1, g1, b1) + (r2, g2, b2) =
    (min(r1+r2, 256), min(g1+g2, 256), min(b1+b2, 256))  
Gaidin
quelle
Warum brauchst du das? Eine einfache Addition liefert möglicherweise nicht immer die gewünschten Ergebnisse.
Dirkgently
3
Idealerweise würde es eine Farbmischung darstellen, als wäre es farbiges Licht. Ich kann mich irren, aber ich dachte, das ist es, was additive Farbmischung darstellt. Vielleicht bin ich falsch.
Gaidin
Sie haben absolut Recht, es sollte min sein.
Gaidin
Typischerweise reichen die Farbkanalwerte von 0 bis 255, nicht von 1 bis 256.
Mr Fooz

Antworten:

64

Es hängt davon ab, was Sie wollen, und es kann hilfreich sein, die Ergebnisse verschiedener Methoden zu sehen.

Falls Sie es wollen

Rot + Schwarz = Rot
Rot + Grün = Gelb
Rot + Grün + Blau = Weiß
Rot + Weiß = Weiß 
Schwarz + Weiß = Weiß

dann funktioniert das Hinzufügen mit einer Klammer (z. B. min(r1 + r2, 255)) Dies ähnelt eher dem Lichtmodell, auf das Sie sich bezogen haben.

Falls Sie es wollen

Rot + Schwarz = Dunkelrot
Rot + Grün = Dunkelgelb
Rot + Grün + Blau = Dunkelgrau
Rot + Weiß = Pink
Schwarz + Weiß = Grau

Dann müssen Sie die Werte mitteln (z. B. (r1 + r2) / 2). Dies funktioniert besser zum Aufhellen / Abdunkeln von Farben und zum Erstellen von Verläufen.

Daniel LeCheminant
quelle
Liege ich falsch oder ist Ihre zweite Option nicht eine "additive Farbmischung", sondern eine "substanzielle Farbmischung"? (und der Titel der Frage ist falsch, spielt aber keine Rolle)
Alfonso Nishikawa
3
@AlfonsoNishikawa nein, es ist nicht subtraktiv - die zweite Option würde am besten als "Farbmischung" beschrieben. Subtraktiv wäre nur angemessen, wenn Sie in CMYK arbeiten würden.
Mark Ransom
81

Zum Mischen mit Alphakanälen können Sie die folgenden Formeln verwenden:

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;

fgist die Lackfarbe. bgist der Hintergrund. rist die resultierende Farbe. 1.0e-6ist nur eine sehr kleine Zahl, um Rundungsfehler auszugleichen.

HINWEIS: Alle hier verwendeten Variablen liegen im Bereich [0.0, 1.0]. Sie müssen durch 255 dividieren oder multiplizieren, wenn Sie Werte im Bereich [0, 255] verwenden möchten.

Zum Beispiel 50% Rot über 50% Grün:

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

Die resultierende Farbe ist: (0.67, 0.33, 0.00, 0.75)oder 75% braun (oder dunkelorange).


Sie können diese Formeln auch umkehren:

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

oder

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;

Die Formeln berechnen, dass die Hintergrund- oder Lackfarbe sein muss, um die gegebene resultierende Farbe zu erzeugen.


Wenn Ihr Hintergrund undurchsichtig ist, ist das Ergebnis auch undurchsichtig. Die Vordergrundfarbe könnte dann einen Wertebereich mit unterschiedlichen Alpha-Werten annehmen. Für jeden Kanal (rot, grün und blau) müssen Sie überprüfen, welcher Bereich von Alphas zu gültigen Werten führt (0 - 1).

Markus Jarderot
quelle
Was können Sie gegen das Problem "Division durch Null" tun, wenn fg.A und bg.A beide 0,0 sind? Dieses Ergebnis ist fA = 0. Und dann habe ich ein Problem der Division durch Null, dh hier: rR = fg.R * fg.A / rA + bg.R * bg.A * (1 - fg.A) / rA;
Knotenteich
Wie mussten diese Formeln angepasst werden, um eine fg-Farbe mit Alpha auf ein undurchsichtiges bg zu mischen? Ich habe meine gewünschte Ergebnisfarbe und die BG-Farbe und mit diesen Informationen muss ich bestimmen, welche FG-Farbe sein muss.
Ubiquibacon
57

Unterhaltsame Tatsache: Computer-RGB-Werte werden aus der Quadratwurzel des Photonenflusses abgeleitet. Als allgemeine Funktion sollte Ihre Mathematik dies berücksichtigen. Die allgemeine Funktion hierfür für einen bestimmten Kanal lautet:

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

Wobei a und b die zu mischenden Farben sind und t eine Zahl von 0-1 ist, die den Punkt in der Mischung darstellt, den Sie zwischen a und b wünschen.

Der Alpha-Kanal ist anders; es repräsentiert nicht die Photonenintensität, sondern nur den Prozentsatz des Hintergrunds, der durchscheinen sollte; Wenn Sie also Alpha-Werte mischen, reicht der lineare Durchschnitt aus:

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

Um das Mischen von zwei Farben mit diesen beiden Funktionen zu handhaben, sollte der folgende Pseudocode Ihnen gut tun:

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

Im Übrigen sehne ich mich nach einer Programmiersprache und einer Tastatur, die es ermöglichen, Mathematik (oder mehr) sauber darzustellen (das kombinierte Overline-Unicode-Zeichen funktioniert nicht für hochgestellte Zeichen, Symbole und eine Vielzahl anderer Zeichen) und sie richtig zu interpretieren. sqrt ((1-t) * pow (a, 2) + t * pow (b, 2)) liest sich einfach nicht so sauber.

Fordi
quelle
Vielen Dank, das war es, wonach ich gesucht habe, als ich nach einem Farbmischungsalgorithmus gesucht habe. Das Problem mit den obigen Antworten (unter Verwendung einer linearen Mischung von RGB-Werten) besteht darin, dass sie unnatürlich aussehende Übergänge zwischen Farben mit zu dunklen Flecken ergeben.
James
5
Quadratwurzel ist nicht ganz richtig. Die in unseren Programmen manipulierten Zahlen wurden einer Gammakorrektur unterzogen, da unsere Augen nicht linear auf Licht reagieren, und dies nutzt den begrenzten Bereich besser aus. Die typische Gammakorrektur ist 2,2, was nahe an der in dieser Antwort empfohlenen 2,0 liegt, aber nicht ganz dieser entspricht. In einigen Fällen ist es besser, im gammakorrigierten Raum zu arbeiten, um beispielsweise einen Graustufenverlauf zu erzeugen.
Mark Ransom
Ich habe mit einem Spielzeug gespielt, das zwei Farben schnell hintereinander abwechselt, bis sie zu einer einzigen Farbe zusammenlaufen, und dieser Mischalgorithmus sieht perfekt aus! Dies ist eindeutig die richtige Mathematik, ich habe es nie gewusst! Vielen Dank!!
Luqui
9

Einige Punkte:

  • Ich denke, Sie möchten min anstelle von max verwenden
  • Ich denke, Sie möchten 255 anstelle von 256 verwenden

Dies wird geben:

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

Die "natürliche" Art, Farben zu mischen, besteht darin, den Durchschnitt zu verwenden, und dann brauchen Sie nicht die min:

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

Dani van der Meer
quelle
Es tut uns leid. Ich spreche. min (a, b) ergibt den kleinsten Wert von a und b. min (a, Konstante) beschränkt a unter die Konstante.
Markus Jarderot
@ Markus, beide sind gleich! (gibt den geringsten Wert).
UpTheCreek
6

Javascript-Funktion zum Mischen von RGBA-Farben

c1, c2 und Ergebnis - JSONs wie 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
       }
     } 
Nedudi
quelle
Könnte dies geändert werden, um mehr als zwei Farben zu verarbeiten?
Indiana Kernick
Oder würdest du nur rgbaSum(rgbaSum(c1,c2),rgbaSum(c3,c4)). Wäre das richtig?
Indiana Kernick
5

PYTHON COLOR MIXING DURCH ADDITION IN CMYK SPACE

Eine Möglichkeit, dies zu tun, besteht darin, zuerst die Farben in das CMYK- Format zu konvertieren, sie dort hinzuzufügen und dann wieder in RGB zu konvertieren .

Hier ist ein Beispielcode 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)

Das Ergebnis Ihrer Frage wäre dann (unter der Annahme einer halben Mischung Ihrer beiden Farben:

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

wo die 0,5er sind, um zu sagen, dass wir 50% der ersten Farbe mit 50% der zweiten Farbe mischen.

patapouf_ai
quelle
3

Ja, so einfach ist das. Eine andere Möglichkeit besteht darin, den Durchschnitt zu ermitteln (zum Erstellen von Verläufen).

Es hängt wirklich nur von dem Effekt ab, den Sie erzielen möchten.

Wenn Alpha hinzugefügt wird, wird es jedoch kompliziert. Es gibt verschiedene Methoden zum Mischen mit einem Alpha.

Ein Beispiel für eine einfache Alpha-Mischung: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending

John Gietzen
quelle
3

Hier finden Sie die von Fordi und Markus Jarderot vorgeschlagenen Mischmethoden in einer Python-Funktion, die zwei Farben A und B allmählich mischt oder mischt.

Der "Mix" -Modus ist nützlich, um zwischen zwei Farben zu interpolieren. Der "Misch" -Modus (mit t=0) ist nützlich, um die resultierende Farbe zu berechnen, wenn eine durchscheinende Farbe auf eine andere (möglicherweise durchscheinende) Farbe gemalt wird. gammaKorrektur führt zu schöneren Ergebnissen, da berücksichtigt wird, dass die physikalische Lichtintensität und die wahrgenommene Helligkeit (vom Menschen) nicht linear zusammenhängen.


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

Sehen Sie unten, wie dies verwendet werden kann. Im "Mix" -Modus stimmen die linken und rechten Farben genau color_aund überein color_b. Im "Mischmodus" ist die linke Farbe bei t=0die Farbe, die sich ergibt, wenn sie color_aüberblendet wird color_b(und ein weißer Hintergrund). Im Beispiel wird color_adann zunehmend durchscheinend gemacht, bis man ankommt color_b.

Beachten Sie, dass Mischen und Mischen gleichwertig sind, wenn die Alpha-Werte 1,0 betragen.

Ergebnisse


Der Vollständigkeit halber hier der Code zur Reproduktion des obigen Diagramms.

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)

Und zum Schluss hier eine nützliche Lektüre über die Gammakorrektur.

normanius
quelle
3

Als ich hierher kam, fand ich nicht den Algorithmus "Additive Color Mixing", den ich tatsächlich suchte, der auch in Photoshop verfügbar ist und auf Wikipedia als "Bildschirm" beschrieben wird . (Aka "aufhellen" oder "invertieren multiplizieren" .) Es wird ein Ergebnis erzeugt, das zwei kombinierten Lichtquellen ähnelt.

Im Bildschirmüberblendungsmodus werden die Werte der Pixel in den beiden Ebenen invertiert, multipliziert und dann erneut invertiert. Dies ergibt den gegenteiligen Effekt der Multiplikation. Das Ergebnis ist ein helleres Bild.

Hier ist es:

// (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
quelle
Ich hoffe, das ist es, wonach ich suche. Würde dies funktionieren, um zwei verschiedene Farbtöne zu mischen? Zum Beispiel zwei blaue Werte, definiert als: blue1 = (17, 43, 154) und blue2 = (22, 56, 186)
Mohd
1
@Mohd Hängt davon ab, welches Ergebnis Sie erwarten. Da es sich um eine additive Mischung handelt, ist die Ergebnisfarbe immer heller, da beide Farben hinzugefügt werden. Wenn Sie die Farben "mischen" möchten, was zu einem Ton führt, der irgendwo dazwischen liegt, dann nein. Verwenden b3 = {r: (b1.r + b2.r) / 2, g: (b1.g + b2.g) /2, ...
Sie dazu
Du hast Recht; in der Tat hat der Durchschnitt über jeden Kanal den Job gemacht.
Mohd
1

Geschrieben / gebrauchte etwas wie @Markus Jarderot ‚s sRGBMischungs Antwort (die nicht Gamma da die behoben wird , ist die Standard - legacy) mit 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;

Weitere Informationen: Was jeder Codierer über Gamma wissen sollte

Top-Master
quelle
1

Ich habe an einem ähnlichen Problem gearbeitet und bin hier gelandet, musste aber am Ende meine eigene Implementierung schreiben. Ich wollte im Grunde die neue Vordergrundfarbe über die vorhandene Hintergrundfarbe "überlagern". (Und ohne einen beliebigen Mittelpunkt wie zu verwenden t. Ich glaube, meine Implementierung ist immer noch "additiv".) Dies scheint auch in allen meinen Testfällen sehr sauber zu passen.

Hier new_argbkonvertiert man einfach das intin eine Struktur mit 4, unsigned chardamit ich die Anzahl der Bitverschiebungen reduzieren kann.

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

In meiner Umgebung schreibe ich Farben intin ein 1D-Pixel-Array, das mit 0 Bytes initialisiert wird. Durch Erhöhen des Alphas tendiert das Pixel zu Schwarz. ( 0 0 0 0wäre undurchsichtiges Schwarz und 255 255 255 255wäre transparentes Weiß ... auch bekannt als Schwarz.)

ngontjar
quelle
0

Hier ist eine hochoptimierte, eigenständige C ++ - Klasse, gemeinfrei, mit Gleitkomma und zwei unterschiedlich optimierten 8-Bit-Mischmechanismen in Funktions- und Makroformaten sowie einer technischen Diskussion sowohl des vorliegenden Problems als auch der Vorgehensweise und der Bedeutung von, Optimierung dieses Problems:

https://github.com/fyngyrz/colorblending

Fyngyrz
quelle
Nur-Link-Antworten sind keine gute Idee, Links werden schlecht und Sie haben etwas Wertloses übrig. Wenn Sie den Code hier nicht veröffentlichen können, beschreiben und fassen Sie ihn zumindest zusammen.
Mark Ransom
Ich würde gerne den Code hier posten, wenn SO sogar einen etwas so guten Mechanismus hätte wie Github. Aber das tut es nicht. Ganz zu schweigen von den widerwärtigen Lizenzrichtlinien von SO. Ein Link zu Github, der schlecht wird, ist ungefähr so ​​wahrscheinlich wie ein Link zu SO, der schlecht wird. Links sind das, worum es im Web geht. Was ich gepostet habe, ist zu 100% relevant für diese Frage und eine hervorragende Reihe von Lösungen für dieses spezielle Problem, die ich öffentlich zugänglich gemacht habe. Sie sind in keiner Weise hilfreich oder nützlich für Ihre Bemerkungen, Sie versuchen nur, Ärger zu machen.
Fyngyrz
1
Nein, ich versuche festzustellen, dass StackOverflow Antworten enthält , keine Links zu den Antworten. Google hat bereits viele davon.
Mark Ransom
3
Ich gab eine relevante Antwort auf die Frage. Die Antwort enthält einen Link zum Code. SO verfügt weder über einen Mechanismus zum Einschließen einer signifikanten c-Klasse noch über eine akzeptable Lizenzierung für Code, der auf der Site angezeigt wird. Daher ist das, was Sie möchten, einfach nicht möglich. Sie haben die Wahl zwischen einer Antwort mit einem Link oder einer Nichtantwort. Letzteres nützt niemandem etwas. Ersteres ist relevant, informativ und sehr nützlich. Bei Google gibt es eine Senkgrube an Irrelevanz und Anzeigen. Vielleicht sollten Sie überlegen, Ihre Position zu überdenken. Das letzte Wort gehört dir. Ich bin zufrieden mit meiner Antwort.
Fyngyrz
1
Es scheint ein bisschen oberflächlich zu sein, einen Mann für die Veröffentlichung eines Links zu einer Lösung, die sich in seinem eigenen Github-Repository befindet, zu bewerten.
BobRodes
0

Vielen Dank an Markus Jarderot, Andras Zoltan und hkurabko; Hier ist der Python-Code zum Mischen einer Liste von RGB-Bildern.

Mit Markus Jarderots Code können wir RGBA-Farben erzeugen, dann verwende ich die Methode von Andras Zoltan und hkurabko, um RGBA in RGB zu übertragen.

Vielen Dank!

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

Prüfung

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
quelle