Was sind die praktischen Unterschiede beim Arbeiten mit Farben in einem linearen oder einem nichtlinearen RGB-Raum?


85

Was ist die grundlegende Eigenschaft eines linearen RGB-Raums und was ist die grundlegende Eigenschaft eines nichtlinearen? Was ändert sich, wenn über die Werte in jedem Kanal in diesen 8 (oder mehr) Bits gesprochen wird?

In OpenGL sind Farben 3 + 1 Werte, und damit meine ich RGB + Alpha, wobei 8 Bit für jeden Kanal reserviert sind, und dies ist der Teil, den ich klar bekomme.

Aber wenn es um Gammakorrektur geht, verstehe ich nicht, wie sich das Arbeiten in einem nichtlinearen RGB-Raum auswirkt.

Da ich weiß, wie man eine Kurve in einer Grafiksoftware für die Fotobearbeitung verwendet, ist meine Erklärung, dass Sie in einem linearen RGB-Raum die Werte so nehmen, wie sie sind, ohne Manipulation und ohne mathematische Funktion, stattdessen, wenn sie nicht linear sind Der Kanal entwickelt sich normalerweise nach einem klassischen Verhalten der Leistungsfunktion.

Selbst wenn ich diese Erklärung als die reale nehme, verstehe ich immer noch nicht, was ein realer linearer Raum ist, weil nach der Berechnung alle nichtlinearen RGB-Räume linear werden und am wichtigsten ist, dass ich nicht den Teil bekomme, in dem ein nichtlinearer Raum ist -linearer Farbraum ist besser für das menschliche Auge geeignet, da am Ende alle RGB-Räume für das, was ich verstehe, linear sind.


In der Praxis können Sie in SVG entweder lineares oder Standard-RGB als Farbraum angeben, und ich habe keine Ahnung, was der Effekt ist, abgesehen von der Tatsache, dass dies wichtig zu sein scheint :-)
Michael Mullany

@MichaelMullany dieses lineare Ding sieht eher wie ein Hinweis für den Benutzer aus als wie eine echte unverwechselbare Qualität.
Ken

Etwas, das mir geholfen hat: Ich denke, es war ein Mathematiklehrer, der mir sagte "Denklinie, wenn du linear hörst". Ich bin mir nicht sicher, ob dies jemandem hilft, aber für mich war es ein "Oh ja!" Moment
Joe Plante

Antworten:


222

Angenommen, Sie arbeiten mit RGB-Farben: Jede Farbe wird mit drei Intensitäten oder Helligkeiten dargestellt. Sie müssen zwischen "linearem RGB" und "sRGB" wählen. Im Moment vereinfachen wir die Dinge, indem wir die drei verschiedenen Intensitäten ignorieren und davon ausgehen, dass Sie nur eine Intensität haben: Das heißt, Sie haben nur mit Graustufen zu tun.

In einem linearen Farbraum ist die Beziehung zwischen den von Ihnen gespeicherten Zahlen und den von ihnen dargestellten Intensitäten linear. In der Praxis bedeutet dies, dass Sie die Intensität (die Helligkeit des Graus) verdoppeln, wenn Sie die Zahl verdoppeln. Wenn Sie zwei Intensitäten addieren möchten (weil Sie eine Intensität basierend auf den Beiträgen zweier Lichtquellen berechnen oder weil Sie ein transparentes Objekt über einem undurchsichtigen Objekt hinzufügen), können Sie dies tun, indem Sie einfach die hinzufügen zwei Zahlen zusammen. Wenn Sie irgendeine Art von 2D-Überblendung oder 3D-Schattierung oder fast jede Bildverarbeitung durchführen, möchten Sie Ihre Intensitäten in einem linearen FarbraumSie können also einfach Zahlen addieren, subtrahieren, multiplizieren und dividieren, um den gleichen Effekt auf die Intensitäten zu erzielen. Die meisten Farbverarbeitungs- und Rendering-Algorithmen liefern nur mit linearem RGB korrekte Ergebnisse, es sei denn, Sie fügen allem zusätzliche Gewichte hinzu.

Das klingt wirklich einfach, aber es gibt ein Problem. Die Lichtempfindlichkeit des menschlichen Auges ist bei niedrigen Intensitäten feiner als bei hohen Intensitäten. Das heißt, wenn Sie eine Liste aller Intensitäten erstellen, die Sie unterscheiden können, gibt es mehr dunkle als helle. Anders ausgedrückt, Sie können dunkle Grautöne besser voneinander unterscheiden als helle Grautöne. Insbesondere wenn Sie 8 Bit zur Darstellung Ihrer Intensität verwenden und dies in einem linearen Farbraum tun, erhalten Sie zu viele helle Schattierungen und nicht genügend dunkle Schattierungen. Sie bekommen Streifen in Ihren dunklen Bereichen, während Sie in Ihren hellen Bereichen Teile auf verschiedenen Weißtönen verschwenden, die der Benutzer nicht unterscheiden kann.

Um dieses Problem zu vermeiden und diese 8 Bits optimal zu nutzen, verwenden wir in der Regel sRGB . Der sRGB-Standard gibt an, dass Sie eine Kurve verwenden müssen, um Ihre Farben nicht linear zu machen. Die Kurve ist unten flacher, sodass Sie mehr dunkle Grautöne und oben steiler haben können, sodass Sie weniger helle Grautöne haben. Wenn Sie die Zahl verdoppeln, verdoppeln Sie die Intensität mehr als. Dies bedeutet, dass Sie beim Hinzufügen von sRGB-Farben ein Ergebnis erzielen, das heller ist, als es sein sollte. Heutzutage interpretieren die meisten Monitore ihre Eingabefarben als sRGB. Also, wenn Sie eine Farbe auf dem Bildschirm setzen, oder es in einer 8-Bit-pro-Kanal - Textur zu speichern, speichern Sie es als sRGB , damit Sie die beste Verwendung dieser 8 Bits zu machen.

Sie werden feststellen, dass wir jetzt ein Problem haben: Wir möchten, dass unsere Farben im linearen Raum verarbeitet, aber in sRGB gespeichert werden. Dies bedeutet, dass Sie beim Lesen eine sRGB-zu-Linear-Konvertierung und beim Schreiben eine Linear-zu-sRGB-Konvertierung durchführen. Da wir bereits gesagt haben, dass lineare 8-Bit-Intensitäten nicht genügend Dunkelheiten aufweisen, würde dies zu Problemen führen. Daher gibt es eine weitere praktische Regel: Verwenden Sie keine linearen 8-Bit-Farben, wenn Sie dies vermeiden können. Es wird üblich, der Regel zu folgen, dass 8-Bit-Farben immer sRGB sind. Sie führen also Ihre sRGB-zu-Linear-Konvertierung gleichzeitig mit der Erweiterung Ihrer Intensität von 8 auf 16 Bit oder von Ganzzahl zu Gleitkomma durch. Wenn Sie Ihre Gleitkomma-Verarbeitung abgeschlossen haben, werden Sie gleichzeitig mit der Konvertierung in sRGB auf 8 Bit eingegrenzt. Wenn Sie diese Regeln befolgen,

Wenn Sie ein sRGB-Bild lesen und lineare Intensitäten wünschen, wenden Sie diese Formel auf jede Intensität an:

float s = read_channel();
float linear;
if (s <= 0.04045) linear = s / 12.92;
else linear = pow((s + 0.055) / 1.055, 2.4);

Wenn Sie ein Bild als sRGB schreiben möchten, wenden Sie diese Formel auf jede lineare Intensität an:

float linear = do_processing();
float s;
if (linear <= 0.0031308) s = linear * 12.92;
else s = 1.055 * pow(linear, 1.0/2.4) - 0.055; ( Edited: The previous version is -0.55 )

In beiden Fällen reicht der Gleitkomma-Wert von 0 bis 1. Wenn Sie also 8-Bit-Ganzzahlen lesen, möchten Sie zuerst durch 255 dividieren, und wenn Sie 8-Bit-Ganzzahlen schreiben, möchten Sie mit 255 multiplizieren Zuletzt genauso, wie Sie es normalerweise tun würden. Das ist alles, was Sie wissen müssen, um mit sRGB zu arbeiten.

Bisher habe ich mich nur mit einer Intensität befasst, aber es gibt klügere Dinge, die mit Farben zu tun haben. Das menschliche Auge kann verschiedene Helligkeiten besser voneinander unterscheiden als verschiedene Farbtöne (technisch gesehen hat es eine bessere Luminanzauflösung als Chrominanz), sodass Sie Ihre 24 Bit noch besser nutzen können, indem Sie die Helligkeit getrennt von der Tönung speichern. Dies versuchen YUV-, YCrCb- usw. Darstellungen zu tun. Der Y-Kanal ist die Gesamthelligkeit der Farbe und verwendet mehr Bits (oder hat eine größere räumliche Auflösung) als die beiden anderen Kanäle. Auf diese Weise müssen Sie nicht (immer) eine Kurve anwenden, wie Sie es bei RGB-Intensitäten tun. YUV ist ein linearer Farbraum. Wenn Sie also die Zahl im Y-Kanal verdoppeln, verdoppeln Sie die Helligkeit der Farbe, aber Sie können YUV-Farben nicht wie bei RGB-Farben addieren oder multiplizieren.

Ich denke, das beantwortet Ihre Frage, daher werde ich mit einer kurzen historischen Notiz enden. Vor sRGB war in alten CRTs eine Nichtlinearität eingebaut. Wenn Sie die Spannung für ein Pixel verdoppeln würden, würden Sie die Intensität mehr als verdoppeln. Wie viel mehr war für jeden Monitor unterschiedlich, und dieser Parameter wurde als Gamma bezeichnet . Dieses Verhalten war nützlich, weil es bedeutete, dass Sie mehr Dunkelheiten als Lichter erhalten konnten, aber es bedeutete auch, dass Sie nicht sagen konnten, wie hell Ihre Farben auf der CRT des Benutzers sein würden, es sei denn, Sie haben es zuerst kalibriert. Gamma-Korrekturbedeutet, die Farben, mit denen Sie beginnen (wahrscheinlich linear), zu transformieren und sie für das Gamma der CRT des Benutzers zu transformieren. OpenGL stammt aus dieser Zeit, weshalb sein sRGB-Verhalten manchmal etwas verwirrend ist. Aber GPU-Anbieter arbeiten jetzt in der Regel mit der oben beschriebenen Konvention: Wenn Sie eine 8-Bit-Intensität in einer Textur oder einem Framebuffer speichern, ist dies sRGB, und wenn Sie Farben verarbeiten, ist es linear. Bei einem OpenGL ES 3.0 verfügt beispielsweise jeder Framebuffer und jede Textur über ein "sRGB-Flag", das Sie aktivieren können, um die automatische Konvertierung beim Lesen und Schreiben zu ermöglichen. Sie müssen überhaupt keine explizite sRGB-Konvertierung oder Gammakorrektur durchführen.


5
erstaunliche Antwort, danke, es ist immer erstaunlich, wenn Dinge erklärt werden. Ich würde nur nach einem Buch oder einer Ressource fragen, die Ihrer Meinung nach für dieses Thema, die Farbräume und die Formeln für die Konvertierung von sRGB gut genug ist <-> linear oder welche Funktion kann dieses Verhalten approximieren?
Ken

Ich fürchte, ich kenne keine guten Bücher oder Ressourcen. Die Wikipedia-Seite ist umfassend und enthält alle Informationen zum Weißpunkt und zur Größe des Farbumfangs (was ich nicht erwähnt habe, da die meisten Leute nichts darüber wissen müssen), aber das macht es ein bisschen undurchdringlich .
Dan Hulme



1

Ich bin kein "Experte für menschliche Farberkennung", aber ich habe ähnliche Dinge bei der YUV-> RGB-Konvertierung getroffen. Es gibt unterschiedliche Gewichte für R / G / B-Kanäle. Wenn Sie also die Quellfarbe um x ändern, ändern die RGB-Werte unterschiedliche Mengen.

Wie gesagt, ich bin sowieso kein Experte. Ich denke, wenn Sie eine farbkorrekte Transformation durchführen möchten, sollten Sie dies im YUV-Raum tun und dann in RGB konvertieren (oder die mathematisch äquivalente Operation für RGB ausführen, Vorsicht von Datenverlust). Ich bin mir auch nicht sicher, ob YUV die beste native Darstellung von Farben ist, aber Videokameras bieten dieses Format. Hier bin ich auf das Problem gestoßen.

Hier ist die magische YUV-> RGB-Formel mit Geheimnummern: http://www.fourcc.org/fccyvrgb.php


1
Seien Sie vorsichtig bei RGB <-> YUV-Konvertierungen und zurück. Ich bin mir nicht sicher, ob dies in jedem Fall der Fall ist, aber der YUV-Farbraum wird manchmal in einen Bereich von 16 bis 235 anstelle des Bereichs von 0 bis 255 in 24-Bit-RGB konvertiert. Sie können also jedes Mal Daten verlieren, wenn Sie eine Farbraumkonvertierung durchführen. Die meisten Leute neigen dazu zu sagen, dass sie im selben Farbraum bleiben sollen, wenn Sie helfen können.
Joe Plante
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.