Programmatisch eine Farbe aufhellen

Motivation

Ich möchte einen Weg finden, eine beliebige Farbe zu nehmen und sie ein paar Schattierungen heller zu machen, so dass ich programmatisch einen schönen Farbverlauf von der einen Farbe zu einer leichteren Version erzeugen kann. Der Farbverlauf wird als Hintergrund in einer Benutzeroberfläche verwendet.

Möglichkeit 1

Natürlich kann ich die RGB-Werte einfach aufteilen und sie einzeln um einen bestimmten Betrag erhöhen. Ist das wirklich was ich will?

Möglichkeit 2

Mein zweiter Gedanke war, das RGB in HSV / HSB / HSL (Farbton, Sättigung, Wert / Helligkeit / Helligkeit) zu konvertieren, die Helligkeit ein wenig zu erhöhen, die Sättigung etwas zu verringern und sie dann wieder in RGB umzuwandeln. Wird dies generell den gewünschten Effekt haben?

Ich würde für die zweite Option gehen. Im Allgemeinen ist der RGB-Raum nicht wirklich gut für Farbmanipulationen (Übergang von einer Farbe zu einer anderen, Aufhellen / Verdunkeln einer Farbe, etc.). Unten sind zwei Seiten, die ich mit einer schnellen Suche gefunden habe, um von / nach RGB zu / von HSL zu konvertieren:

  • aus den “Grundlagen der Computergrafik”
  • einige Quellcodes in C # – sollten sich leicht an andere Programmiersprachen anpassen lassen.

Wie Wedge sagte , möchtest du multiplizieren, um die Dinge heller zu machen, aber das funktioniert nur, bis eine der colors gesättigt ist (dh auf 255 oder mehr trifft). An diesem Punkt können Sie die Werte auf 255 beschränken, aber Sie ändern den Farbton auf subtile Weise, wenn Sie heller werden. Um den Farbton beizubehalten, möchten Sie das Verhältnis von (Mitte-niedrigste) / (höchste-niedrigste) beibehalten.

Hier sind zwei functionen in Python. Der erste implementiert den naiven Ansatz, der die RGB-Werte bei Überschreiten auf 255 begrenzt. Der zweite umverteilt die überschüssigen Werte, um den Farbton intakt zu halten.

def clamp_rgb(r, g, b): return min(255, int(r)), min(255, int(g)), min(255, int(b)) def redistribute_rgb(r, g, b): threshold = 255.999 m = max(r, g, b) if m < = threshold: return int(r), int(g), int(b) total = r + g + b if total >= 3 * threshold: return int(threshold), int(threshold), int(threshold) x = (3 * threshold - total) / (3 * m - total) gray = threshold - x * m return int(gray + x * r), int(gray + x * g), int(gray + x * b) 

Ich habe einen Farbverlauf erstellt, der mit dem RGB-Wert (224,128,0) beginnt und ihn mit 1,0, 1,1, 1,2 usw. bis 2,0 multipliziert. Die obere Hälfte ist das Ergebnis mit clamp_rgb und die untere Hälfte ist das Ergebnis mit redistribute_rgb . Ich denke, es ist leicht zu sehen, dass das Umverteilen der Überläufe ein viel besseres Ergebnis liefert, ohne den RGB-Farbraum verlassen zu müssen.

Helligkeitsverlauf mit Einspannung (oben) und Umverteilung (unten)

Zum Vergleich, hier ist der gleiche Farbverlauf in den HLS- und HSV-Farbräumen, wie er von Pythons Modul colorsys implementiert wurde. Nur die L Komponente wurde modifiziert und die resultierenden RGB-Werte wurden geklammert. Die Ergebnisse sind ähnlich, erfordern jedoch Farbraumkonvertierungen für jedes Pixel.

Helligkeitsgradient mit HLS (oben) und HSV (unten)

In C #:

 public static Color Lighten(Color inColor, double inAmount) { return Color.FromArgb( inColor.A, (int) Math.Min(255, inColor.R + 255 * inAmount), (int) Math.Min(255, inColor.G + 255 * inAmount), (int) Math.Min(255, inColor.B + 255 * inAmount) ); } 

Ich habe das überall benutzt.

Die ControlPaint-class im System.Windows.Forms-Namespace hat die statischen Methoden Light und Dark:

 public static Color Dark(Color baseColor, float percOfDarkDark); 

Diese Methoden verwenden private Implementierung von HLSColor. Ich wünschte, diese Struktur wäre öffentlich und in System.Drawing.

Alternativ können Sie GetHue, GetSaturation, GetBrightness für Color struct verwenden, um HSB-Komponenten zu erhalten. Leider habe ich die umgekehrte Konvertierung nicht gefunden.

Konvertieren Sie es in RGB und interpolieren Sie linear zwischen der Originalfarbe und der Zielfarbe (oft weiß). Wenn Sie also 16 Schattierungen zwischen zwei colors wünschen, tun Sie Folgendes:

 for(i = 0; i < 16; i++) { colors[i].R = start.R + (i * (end.R - start.R)) / 15; colors[i].G = start.G + (i * (end.G - start.G)) / 15; colors[i].B = start.B + (i * (end.B - start.B)) / 15; } 

Um eine hellere oder dunklere Version einer bestimmten Farbe zu erhalten, sollten Sie ihre Helligkeit ändern. Sie können dies leicht tun, auch ohne Ihre Farbe in HSL- oder HSB-Farbe zu konvertieren. Um beispielsweise eine Farbe heller zu machen, können Sie den folgenden Code verwenden:

 float correctionFactor = 0.5f; float red = (255 - color.R) * correctionFactor + color.R; float green = (255 - color.G) * correctionFactor + color.G; float blue = (255 - color.B) * correctionFactor + color.B; Color lighterColor = Color.FromArgb(color.A, (int)red, (int)green, (int)blue); 

Wenn Sie weitere Informationen benötigen, lesen Sie die vollständige Geschichte in meinem Blog .

Eine sehr ähnliche Frage mit nützlichen Antworten wurde bereits früher gestellt: Wie ermittle ich eine dunklere oder hellere Farbvariante einer bestimmten Farbe?

Kurze Antwort: Multiplizieren Sie die RGB-Werte mit einer Konstante, wenn Sie nur “gut genug” benötigen, und übersetzen Sie sie in HSV, wenn Sie Genauigkeit benötigen.

Ich benutzte Andrews Antwort und Marks Antwort, um dies zu machen (ab 1/2013 keine Bereichseingabe für ff).

 function calcLightness(l, r, g, b) { var tmp_r = r; var tmp_g = g; var tmp_b = b; tmp_r = (255 - r) * l + r; tmp_g = (255 - g) * l + g; tmp_b = (255 - b) * l + b; if (tmp_r > 255 || tmp_g > 255 || tmp_b > 255) return { r: r, g: g, b: b }; else return { r:parseInt(tmp_r), g:parseInt(tmp_g), b:parseInt(tmp_b) } } 

Bildbeschreibung hier eingeben

Die Konvertierung in HS (LVB), die Erhöhung der Helligkeit und die anschließende Konvertierung in RGB sind die einzige Möglichkeit, die Farbe zuverlässig zu reduzieren, ohne die Farbton- und Sättigungswerte zu beeinflussen (dh die Farbe nur aufzuhellen, ohne sie auf andere Weise zu verändern).

Ich habe dies in beide Richtungen gemacht – mit Möglichkeit 2 erhalten Sie viel bessere Ergebnisse.

Jeder einfache Algorithmus, den Sie für Möglichkeit 1 konstruieren, wird wahrscheinlich nur für einen begrenzten Bereich von Anfangssättigungen funktionieren.

Sie würden gerne in Poss 1 schauen, wenn (1) Sie die verwendeten colors und Helligkeiten einschränken können und (2) Sie die Berechnung in einem Rendering durchführen.

Das Generieren des Hintergrunds für eine Benutzeroberfläche wird nicht sehr viele Schattierungsberechnungen benötigen, daher schlage ich Poss 2 vor.

-Al.

Wenn Sie eine Farbverlaufsausblendung erzeugen möchten, würde ich folgende Optimierung vorschlagen: Statt RGB-> HSB-> RGB für jede einzelne Farbe zu verwenden, sollten Sie nur die Zielfarbe berechnen. Sobald Sie das Ziel-RGB kennen, können Sie einfach die Zwischenwerte im RGB-Raum berechnen, ohne dass Sie vor und zurück konvertieren müssen. Ob Sie einen linearen Übergang der Verwendung einer bestimmten Kurve berechnen, liegt an Ihnen.

Methode 1: RGB in HSL konvertieren, HSL anpassen, zurück in RGB konvertieren.

Methode 2: Lerp die RGB-Farbwerte – http://en.wikipedia.org/wiki/Lerp_(computing)

Siehe meine Antwort auf diese ähnliche Frage für eine C # -Implementierung von Methode 2.

Vorgeben, dass Sie Alpha zu Weiß gemischt haben:

 oneMinus = 1.0 - amount r = amount + oneMinus * r g = amount + oneMinus * g b = amount + oneMinus * b 

wobei der amount von 0 bis 1 ist, wobei 0 die ursprüngliche Farbe und 1 Weiß zurückgibt.

Sie möchten vielleicht mit der Hintergrundfarbe mischen, wenn Sie aufhellen, um etwas deaktiviert anzuzeigen:

 oneMinus = 1.0 - amount r = amount * dest_r + oneMinus * r g = amount * dest_g + oneMinus * g b = amount * dest_b + oneMinus * b 

wo (dest_r, dest_g, dest_b) die Farbe ist, zu der gemischt wird und die amount von 0 bis 1 ist, wobei 0 zurückkehrt (r, g, b) und 1 zurückkehrt (dest.r, dest.g, dest.b)

Ich habe diese Frage erst gefunden, nachdem sie zu meiner ursprünglichen Frage verwandt wurde.

Allerdings mit Hilfe dieser großartigen Antworten. Ich habe dafür eine nette Zweilinerfunktion zusammengestellt:

Programmatisch Aufhellen oder Abdunkeln einer Hex-Farbe (oder rgb und Mischen von colors)

Es ist eine Version von Methode 1. Aber mit Übersättigung berücksichtigt. Wie Keith in seiner Antwort oben sagte; benutze Lerp, um das gleiche Problem zu lösen, das Mark erwähnt hat, aber ohne Umverteilung. Die Ergebnisse von shadeColor2 sollten dem HSL- shadeColor2 sehr viel näher kommen, jedoch ohne Overhead.

Ich hätte zuerst Nummer # 1 versucht, aber # 2 klingt ziemlich gut. Versuchen Sie es selbst und sehen Sie, ob Sie mit den Ergebnissen zufrieden sind, es klingt so, als würden Sie vielleicht 10 Minuten brauchen, um einen Test zu machen.

Technisch gesehen glaube ich nicht, dass beides korrekt ist, aber ich glaube, dass Sie eine Variante von Option 2 wollen. Das Problem ist, dass RGB 990000 genommen und “aufhellt” wurde wirklich nur auf den roten Kanal hinzufügen (Wert, Helligkeit, Helligkeit), bis Sie zu FF gekommen sind. Danach (festes Rot) würde es die Sättigung verringern , um den ganzen Weg zu solidem Weiß zu gehen.

Die Konvertierungen werden ärgerlich, vor allem weil man nicht direkt von und zu RGB und Lab gehen kann, aber ich denke, dass man die Chrominanz- und Lumenance-Werte wirklich trennen will, und nur die Helligkeit ändern, um wirklich das zu erreichen, was man will.

Sie finden Code zum Konvertieren zwischen Farbräumen in der Ruby-Bibliothek für Farbwerkzeuge

Ich habe einen Blogbeitrag , der zeigt, wie man das in Delphi macht. Es ist ziemlich einfach, weil die functionen ColorRGBToHSL und ColorHLSToRGB Teil der Standardbibliothek sind.

Hier ist ein Beispiel für die Aufhellung einer RGB-Farbe in Python:

 def lighten(hex, amount): """ Lighten an RGB color by an amount (between 0 and 1), eg lighten('#4290e5', .5) = #C1FFFF """ hex = hex.replace('#','') red = min(255, int(hex[0:2], 16) + 255 * amount) green = min(255, int(hex[2:4], 16) + 255 * amount) blue = min(255, int(hex[4:6], 16) + 255 * amount) return "#%X%X%X" % (int(red), int(green), int(blue)) 

Ein bisschen spät auf die Party, aber wenn Sie javascript oder nodejs , können Sie tinycolor Bibliothek verwenden , und manipulieren Sie die Farbe, wie Sie wollen:

 tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d"