Nichtlineare Farbinterpolation?

7

Wenn ich eine gerade Linie habe, die von 0 bis 1 misst, dann habe ich colorA (255,0,0) bei 0 auf der Linie, dann bei 0,3 habe ich colorB (20,160,0) dann bei 1 auf der Linie Ich habe colorC (0,0,0). Wie könnte ich die Farbe bei 0,7 finden?

Danke

    
jmasterx 10.06.2010, 17:47
quelle

5 Antworten

27

[Meine Kommentare zu Patrick ausgearbeitet - alles war ein wenig außer Kontrolle geraten!]

Das ist wirklich eine interessante Frage, und einer der Gründe, warum es interessant ist, ist, dass es keine "richtige" Antwort gibt. Farbdarstellung und Dateninterpolation können auf viele verschiedene Arten erfolgen. Sie müssen Ihren Ansatz für Ihre Problemdomäne entsprechend anpassen. Da wir nicht viel a priori Informationen über diese Domäne erhalten haben, können wir nur einige der Möglichkeiten erkunden.

Das Geschäft mit Farben matschigt das Wasser etwas, also lassen wir das vorübergehend beiseite und denken zuerst über die Interpolation einfacher Skalare nach.

Ausflug in die Interpolation

Nehmen wir an, wir haben einige Datenpunkte wie folgt:

Was wir finden wollen, ist, was der y -Wert für dieses Diagramm an Punkten entlang der x -Achse ist, außer denen, für die wir Werte kennen. Das heißt, wir suchen nach einer Funktion

y = f(x)

das durch diese Punkte geht.

Natürlich gibt es viele verschiedene Möglichkeiten, wie wir die Punkte verbinden können. Wir könnten sie nur mit geraden Segmenten verbinden. Oder wir möchten eine glatte Kurve, und diese Kurve könnte einfach oder beliebig kompliziert sein:

Hier ist es leicht zu verstehen, woher die roten Linien kommen - wir zeichnen gerade Linien von einem bekannten Punkt zum nächsten. Die grüne Linie scheint auch vernünftig zu sein, obwohl wir einige Annahmen darüber hinzufügen, wie sich die Kurve verhalten sollte. Die blaue Linie andererseits wäre schwer zu rechtfertigen auf der Grundlage der Datenpunkte allein, aber dort könnten Umstände sein, bei denen wir Gründe haben, das System unter Verwendung einer solchen Form zu modellieren Wir werden es später sehen.

Beachten Sie auch die gestrichelten Linien, die von den Seiten jeder Kurve abgehen. Diese gehen über die bekannten Punkte hinaus, was Extrapolation anstelle von Interpolation genannt wird. Dies ist oft ein wenig fragwürdiger als eine Interpolation. Zumindest wenn du von einem bekannten Punkt zum nächsten gehst, hast du einige Beweise, dass du auf dem richtigen Weg bist. Je weiter man von den bekannten Punkten kommt, desto wahrscheinlicher wird man vom Weg abkommen. Aber es ist immer noch eine nützliche Technik und es kann durchaus sinnvoll sein.

OK, also ist das Bild hübsch und alles, aber wie generieren wir diese Zeilen?

Wir müssen eine f(x) finden, die uns die gewünschte y liefert. Es gibt viele verschiedene Funktionen, die wir abhängig von den Umständen verwenden können, aber bei weitem am häufigsten ist die Verwendung einer Polynomfunktion, dh:

%Vor%

Nun, mit N verschiedenen Datenpunkten, ist es immer möglich, eine perfekt passende Kurve mit einem Polynom von Grad N-1 zu finden - eine gerade Linie für zwei Punkte, eine Parabel für drei, eine kubische für vier usw. - aber wenn die Daten nicht ungewöhnlich gut sind, tendiert die Kurve dazu, verrückt zu werden, wenn der Grad steigt. Wenn also kein Grund zu der Annahme besteht, dass das Verhalten der Daten durch Polynome höheren Grades gut modelliert wird, ist es üblich, die Daten stückweise zu interpolieren, wobei ein anderes Kurvensegment zwischen jedem aufeinander folgenden Punktepaar angeordnet wird.

Typischerweise wird jedes Segment als Polynom mit dem Grad 1 oder 3 modelliert. Ersteres ist nur eine gerade Linie und wird verwendet, weil es wirklich einfach ist und keine Informationen benötigt, als die beiden Datenpunkte selbst. Letzteres ist ein kubischer Spline und wird verwendet, weil es das einfachste Polynom ist, das Ihnen einen weichen Übergang über jeden Punkt ermöglicht. Die Berechnung ist jedoch etwas komplexer und erfordert zwei zusätzliche Informationen für jedes Segment (genau das, was diese Teile sind, hängt von der jeweiligen Spline-Form ab, die Sie verwenden).

Die lineare Interpolation ist einfach genug, um in eine Codezeile zu gehen. Wenn unser erster Datenpunkt (x1, y1) und unser zweiter (x2, y2) ist, dann ist der linear interpolierte y bei jedem intermediate x :

%Vor%

(Variationen dazu erscheinen in einigen anderen Antworten.)

Cubic Splines sind ein bisschen zu kompliziert, um hier reinzukommen, aber Google sollte einige anständige Referenzen aufzeigen. Sie sind in diesem Fall sowieso übertrieben, da Sie nur drei Punkte haben.

Zurück zur Frage

Sehen wir uns nun das Problem wie beschrieben an:

Wir haben eine Linie (hier in grau dargestellt), deren Farbe nur an drei Punkten bekannt ist, und wir werden gebeten zu berechnen, was die Farbe an einem anderen Punkt sein wird. Da wir nicht wissen, wie die Colorus verteilt sind, müssen wir einige Annahmen treffen.

Eine Schlüsselannahme ist, dass Farbänderungen entlang der Linie kontinuierlich sind, zumindest in einer gewissen Annäherung.Klar, wenn die Zeile wirklich so aussah:

Dann würden all die früheren Sachen über die Interpolation aus dem Fenster verschwinden. Wir hätten keine Grundlage, um zu entscheiden, welche Farbe irgendein Teil sein sollte, und sollten einfach aufgeben und nach Hause gehen. Nehmen wir an, das ist nicht der Fall, und wir haben etwas zu interpolieren.

Die bekannten Farben werden als RGB angegeben. In dieser Darstellung ist jeder Kanal ein separater Skalarwert und wir können ihn als völlig unabhängig von den anderen betrachten. Ein vollkommen vernünftiger Ansatz wäre also eine stückweise lineare Interpolation jedes Kanals und dann die Rekombination der Ergebnisse.

Das gibt uns so etwas:

Das ist in Ordnung, soweit es geht, aber es gibt Aspekte des Ergebnisses, die wir vielleicht nicht mögen. Einer ist, dass der Übergang von Rot zu Grün durch ein ziemlich trübes Grau-Braun geht. Ein anderer ist, dass der grüne Peak bei 0,3 ein bisschen scharf ist.

Es ist wichtig zu beachten, dass dies in Ermangelung einer umfassenderen Spezifikation wirklich nur ästhetische Anliegen sind. Unsere Technik ist absolut solide, aber sie liefert nicht die Art von Ergebnissen, die wir uns wünschen. Dies hängt von unserer speziellen Problemdomäne ab und letztendlich ist alles eine Frage der Wahl.

Da wir nur drei Datenpunkte haben - und da Hans Passant es vorgeschlagen hat - könnten wir vielleicht stattdessen versuchen, eine Parabel anzubringen, um die gesamte Kurve auf jedem Kanal zu modellieren? Es ist wahr, wir haben keinen Grund zu denken, dass dies ein gutes Modell ist, aber es tut nicht weh zu versuchen:

Die Unterschiede zwischen diesem Gradienten und dem letzten sind aufschlussreich. Das Quadrat hat die Dinge geglättet, aber auch dramatisch übertroffen. Denken Sie daran, der grüne Kanal beginnt und endet bei 0. Eine Parabel ist symmetrisch, also muss ihr Maximum in der Mitte liegen. Die einzige Möglichkeit, einen grünen Anstieg in Richtung 0.3 zu erreichen, besteht darin, den Anstieg bis auf 0,5 fortzusetzen. (Es gibt einen ähnlichen Effekt im roten Kanal, aber es ist weniger offensichtlich, weil es in diesem Fall ein Unterschwingen ist und der Wert auf 0 geklemmt wird.)

Haben wir irgendwelche Beweise dafür, dass diese Art von Form wirklich in unserer Farblinie vorhanden ist? Nein, wir haben es explizit über unsere Modellwahl eingeführt. Das macht es nicht ungültig - wir könnten gute Gründe dafür haben, dass es so funktioniert - es ist wieder eine Frage der Wahl.

Aber was ist mit HSV?

Bisher haben wir uns an den ursprünglichen RGB-Farbraum gehalten, aber verschiedene Leute haben darauf hingewiesen, dass dies für die Interpolation weniger als ideal ist: Farbe und Intensität sind in RGB miteinander verbunden und interpolieren zwischen zwei verschiedenen Vollintensitäten Farben führen Sie normalerweise durch ein dunkles Mittel mit geringer Intensität.

In HSV -Darstellung sind Farbe und Intensität in separaten Dimensionen, sodass wir dieses Problem nicht haben. Warum nicht konvertieren und stattdessen die Interpolation in diesem Raum durchführen?

Das führt sofort zu einer Schwierigkeit - oder jedenfalls zu einer anderen Entscheidung. Die Zuordnung zwischen HSV und RGB ist nicht bijektiv ; Insbesondere black , bei dem es sich um einen unserer drei Datenpunkte handelt, handelt es sich um einen einzelnen Punkt im RGB-Raum, der jedoch in HSV eine ganze Ebene einnimmt. Wir können nicht zwischen einem Punkt und einer Ebene interpolieren, also müssen wir einen bestimmten HSV-Schwarzpunkt auswählen, zu dem wir gehen können.

Dies ist die Grundlage von Patricks genialer Lösung, bei der H und S speziell dafür ausgewählt wurden, den gesamten Farbverlauf linear zu machen. Das Ergebnis sieht ungefähr so ​​aus:

Das sieht viel hübscher und bunter aus als die vorherigen Versuche, aber es gibt ein paar Dinge, mit denen wir uns herumschlagen könnten.

Ein wichtiges Problem ist, dass im Falle von V, wo wir noch eindeutige Daten an allen drei Punkten haben, diese Daten nicht wirklich linear sind, und so ist die lineare Anpassung nur eine Annäherung. Das bedeutet, dass der Wert, den wir hier bei 0,3 sehen, nicht ganz so ist, wie er sein sollte.

Eine andere, meiner Meinung nach größere, knifflige Frage: Woher kommt all das Blau? Alle drei unserer bekannten RGB-Datenpunkte haben B = 0. Es erscheint ein bisschen seltsam, plötzlich eine ganze Reihe von Blau vorzustellen, für die wir anscheinend überhaupt keine Beweise haben. Sehen Sie sich dieses Diagramm der RGB-Komponenten in Patricks HSV-Interpolation an:

Der Grund für das Blau ist natürlich, dass wir beim Wechseln von Farbräumen ein Modell ausgewählt haben, bei dem Sie, wenn Sie von Grün weitergehen, unweigerlich zu Blau kommen. Gleichzeitig mussten wir einen unserer Farbton-Datenpunkte verwerfen und haben uns entschieden, ihn durch lineare Extrapolation von den anderen zwei zu füllen, was bedeutet, dass wir tun geh einfach weiter, von grün zu blau über die hügel und weit weg.

Noch einmal, das ist nicht ungültig, und wir haben vielleicht einen guten Grund, es so zu machen. Aber meiner Meinung nach ist es wegen dieser Extrapolation ein wenig mehr als das vorherige stückweise-lineare Beispiel.

Also ist das der einzige Weg, es im HSV zu machen? Natürlich nicht. Es gibt immer mehr Auswahlmöglichkeiten.

Anstatt beispielsweise die H- und S-Werte bei 1,0 zu wählen, um die Linearität zu maximieren, wählen wir sie stattdessen aus, um die Änderung bei einer stückweisen linearen Interpolation zu minimieren. Wie es passiert, für S stimmen die beiden Strategien überein: Es ist 100 an beiden Punkten, also machen wir es am Ende auch 100. Die zwei Segmente sind kollinear. Für H behalten wir es im zweiten Segment gleich. Dies ergibt ein Ergebnis wie folgt:

Das ist nicht ganz so süß wie das vorherige, aber es erscheint mir etwas plausibler. Aber auch das ist wieder ein ästhetisches Urteil. Das macht das nicht mehr zur "richtigen" Antwort, als es Patrick oder irgendeinen anderen "falsch" macht. Wie ich schon am Anfang gesagt habe, gibt es keine "richtige" Antwort. Es geht darum, Entscheidungen zu treffen, die Ihren Bedürfnissen in einem bestimmten Problem entsprechen - und sich bewusst zu sein, dass Sie diese Entscheidungen getroffen haben und wie sie Ihr Ergebnis beeinflussen.

    
walkytalky 12.06.2010, 22:00
quelle
7

Versuchen Sie, dies in eine andere Farbdarstellung, z. HSV (siehe Ссылка ).

  • Farbe A hat einen Farbton von 0, eine Sättigung von 1 und einen Wert von 1.
  • Farbe C hat einen Farbton von?, eine Sättigung von? und ein Wert von 0.

? bedeutet, dass es eigentlich keine Rolle spielt (da Farbe C einfach schwarz ist).

Konvertiere nun auch Farbe B in einen HSV (kann das nicht aus meinem Kopf tun, sorry), dann wähle schöne Werte für den Farbton und die Sättigung von Farbe C, so dass Farbton, Wert und Sättigung auf einer Linie liegen der HSV-Raum. Ziehen Sie dann die Farbe von 0,7 ab.

BEARBEITEN: Mit dem RGB-HSV-Rechner in Ссылка berechnete ich Folgendes:

  • Farbe A: H: 0, V: 100, S: 100
  • Farbe B: H: 113, V: 100, S: 63

Nun berechnen wir das H und V der Farbe C wie folgt:

  • H: 113 / 0,3 = 376,6
  • V: 100 (da sowohl A als auch B ein V oder 100 haben)

Das gibt uns für die Farbe bei 0.7:

  • H = 376,66 * 0,7 = 263,66
  • V = 100
  • S = irgendwo um 30

Leider passt dies nicht vollständig für die Sättigung, aber wenn Sie auf diese Weise interpolieren, erhalten Sie etwas, das Ihrem Wunsch sehr nahe kommt.

    
Patrick 10.06.2010 17:57
quelle
4

In der Zusammenfassung fragen Sie nach dem Wert von f (0.7), vorausgesetzt, dass f (0.0) = (255, 0, 0), f (0.3) = (20, 160, 0) und f ( 1.0) = (0, 0, 0). Wie bereits erwähnt, ist dies nicht gut definiert, da f eine unendliche Anzahl von Funktionen sein kann.

Einige mögliche Optionen für f sind:

  1. Eine Reihe von Liniensegmenten im RGB-Raum
  2. Eine Reihe von Liniensegmenten nach Zuordnung zu HSV- oder HSL-Raum
  3. Ein kubischer Spline im RGB-Raum.
  4. Ein kubischer Spline im HSV / L-Raum.

Aber die spezielle Wahl, wie f definiert werden sollte, sollte davon abhängen, was Sie tun, oder wie die Farbunterbrechungen für Ihre Anwendung definiert sind.

    
user97370 10.06.2010 18:11
quelle
3

Der richtige Weg zum Interpolieren von RGB besteht darin, zunächst Gamma zu korrigieren, die Farbkomponenten linear zu machen, eine Interpolation durchzuführen und dann zurück zu konvertieren. Andernfalls erhalten Sie Fehler, weil die Werte nichtlinear sind. Weitere Informationen finden Sie unter Ссылка . In diesem Artikel geht es jedoch um die Skalierung. Die Skalierung erfolgt normalerweise durch Interpolation von Pixelwerten. .

Wenn Sie sRGB-Werte haben, können Sie zwischen linearen und nichtlinearen Formeln mit den folgenden Formeln konvertieren: Ссылка (verwenden Sie den Csrgb und lineare Formeln)

Auf der anderen Seite sind die Fehler nicht groß, daher hängt es von Ihrer Anwendung ab, wenn sie wichtig sind.

Für die Interpolation selbst sollte einfache lineare Interpolation ausreichen (wie andere hier bemerkt haben). Siehe Ссылка für die Besonderheiten.

    
ergosys 10.06.2010 18:36
quelle
0

Es sieht so aus, als würden Sie versuchen, im falschen Farbraum zu interpolieren. Zuerst konvertiere zu HSV, dann werden deine Farben

%Vor%

so ist es immer noch verwirrend, aber zumindest können wir sehen, dass der V-Wert auf Null interpoliert wird, der H-Wert ist verwirrend, aber nach der Erkenntnis, dass HSV ist als ein Zylinder modelliert, wir können sehen, dass es wirklich nur von 0 bis 256 mod 256 interpoliert, so dass es einfach auf Null geht.

also wäre deine Gleichung (in HSV)

%Vor%

Also, wenn Sie 0.7 für Frac ersetzen, erhalten Sie die richtige Berechnung in HSV-Koordinaten, wenn Sie zurück zu RGB gehen müssen, sollten Sie sehen, ob Ihre Bibliotheken eine solche Funktion bieten (ich weiß, dass Javas Color-Klasse dies unterstützt), aber wenn Sie können nicht einfach den Code von hier . Es zeigt, wie Farbraumkonvertierungen in C durchgeführt werden.

Viel Glück

    
luke 10.06.2010 18:05
quelle

Tags und Links