Hallo,
ich beschäftige mich grad mit der Umrechnung von HSV nach RGB.
Hier im Forum gibt's ja schon einige Beispiele dazu, u.a. auch eine von
Benedikt K. verfasste Variante, welche ohne float-Werte zurechtkommt:
Beitrag "Re: HSV RGB Led Dimmer, C Code & Video & Doku"
Recht praktisch, da ich das in ASM auf einem 8051 machen will.
Allerdings bräuchte ich auch den umgekehrten Weg, das heisst von RGB zu
HSV. Mir ist klar, dass es natürlich Umrechnungsverluste gibt, wenn man
nicht mit float o.ä. arbeitet. Diese Umrechnungsverluste an sich spielen
keine Rolle.
Ich bräuchte aber die beiden Berechnungen so, dass es zwischen den
Umrechnungen keine Verluste gibt.
Deswegen grübel ich gerade, ob es überhaupt Sinn macht, die Berechnungen
auf dem Controller durchzuführen und stattdessen eher Tabellen zu
verwenden (was auch der Geschwindigkeit zugute kommt).
Im Wikipedia-Artikel http://de.wikipedia.org/wiki/HSV-Farbraum ist u.a.
der Zusammenhang zwischen dem RGB- und dem HSV-Farbraum gezeigt:
http://de.wikipedia.org/w/index.php?title=Datei:HSV-RGB-comparison.svg
Was für mich dort noch nicht ersichtlich ist bzw. wobei ich die Grafik
unverständlich finde ist der Zusammenhang zwischen Value- und
Saturation-Wert.
Hue wählt die Farbe an sich, bzw. die anteilige Zusammensetzung aus RGB.
Saturation ist die Intensität der durch Hue gewählten Farbe(n).
Value ist die Intensität gleichmäßig über alle drei Farben.
Ist das so richtig? Bringt mir ja nix, wenn ich's noch nicht exakt
verstanden habe, vorher brauch ich gar nicht weitermachen :)
Wenn das soweit richtig wäre, dann bringt ein Tabellenansatz
wahrscheinlich nix, denn das wären ja riesige Tabellen, da muss dann
doch noch gerechnet werden, aber das wär erst mal nebensächlich.
Hauptsache ich verstehe das System an sich. Über das verlustfreie
Umrechnen kann man sich immer noch Gedanken machen.
Ralf
Ralf schrieb:> Was für mich dort noch nicht ersichtlich ist bzw. wobei ich die Grafik> unverständlich finde ist der Zusammenhang zwischen Value- und> Saturation-Wert.>> Hue wählt die Farbe an sich,
Also einen Wert am oberen Umfang des Kegels
> Saturation ist die Intensität der durch Hue gewählten Farbe(n).
die Farbsättigung.
Was man im Bild nicht (oder nur schlecht) sieht:
In der Mitte, in der Drehachse des Kegels liegen die 'unbunten' Farben.
Also die Grauwerte, von weiß bis schwarz. Weiß ist oben und schwarz ist
an der Spitze.
Mit Saturation bestimmst du im Grunde, wie weit dein Farbpunkt von
dieser Drehachse entfernt ist. Je näher in der Mitte, desto unbunter ist
deine Farbe und desto mehr hast du keine Farbe mehr, sondern einfach nur
einen Grauwert.
> Value ist die Intensität gleichmäßig über alle drei Farben.
die Helligkeit der Farbe
Value ist die Höhe in der dein Punkt auf dem Kegel ist. Je weiter oben,
desto mehr bist du auf deiner echten Farbe (bzw. weiß). Je weiter unten,
desto näher bist du an Schwarz
Wenn du dich für eine Hue entschieden hast (also die Farbe), dann kann
man da einen Schnitt durch den Kegel machen und diese Schnittfläche ist
ein Dreick. zb bei der Hue für Rot
Rot <--0 Saturation
+------------+ weiß
\ | o value
\ | |
\ | |
\ | |
\ | |
\ | |
\ | v
\ |
\ |
\ |
\ |
\| schwarz
Auf dieser Schnittfläche (also alle Punkte innerhalb des Dreiecks)
liegen also alle Rot-Werte die es gibt. Von reinem Rot (links oben) bis
zu allen Nuancen die man in Richtung weiß bzw. in Richtung schwarz
bilden kann. An der senkrechten Kante rechts sind alle Farben dann nur
noch Grauschattierungen.
Ralf schrieb:> Wenn das soweit richtig wäre, dann bringt ein Tabellenansatz> wahrscheinlich nix, denn das wären ja riesige Tabellen, da muss dann> doch noch gerechnet werden, aber das wär erst mal nebensächlich.> Hauptsache ich verstehe das System an sich. Über das verlustfreie> Umrechnen kann man sich immer noch Gedanken machen.
Was genau willst du machen?
Wenn es darum geht einen Farbverlauf durchzudimmen, dann kann man mit
dem Bild im Wiki-Artikel bei "Zusammenhang HSV-RGB" die Sache deutlich
vereinfacht machen.
Man kann das HSV-System auch hinsichtlich Spektrum und Wellenlänge
interpretieren:
- Hue, die Farbe beginnt auf dem Kreis bei 0 Grad Rot (entspricht 700
nm) und endet bei 270 Grad Blau (entspricht ungefähr 400 nm). Der
restliche Viertelkreis ist ein Zugeständnis an eine Unzulänglichkeit des
menschlichen Auges: Magenta. Entsteht als Sinneseindruck durch
Überlagerung von Rot und Blau, hat aber keine Wellenlänge, weil es
Magenta nicht als monocrhomatisches Licht gibt.
- Saturation, die Sättigung, wird manchmal auch als "Reinheit"
interetiert. Stell dir vor, du sollst eine Wellenlänge in ein Spektrum
von 400-700 nm einzeichenen. Du setzt einen "Nadelimpuls", dann hast du
eine Saturation von 1, genau die eine Farbe. Machst du die Nadel breiter
und oben rund, kommen andere Wellenlängen hinzu, die Saturation sinkt.
Ziehst du eine waagerechte Linie durchs ganze Spektrum, hast du alle
Farben, also keine Sättigung mehr. Je nach Höhe der Linie (Value) ists
dann Weiss, Grau oder Schwarz ...
Verständliche Formeln gibts hier: www.easyrgb.com/index.php?X=MATH
Von HSV nach RGB konvertieren und den RGB-Wert wieder zurück zum
gleichen HSV-Wert geht prinzipbedingt nicht eindeutig. Denn für eine
bestimmte Graustufe gibt es im RGB-Modell nur eine
Darstellungsmöglichkeit (rot = grün = blau = Graustufe), im HSV-Modell
dagegen bei 8 Bit 256 verschiedene (Helligkeit = Graustufe, Sättigung 0,
Farbton beliebig). Bei der Konvertierung von HSV nach RGB geht bei einer
Graustufe also die Farbton-Information verloren.
Sag am besten mal, wozu Du das brauchst, es gibt bestimmt eine andere
Lösung. Zum Beispiel könntest Du zu einer Farbe immer beide
Repräsentationen speichern und bei Änderungen in einem Modell (z.B. im
HSV-Modell Farbton + 1) den neuen Wert in das jeweils andere Modell
(also hier RGB) konvertieren, so dass beide immer "synchron" bleiben.
Vielleicht ist es aber nicht mal nötig, sondern geht noch viel
einfacher.
Hi,
ne Umwandlung von HSI nach RGB für ne Lichtsteuerung findest du auch
hier,Maklerinnen für AVRs in ASM.
http://falk-land.com/node/14
bzw.
http://rgblightcontrol.sourceforge.net
Auf der angegeben Seite (bzw im SVN) findest du auch ne Excel-Tabelle,
wo die Konvertierungsfehler dargestellt werden, in dem Fall für ne
8Bit-PWM.
Mir stellt sich allerdings die Frage, wozu du präzise Umrechnungen
benötigst. Mit LEDs kannste die Graustufen weitgehend knicken und musst
aufgrund der nichtlinearen Helligkeitsverteilung von LEDs bzw. der
niedrigen Quantisierungstiefe bei PWM (im Sinne von Kompromiss zwischen
hinreichend hoher PWM-Frequenz und Bitanzahl) mit Abstrichen leben.
Soll heißen: ermittle die farbrelevanten Parameter deines Systems und
entscheide, ob das diese Präzision überhaupt benötigt, sonst isses
Quatsch. Z.B. Ist die Intensität bei RGB-LEDs nichtlinear - angenommen,
eine Intensität von 127 sei maximal, dann ist 63 nicht halb so hell! Für
normale Zwecke reichen aber einfache Approximationen locker aus.
Und auch nicht vergessen, dass du schon alleine im RGB-Farbraum
allerhand machen kannst, vielleicht kannste dir Farbraum-Umrechnungen
dann schon komplett klemmen.
Hallo,
vielen Dank für eure Antworten.
@Karl Heinz Buchegger:
Danke für die Erläuterung. Das heisst eine Sättigung von 0 führt bei
Value = 1 immer zu weiss, unabhängig vom Hue, richtig? So entnehme ich
das deinem Kegelschnitt.
> Was genau willst du machen?> Wenn es darum geht einen Farbverlauf durchzudimmen, dann kann man mit> dem Bild im Wiki-Artikel bei "Zusammenhang HSV-RGB" die Sache deutlich> vereinfacht machen.
Der Controller empfängt RGB-Werte und gibt diese per PWM aus. Die Idee
war jetzt eben noch ein "Klecks Luxus", weil man mit HSV m.E. viel
schneller zur Wunschfarbe kommt. Der Wunsch nach der "verlustfreien"
Umrechnung war einfach die Idee, dass man ja auch mal die Werte vom
Controller abfragen möchte, wenn jemandem eine RGB-Farbe gefällt und man
die HSV-Werte haben möchte.
@Frank:
Die Erklärung mit Nadeln ist gut, danke! Der Link ist praktisch, da kann
man super von-nach-Konvertierungsroutinen schreiben! Super Sache!
@Fabian O.:
> Von HSV nach RGB konvertieren und den RGB-Wert wieder zurück zum> gleichen HSV-Wert geht prinzipbedingt nicht eindeutig.
Okay, hab ich schon befürchtet :)
> Sag am besten mal, wozu Du das brauchst, es gibt bestimmt eine andere> Lösung.
Wie oben erwähnt, einfach dem User die Möglichkeit geben, zu einem
RGB/HSV-Farbwert das Pendant herauszufinden.
> Zum Beispiel könntest Du zu einer Farbe immer beide Repräsentationen> speichern und bei Änderungen in einem Modell (z.B. im> HSV-Modell Farbton + 1) den neuen Wert in das jeweils andere Modell> (also hier RGB) konvertieren, so dass beide immer "synchron" bleiben.
Das geht eben nicht, weil man dann die Berechnung schon gemacht hat,
bevor der Controller die Daten bekommt - für diesen wiederum ist es ja
nicht nötig, dass er beides kennt.
> Vielleicht ist es aber nicht mal nötig, sondern geht noch viel> einfacher.
Ja, das geht einfacher - ich kann nämlich auch ganz frech sagen, dass es
nur entweder-oder gibt. Also dass der Controller die Daten entweder als
HSV oder RGB interpretiert, aber das jeweilige Pendant nicht
zurückliefern kann. Intern kann ich ja von HSV nach RGB konvertieren
(muss ich ja eh).
Ich denke, so werd ich das dann auch machen. Wer dann immer noch
RGB->HSV braucht kann sich zumindest die groben RGB-Werte über die
diversen Webseiten oder selbst mithilfe des von Frank genannten Links
umrechnen.
Ralf
@Falk:
> ne Umwandlung von HSI nach RGB für ne Lichtsteuerung findest du auch> hier,Maklerinnen für AVRs in ASM.
Danke, schau ich gleich mal an.
> Auf der angegeben Seite (bzw im SVN) findest du auch ne Excel-Tabelle,> wo die Konvertierungsfehler dargestellt werden, in dem Fall für ne> 8Bit-PWM.
Das hört sich gut an, da kann ich ein Feeling für die
Umrechnungsverluste bekommen.
> Mir stellt sich allerdings die Frage, wozu du präzise Umrechnungen> benötigst. Mit LEDs kannste die Graustufen weitgehend knicken und musst> aufgrund der nichtlinearen Helligkeitsverteilung von LEDs bzw. der> niedrigen Quantisierungstiefe bei PWM (im Sinne von Kompromiss zwischen> hinreichend hoher PWM-Frequenz und Bitanzahl) mit Abstrichen leben.
Wie gesagt, war einfach deswegen, weil ich ursprünglich eben vorhatte,
die jeweiligen Pendants ausgeben zu können.
Stimmt, die Abstriche muss man auch noch mit einbeziehen.
> Soll heißen: ermittle die farbrelevanten Parameter deines Systems und> entscheide, ob das diese Präzision überhaupt benötigt, sonst isses> Quatsch. Z.B. Ist die Intensität bei RGB-LEDs nichtlinear - angenommen,> eine Intensität von 127 sei maximal, dann ist 63 nicht halb so hell! Für> normale Zwecke reichen aber einfache Approximationen locker aus.
Dafür verwende ich einen Ansatz hier aus dem Forum. Den Link kann ich
mal raussuchen. Hab's grad nicht parat, wenn ich mich recht erinnere
wird im groben die n-te Wurzel aus der PWM-Auflösung gezogen, wobei n
die Anzahl der gewünschten Stufen ist.
Der resultierende Wert ist ein Faktor. Stufe 0 ist 0, Stufe 1 ist F^1,
usw.
Damit hab ich ganz gute Erfahrungen gemacht.
> Und auch nicht vergessen, dass du schon alleine im RGB-Farbraum> allerhand machen kannst, vielleicht kannste dir Farbraum-Umrechnungen> dann schon komplett klemmen.
Mir erschien der HSV-Farbraum eben einfacher, wenn man eine bestimmte
Farbe erzeugen möchte.
Ralf
Ich verstehe jetzt nicht, wo das Problem liegt, den Controller beide
Umrechungen machen zu lassen. Dann kann er von außen Farben in RGB und
HSV annehmen und auch jede Farbe als RGB und HSV zurückliefern.
Also im Prinzip so:
1
color_rgb_tled_rgb;
2
color_hsv_tled_hsv;
3
4
voidset_rgb(color_rgb_trgb){
5
led_rgb=rgb;
6
led_hsv=color_rgb_to_hsv(rgb);
7
]
8
9
color_rgb_tget_rgb(void){
10
returnrgb;
11
}
12
13
voidset_hsv(color_hsv_thsv){
14
led_hsv=hsv;
15
led_rgb=color_hsv_to_rgb(hsv);
16
]
17
18
color_hsv_tget_hsv(void){
19
returnhsv;
20
}
Kostet drei Byte pro Farbe, die "unnötig" gespeichert sind. Wenn Dich
das stört, dann eben so:
1
color_rgb_tled_rgb;
2
3
voidset_rgb(color_rgb_trgb){
4
led_rgb=rgb;
5
]
6
7
color_rgb_tget_rgb(void){
8
returnrgb;
9
}
10
11
voidset_hsv(color_hsv_thsv){
12
led_rgb=color_hsv_to_rgb(hsv);
13
]
14
15
color_hsv_tget_hsv(void){
16
returncolor_rgb_to_hsv(led_rgb);
17
}
Dann ist aber nicht garantiert, dass man mit get_hsv() genau den mit
set_hsv() gesetzten Wert zurückbekommt. Wäre in Deinem konkreten
Anwendungsbeispiel aber ja auch nicht mal schlimm.
> Ich verstehe jetzt nicht, wo das Problem liegt, den Controller beide> Umrechungen machen zu lassen.> Dann ist aber nicht garantiert, dass man mit get_hsv() genau den mit> set_hsv() gesetzten Wert zurückbekommt. Wäre in Deinem konkreten> Anwendungsbeispiel aber ja auch nicht mal schlimm.
Schlimm nicht, es dürfte optisch kaum einen Unterschied machen.
Vielleicht implementier ich's doch noch, mal schauen. Und um Rückfragen
der Anwender zu unterbinden, warum die Konvertierungen Abweichungen
voneinander haben kann ich ja auf die Umrechnungen verweisen und
erläutern, dass es prinzipbedingt Abweichungen gibt.
Ralf
Ralf schrieb:> Und um Rückfragen> der Anwender zu unterbinden, warum die Konvertierungen Abweichungen> voneinander haben kann ich ja auf die Umrechnungen verweisen und> erläutern, dass es prinzipbedingt Abweichungen gibt.
In der ersten Variante liefert der Controller doch immer genau das
zurück, was der Anwender vorgegeben hat.
Ralf schrieb:> voneinander haben kann ich ja auf die Umrechnungen verweisen und> erläutern, dass es prinzipbedingt Abweichungen gibt.
Dann würde ich einfach die jeweilige Vorgabe vom Benutzer auf jeden Fall
so speichern, wie ich sie kriege.
Kriege ich HSV, dann rechen ich RGB aus
Will der Benutzer wieder HSV, dann kriegt er die Werte die er mir
gegeben hat.
Will er RGB, dann kriegt er eben die errechneten
Kriege ich RGB, dann rechne ich HSV aus
Will der Benuter HSV, dann kriegt er die errechneten
Will er aber RGB, dann kriegt er die, die er mir gegeben hat.
Auf die Art ist sichergestellt, dass er auf jeden Fall wieder exakt die
Werte bekommt, die er mir auch gegeben hat und 'nur' die jeweils anderen
eine Approximation sind.
> Dann würde ich einfach die jeweilige Vorgabe vom Benutzer auf jeden Fall> so speichern, wie ich sie kriege.
Hmmmm... das könnte klappen, die paar Bits RAM, um den Typ der Daten zu
identifizieren könnte ich noch rausknautschen ;)
Werd ich mal so in Angriff nehmen.
Ralf