Programmatisch eine Farbe aufhellen

72

Motivation

Ich möchte einen Weg finden, eine beliebige Farbe zu nehmen und sie um einige Schattierungen aufzuhellen, damit ich programmgesteuert einen schönen Farbverlauf von einer Farbe zu einer helleren Version erstellen kann. Der Verlauf wird als Hintergrund in einer Benutzeroberfläche verwendet.

Möglichkeit 1

Natürlich kann ich die RGB-Werte einfach aufteilen und einzeln um einen bestimmten Betrag erhöhen. Will ich das eigentlich?

Möglichkeit 2

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

Dave Lockhart
quelle
40
Die Programmiersprache spielt keine Rolle.
David Arno
Wenn der Hintergrund weiß ist, kann das Ändern von Alpha / Transparenz oft als Hack zum "Aufhellen" der Farbe dienen.
Astreltsov

Antworten:

38

Ich würde mich für die zweite Option entscheiden. Im Allgemeinen eignet sich der RGB-Bereich nicht wirklich für Farbmanipulationen (Übergang von einer Farbe zu einer anderen, Aufhellen / Abdunkeln einer Farbe usw.). Im Folgenden sind zwei Websites aufgeführt, die ich mit einer Schnellsuche gefunden habe, um von / zu RGB zu / von HSL zu konvertieren:

Grauer Panther
quelle
9
Der zweite Link ist unterbrochen.
RenniePet
Guter Ersatzlink für den Konvertierungsquellcode: bobpowell.net/RGBHSB.aspx
Curtis Yallop
Ein weiterer Referenzlink: social.msdn.microsoft.com/Forums/vstudio/en-US/…
Curtis Yallop
58

Wie Wedge sagte , möchten Sie multiplizieren, um die Dinge heller zu machen, aber das funktioniert nur, bis eine der Farben gesättigt ist (dh Treffer 255 oder höher). An diesem Punkt können Sie die Werte einfach auf 255 klemmen, aber Sie werden den Farbton subtil ändern, wenn Sie heller werden. Um den Farbton beizubehalten, möchten Sie das Verhältnis (Mitte-Niedrigster) / (Höchste-Niedrigste) beibehalten.

Hier sind zwei Funktionen in Python. Der erste implementiert den naiven Ansatz, bei dem die RGB-Werte nur auf 255 begrenzt werden, wenn sie überschritten werden. Der zweite verteilt die überschüssigen Werte neu, 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 Verlauf 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_rgbund die untere Hälfte ist das Ergebnis mit redistribute_rgb. Ich denke, es ist leicht zu erkennen, dass die Umverteilung der Überläufe zu einem viel besseren Ergebnis führt, ohne den RGB-Farbraum verlassen zu müssen.

Helligkeitsgradient mit Klemmung (oben) und Umverteilung (unten)

Zum Vergleich ist hier derselbe Farbverlauf in den HLS- und HSV-Farbräumen, der vom Python- colorsysModul implementiert wurde . Nur die LKomponente wurde modifiziert und die resultierenden RGB-Werte wurden geklemmt. Die Ergebnisse sind ähnlich, erfordern jedoch Farbraumkonvertierungen für jedes Pixel.

Helligkeitsgradient mit HLS (oben) und HSV (unten)

Mark Ransom
quelle
Nachdem ich dies positiv bewertet hatte, wurde mir klar, dass dies viel zu viel des Guten ist. Alles, was Sie tun müssen, ist eine Alpha-Mischung mit Weiß bei einer bestimmten Deckkraft (dh interpolieren Sie die Farbkomponenten um den gleichen Bruchteil in Richtung 255).
Andy
@ Andy schau dir das Beispiel an. Die ersten beiden Kästchen links enthalten kein Weiß, sie sind vollständig gesättigt. Es wäre mehr gewesen, wenn ich mit einer dunkleren Farbe angefangen hätte.
Mark Ransom
Ah, ich verstehe, also hat Ihr Code die gleiche lineare Diskontinuität wie der HLS-Farbraum. Ich kann sehen, wie das zu einem reicheren Gefälle führen würde. Da ich nur eine Farbe für ein Hover-Highlight aufhellen wollte, anstatt einen Farbverlauf zu erstellen, erwartete ich eine einfachere Methode
Andy
1
@Andy gibt es eine andere Antwort, die eine lineare Interpolation mit Weiß vorschlägt. Ich glaube, genau das ist es, wonach Sie suchen.
Mark Ransom
Ja, ich wollte diese Antwort selbst hinzufügen, bis ich sah, dass jemand anderes es getan hatte. Prost!
Andy
25

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.

Nick
quelle
Sehr praktisch und einfach. Verwenden Sie es jetzt in einer VB.NET-App.
Kezzer
Siehe stackoverflow.com/questions/801406/…
Martin Marconcini
Wenn Sie verwenden, using System.Windows.Media.Color;sollten Sie nicht in Byte umwandeln?
Devid
11

Die ControlPaint-Klasse im System.Windows.Forms-Namespace verfügt über statische Methoden: Hell und Dunkel:

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

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

Alternativ können Sie GetHue, GetSaturation, GetBrightness on Color struct verwenden, um HSB-Komponenten abzurufen. Leider habe ich die umgekehrte Konvertierung nicht gefunden.

Ilya Ryzhenkov
quelle
8

Konvertieren Sie es in RGB und interpolieren Sie linear zwischen der Originalfarbe und der Zielfarbe (häufig Weiß). Wenn Sie also 16 Farbtöne zwischen zwei Farben 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;
}
Adam Rosenfield
quelle
In den meisten Fällen werden nur die Start- und Endfarbe benötigt, da die Grafikbibliothek Ihrer Wahl wahrscheinlich über Verlaufsfunktionen verfügt.
Max Schmeling
Durch die Verwendung der Ganzzahldivision entfällt die Notwendigkeit einer Rundung (Etage). Klug.
Stefan Steiger
6

Um eine hellere oder dunklere Version einer bestimmten Farbe zu erhalten, sollten Sie deren Helligkeit ändern. Sie können dies problemlos tun, auch ohne Ihre Farbe in HSL- oder HSB-Farbe umzuwandeln. 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 Details benötigen, lesen Sie die ganze Geschichte in meinem Blog .

Pavel Vladov
quelle
+1, Nicks-Methode, der richtige Weg. Sie können die Umwandlung jedoch immer noch von und nach float überspringen, indem Sie dies wie Adam Rosenfield tun, indem Sie den Korrekturfaktor in Schritte und Index aufteilen, wodurch auch zwei verständliche Werte anstelle einer abstrakten Zahl zwischen 0,0 und 1,0 erhalten werden. Beispiel: Ihr Korrekturfaktor ist Rosenfields i / 15, während Sie Weiß als Zielfarbe annehmen.
Stefan Steiger
3

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

David Arno
quelle
3

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

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

Keil
quelle
Für den Verweis auf die ähnliche Frage positiv bewertet, aber ich bin mit dem RGB-Rat nicht einverstanden - gehen Sie zum HSV.
Blair Conrad
3

Ich habe Andrews Antwort und Marks Antwort verwendet, 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) }
}

Geben Sie hier die Bildbeschreibung ein

user1873073
quelle
2

Ich habe dies in beide Richtungen getan - mit Möglichkeit 2 erzielen Sie viel bessere Ergebnisse.

Jeder einfache Algorithmus, den Sie für Möglichkeit 1 erstellen, funktioniert wahrscheinlich nur für einen begrenzten Bereich von Startsättigungen.

Sie sollten sich Poss 1 ansehen, wenn (1) Sie die verwendeten Farben und Helligkeiten einschränken können und (2) Sie die Berechnung häufig in einem Rendering durchführen.

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

-Al.


quelle
1

Wenn Sie ein Ausblenden des Verlaufs erzeugen möchten, würde ich die folgende Optimierung vorschlagen: Anstatt RGB-> HSB-> RGB für jede einzelne Farbe auszuführen, sollten Sie nur die Zielfarbe berechnen. Sobald Sie das Ziel-RGB kennen, können Sie einfach die Zwischenwerte im RGB-Raum berechnen, ohne hin und her konvertieren zu müssen. Ob Sie einen linearen Nutzungsübergang berechnen, liegt bei Ihnen.

VoidPointer
quelle
1

Stellen Sie sich vor, Sie hätten Alpha zu Weiß gemischt:

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

Dabei amountliegt der Wert zwischen 0 und 1, wobei 0 die ursprüngliche Farbe und 1 Weiß zurückgibt.

Möglicherweise möchten Sie mit der Hintergrundfarbe mischen, wenn Sie aufhellen, um etwas Deaktiviertes 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)wird die Farbe gemischt und amountist von 0 bis 1, wobei Null zurückkehrt (r, g, b)und 1 zurückkehrt(dest.r, dest.g, dest.b)

vorbenetzen
quelle
Ich denke, das sollte die beste Antwort sein. Ebenso verdunkeln Sie zum Abdunkeln nur Alpha mit Schwarz (dh multiplizieren Sie die Komponenten mit einigen amount < 1).
Andy
1

Ich habe diese Frage erst gefunden, nachdem sie mit meiner ursprünglichen Frage verwandt war.

Verwenden Sie jedoch die Erkenntnisse aus diesen großartigen Antworten. Ich habe dafür eine schöne Zwei-Liner-Funktion zusammengestellt:

Programmgesteuert eine Hex-Farbe aufhellen oder abdunkeln (oder RGB und Farben mischen)

Es ist eine Version von Methode 1. Aber unter Berücksichtigung der Übersättigung. Wie Keith in seiner Antwort oben sagte; Verwenden Sie Lerp, um das gleiche Problem zu lösen, das Mark erwähnt hat, jedoch ohne Umverteilung. Die Ergebnisse von shadeColor2sollten viel näher daran liegen, es mit HSL richtig zu machen, aber ohne Overhead.

Zuhälter Trizkit
quelle
0

Ich hätte zuerst Nummer 1 ausprobiert, aber Nummer 2 klingt ziemlich gut. Versuchen Sie es selbst und sehen Sie, ob Sie mit den Ergebnissen zufrieden sind. Es hört sich so an, als würden Sie vielleicht 10 Minuten brauchen, um einen Test zu erstellen.

davr
quelle
0

Technisch gesehen halte ich beides auch nicht für richtig, aber ich glaube, Sie möchten eine Variante von Option 2. Das Problem ist, dass RGB 990000 benötigt und "aufgehellt" wird, um den roten Kanal (Wert, Helligkeit, Helligkeit) zu erweitern, bis Sie zu FF gelangen. Danach (durchgehend rot) würde die Sättigung verringert , um bis zu festem Weiß zu gelangen.

Die Konvertierungen werden ärgerlich, zumal Sie nicht direkt zu und von RGB und Lab wechseln können, aber ich denke, Sie möchten die Chrominanz- und Luminanzwerte wirklich trennen und einfach die Luminanz ändern, um wirklich das zu erreichen, was Sie wollen.

Pseudo-Masochist
quelle
0

In der Ruby-Bibliothek der Farbwerkzeuge finden Sie Code zum Konvertieren zwischen Farbräumen

Thibaut Barrère
quelle
0

Ich habe einen Blog-Beitrag , der zeigt, wie das in Delphi geht. Es ist ziemlich einfach, da die Funktionen ColorRGBToHSL und ColorHLSToRGB Teil der Standardbibliothek sind.

Lawrence Barsanti
quelle
0

Hier ist ein Beispiel für das Aufhellen einer RGB-Farbe in Python:

def lighten(hex, amount):
    """ Lighten an RGB color by an amount (between 0 and 1),

    e.g. 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))
Aidan
quelle