565 Stimmen

Formel zur Bestimmung der wahrgenommenen Helligkeit der RGB-Farbe

Ich suche nach einer Art Formel oder Algorithmus, um die Helligkeit einer Farbe anhand der RGB-Werte zu bestimmen. Ich weiß, dass es nicht so einfach ist, die RGB-Werte zusammenzuzählen und höhere Summen heller zu machen, aber ich bin irgendwie ratlos, wo ich anfangen soll.

10 Stimmen

Die wahrgenommene Helligkeit ist das, wonach ich suche, danke.

0 Stimmen

Ich habe [diesen Code][1] (geschrieben in C#) gefunden, der hervorragende Arbeit bei der Berechnung der "Helligkeit" einer Farbe leistet. In diesem Szenario versucht der Code festzustellen, ob weißer oder schwarzer Text über der Farbe platziert werden soll. [1]:nbdtech.com/Blog/archive/2008/04/27/…

2 Stimmen

Es gibt einen guten Artikel (Farbmanipulation in .NET - Teil 1) über Farbräume und deren Konvertierungen, einschließlich sowohl Theorie als auch Code (C#). Für die Antwort schauen Sie sich das Thema Konvertierung zwischen Modellen im Artikel an.

610voto

Anonymous Punkte 17529

Die Methode könnte je nach Ihren Bedürfnissen variieren. Hier sind 3 Möglichkeiten, die Luminanz zu berechnen:

  • Luminanz (Standard für bestimmte Farbräume): (0.2126*R + 0.7152*G + 0.0722*B) Quelle img

  • Luminanz (wahrgenommene Option 1): (0.299*R + 0.587*G + 0.114*B) Quelle img

  • Luminanz (wahrgenommene Option 2, langsamer zu berechnen): sqrt( 0.241*R^2 + 0.691*G^2 + 0.068*B^2 ) sqrt( 0.299*R^2 + 0.587*G^2 + 0.114*B^2 ) (danke an @MatthewHerbst) Quelle img

[Edit: Beispiele hinzugefügt, die benannte CSS-Farben mit jeder Methode sortiert verwendet.]

38 Stimmen

Beachte, dass beide Aspekte die physiologischen Aspekte betonen: Das menschliche Auge ist am empfindlichsten für grünes Licht, weniger für rot und am wenigsten für blau.

28 Stimmen

Beachten Sie auch, dass all dies wahrscheinlich für lineares 0-1 RGB ist und Sie wahrscheinlich gamma-korrigiertes 0-255 RGB haben. Sie werden nicht so konvertiert, wie Sie denken.

3 Stimmen

Für die ersten beiden ist die Quelle in den anderen Antworten. Was die letzte betrifft - Ich glaube, sie stammt aus den Vorlesungen im Fernsehen oder Grafiken...

359voto

Franci Penov Punkte 73239

Ich denke, was du suchst, ist die RGB -> Luma Konversionsformel.

Fotometrisch/digital ITU BT.709:

Y = 0.2126 R + 0.7152 G + 0.0722 B

Digital ITU BT.601 (gibt mehr Gewicht auf die R und B Komponenten):

Y = 0.299 R + 0.587 G + 0.114 B

Wenn du Genauigkeit gegen Leistung eintauschen möchtest, gibt es zwei Näherungsformeln dafür:

Y = 0.33 R + 0.5 G + 0.16 B

Y = 0.375 R + 0.5 G + 0.125 B

Diese können schnell berechnet werden als

Y = (R+R+B+G+G+G)/6

Y = (R+R+R+B+G+G+G+G)>>3

1 Stimmen

Wie kommt es, dass Ihre "schnell berechneten" Werte die Farbe Blau bei der Näherung überhaupt nicht berücksichtigen?

3 Stimmen

@Jonathan Dumaine - Die beiden schnellen Berechnungsformeln enthalten beide Blau - die erste ist (2*Rot + Blue + 3*Grün)/6, die zweite ist (3*Rot + Blue + 4*Grün)>>3. Zugegeben, in beiden schnellen Näherungen hat Blau das geringste Gewicht, aber es ist immer noch da.

11 Stimmen

Die schnelle Version ist noch schneller, wenn Sie es so machen: Y = (R<<1+R+G<<2+B)>>3 (das sind nur 3-4 CPU-Zyklen auf ARM), aber ich denke, ein guter Compiler wird diese Optimierung für Sie durchführen.

318voto

Myndex Punkte 2495

Die "Akzeptierte" Antwort ist falsch und unvollständig

Die einzigen Antworten, die korrekt sind, sind die von @jive-dadson und @EddingtonsMonkey, und unterstützend @nils-pipenbrinck. Die anderen Antworten (einschließlich der akzeptierten) verlinken oder zitieren Quellen, die entweder falsch, irrelevant, veraltet oder defekt sind.

Kurz gesagt:

  • sRGB muss linearisiert werden, bevor die Koeffizienten angewendet werden.
  • Die Helligkeit (L oder Y) ist linear wie auch das Licht.
  • Die wahrgenommene Helligkeit (L*) ist nichtlinear wie auch die menschliche Wahrnehmung.
  • HSV und HSL sind in Bezug auf die Wahrnehmung nicht annähernd genau.
  • Der IEC-Standard für sRGB legt einen Schwellenwert von 0,04045 fest, es ist nicht 0,03928 (das stammt aus einem obsoleten frühen Entwurf).
  • Um nützlich zu sein (d. h. im Verhältnis zur Wahrnehmung) benötigen euklidische Abstände einen wahrnehmungsgleichmäßigen kartesischen Vektorraum wie CIELAB. sRGB ist keiner.

Was folgt, ist eine korrekte und vollständige Antwort:

Weil dieser Thread in Suchmaschinen stark präsent ist, füge ich diese Antwort hinzu, um die verschiedenen Missverständnisse zum Thema zu klären.

Helligkeit ist ein linearer Maßstab für Licht, spektral gewichtet für normales Sehen, aber nicht an die nichtlineare Wahrnehmung von Helligkeit angepasst. Es kann ein relativer Maßstab sein, Y wie in CIEXYZ, oder als L, ein absoluter Maßstab in cd/m2 (nicht zu verwechseln mit L*).

Wahrgenommene Helligkeit wird von einigen Sehmodellen wie CIELAB verwendet, hier ist L* (Lstern) ein Wert von wahrnehmbarer Helligkeit und ist nichtlinear, um der nichtlinearen Reaktion der menschlichen Vision anzunähern. (Das heißt, linear zur Wahrnehmung, aber daher nichtlinear zum Licht).

Helligkeit ist ein Wahrnehmungsattribut, es hat keine "physische" Maßeinheit. Einige Farberscheinungsmodelle haben jedoch einen Wert, üblicherweise bezeichnet als "Q" für wahrgenommene Helligkeit, der sich von wahrgenommener Helligkeit unterscheidet.

Luma ( prime) ist ein gammakodiertes, gewichtetes Signal, das bei einigen Videoencodings verwendet wird (Y´I´Q´). Es darf nicht mit linearer Helligkeit verwechselt werden.

Gamma oder Übertragungskurve (TRC) ist eine Kurve, die häufig der Wahrnehmungskurve ähnelt und die häufig auf Bilddaten angewendet wird, um Rauschen zu reduzieren und/oder die Datenverwendung zu verbessern (und andere Gründe).

Um die wahrgenommene Helligkeit zu bestimmen, konvertieren Sie zunächst gamma-kodierte R´G´B´-Bildwerte in lineare Helligkeit (L oder Y ) und dann in nichtlineare wahrgenommene Helligkeit (*`L`** )


UM DIE HELLIGKEIT ZU FINDEN:

...Weil sie anscheinend irgendwo verloren gegangen ist...

Schritt eins:

Konvertieren Sie alle sRGB 8-Bit-Integerwerte in Dezimalzahlen von 0,0 bis 1,0

  vR = sR / 255;
  vG = sG / 255;
  vB = sB / 255;

Schritt zwei:

Konvertieren Sie einen gammakodierten RGB in einen linearen Wert. sRGB (Computernorm) erfordert beispielsweise eine Potenzkurve von etwa V^2.2, obwohl die "genaue" Transformation lautet:

sRGB zu Linear

Wo V´ der gammakodierte R, G oder B-Kanal von sRGB ist.
Pseudocode:

function sRGBtoLin(colorChannel) {
        // Senden Sie dieser Funktion einen dezimalen sRGB-gammakodierten Farbwert
        // zwischen 0,0 und 1,0, und sie gibt einen linearisierten Wert zurück.

    if ( colorChannel <= 0,04045 ) {
            return colorChannel / 12,92;
        } else {
            return pow((( colorChannel + 0,055)/1,055),2,4);
        }
    }

Schritt drei:

Um die Helligkeit (Y) zu finden, wenden Sie die Standardkoeffizienten für sRGB an:

Koeffizienten anwenden Y = R * 0,2126 + G * 0,7152 + B *  0,0722

Pseudocode unter Verwendung der obigen Funktionen:

Y = (0,2126 * sRGBtoLin(vR) + 0,7152 * sRGBtoLin(vG) + 0,0722 * sRGBtoLin(vB))

UM DIE WAHRGENOMMENE HELLIGKEIT ZU FINDEN:

Schritt vier:

Nehmen Sie die Helligkeit Y von oben und transformieren Sie sie in L*

L* aus Y Gleichung
Pseudocode:

function YtoLstar(Y) {
        // Senden Sie dieser Funktion einen Helligkeitswert zwischen 0,0 und 1,0,
        // und sie gibt L* zurück, was "wahrnehmbare Helligkeit" ist.

    if ( Y <= (216/24389)) {
            return Y * (24389/27);
        } else {
            return pow(Y,(1/3)) * 116 - 16;
        }
    }

L* ist ein Wert von 0 (schwarz) bis 100 (weiß), wobei 50 das wahrnehmbare "Mittelgrau" ist. L* = 50 entspricht Y = 18,4 oder mit anderen Worten einer 18% grauen Karte, die die Mitte einer fotografischen Belichtung (Ansel Adams Zone V) darstellt.

Referenzen:

IEC 61966-2-1:1999 Standard
Wikipedia sRGB
Wikipedia CIELAB
Wikipedia CIEXYZ
Charles Poyntons Gamma-FAQ

1 Stimmen

Ich habe eine Demonstration erstellt, die BT.601 Luma und CIE 1976 L* Perceptual Grey vergleicht, unter Verwendung weniger MATLAB-Befehle: Luma=rgb2gray(RGB);LAB=rgb2lab(RGB);LAB(:,:,2:3)=0;Perceptua‌lGray=lab2rgb(LAB);

2 Stimmen

@asdfasdfads Ja, `L*a*b*` berücksichtigt nicht eine Reihe von psychophysischen Attributen. Der Helmholtz-Kohlrausch-Effekt ist einer davon, aber es gibt viele andere. CIELAB ist keineswegs ein "vollständiges" Bildbeurteilungsmodell. In meinem Beitrag habe ich versucht, die grundlegenden Konzepte so vollständig wie möglich zu behandeln, ohne in die sehr tiefen Details einzutauchen. Das Hunt-Modell, Fairchilds Modelle und andere erledigen einen weit umfassenderen Job, sind jedoch auch wesentlich komplexer.

1 Stimmen

Beachten Sie, dass der falsche Schwellenwert aus dem alten sRGB-Standard auch in anderen Veröffentlichungen, einschließlich der offiziellen Beschreibung des Mindesttextkontrasttests der Web Content Accessibility Guidelines 2.1, weitergegeben wird. Da Barrierefreiheit die Frage motiviert haben könnte, könnte dies nützliche Informationen sein. w3.org/WAI/WCAG21/Techniques/general/G17.html#tests

123voto

Petr Hurtak Punkte 2161

Ich habe den Vergleich der drei Algorithmen in der akzeptierten Antwort erstellt. Ich habe Farben in einem Zyklus generiert, wobei nur etwa jede 400. Farbe verwendet wurde. Jede Farbe wird durch 2x2 Pixel dargestellt, die Farben sind von dunkelsten bis hellsten sortiert (von links nach rechts, von oben nach unten).

1. Bild - Helligkeit (relativ)

0,2126 * R + 0,7152 * G + 0,0722 * B

2. Bild - http://www.w3.org/TR/AERT#color-contrast

0,299 * R + 0,587 * G + 0,114 * B

3. Bild - HSP Farbmodell

sqrt(0,299 * R^2 + 0,587 * G^2 + 0,114 * B^2)

4. Bild - WCAG 2.0 SC 1.4.3 relative Helligkeit und Kontrastverhältnis Formel (siehe @Synchro's Antwort hier)

Je nach der Anzahl der Farben in einer Reihe kann ein Muster manchmal auf dem 1. und 2. Bild erkannt werden. Ich habe noch nie ein Muster auf dem Bild des 3. oder 4. Algorithmus entdeckt.

Wenn ich wählen müsste, würde ich mich für Algorithmus Nummer 3 entscheiden, da er viel einfacher zu implementieren ist und ungefähr 33% schneller ist als der 4.

Vergleich der wahrgenommenen Helligkeitsalgorithmen

16 Stimmen

Dein Vergleichsbild ist inkorrekt, weil du nicht den richtigen Eingang für alle Funktionen bereitgestellt hast. Die erste Funktion erfordert linearen RGB-Eingang; ich kann den Banding-Effekt nur reproduzieren, indem ich nichtlineare (d.h. gama-korrigierte) RGB bereitstelle. Wenn du dieses Problem korrigierst, treten keine Banding-Artefakte auf und die erste Funktion ist der klare Gewinner.

4 Stimmen

@Max die `^2` und `sqrt` in der dritten Formel sind eine schnellere Methode zur Annäherung von linearem RGB aus nicht-linearem RGB anstelle von `^2.2` und `^(1/2.2)`, die korrekter wäre. Leider ist es äußerst häufig, nicht-lineare Eingaben anstelle von linearen zu verwenden.

0 Stimmen

Hast du RGB auf {0, 1} normalisiert oder bei {0, 255} belassen?

82voto

Jive Dadson Punkte 15912

Unten finden Sie den EINZIGEN KORREKTEN Algorithmus zur Umwandlung von sRGB-Bildern, wie sie in Browsern usw. verwendet werden, in Graustufen.

Es ist erforderlich, eine Inverse der Gamma-Funktion für den Farbraum anzuwenden, bevor das innerhältnis berechnet wird. Anschließend wenden Sie die Gamma-Funktion auf den reduzierten Wert an. Das Fehlen der Gamma-Funktion kann zu Fehlern von bis zu 20% führen.

Für typische Computerdinge ist der Farbraum sRGB. Die richtigen Zahlen für sRGB sind ungefähr 0,21, 0,72, 0,07. Gamma für sRGB ist eine zusammengesetzte Funktion, die eine Exponentialfunktion mit 1/(2,2) annähert. Hier ist das Ganze in C++.

// sRGB-Ausleuchtungswerte(Y)
const double rY = 0.212655;
const double gY = 0.715158;
const double bY = 0.072187;

// Inverse der sRGB "Gamma"-Funktion (ca. 2,2)
double inv_gam_sRGB(int ic) {
    double c = ic/255.0;
    if ( c <= 0.04045 )
        return c/12.92;
    else 
        return pow(((c+0.055)/(1.055)),2.4);
}

// sRGB "Gamma"-Funktion (ca. 2,2)
int gam_sRGB(double v) {
    if(v<=0.0031308)
      v *= 12.92;
    else 
      v = 1.055*pow(v,1.0/2.4)-0.055;
    return int(v*255+0.5); // Dies ist korrekt in C++. Andere Sprachen benötigen möglicherweise kein +0.5
}

// GRAUWERT ("Helligkeit")
int gray(int r, int g, int b) {
    return gam_sRGB(
            rY*inv_gam_sRGB(r) +
            gY*inv_gam_sRGB(g) +
            bY*inv_gam_sRGB(b)
    );
}

1 Stimmen

Warum haben Sie eine zusammengesetzte Funktion verwendet, um den Exponenten zu approximieren? Warum nicht einfach eine direkte Berechnung durchführen? Danke

8 Stimmen

Das ist genau die Art und Weise, wie sRGB definiert ist. Ich glaube, der Grund dafür ist, dass es einige numerische Probleme in der Nähe von Null vermeidet. Es würde keinen großen Unterschied machen, wenn Sie die Zahlen einfach auf die Potenzen von 2.2 und 1/2.2 erhöhten.

10 Stimmen

JMD - Im Rahmen der Arbeit in einem Labor für visuelle Wahrnehmung habe ich direkte Leuchtdichtemessungen an CRT-Monitoren durchgeführt und kann bestätigen, dass es einen linearen Bereich der Leuchtdichte am unteren Ende des Wertebereichs gibt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X