Der HSV-Farbraum

    • Allgemein

    Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

      Der HSV-Farbraum

      Konvertierung HSV to RGB

      Wer sich mit dem HSV-Farbraum nicht auskennt, dem empfehle ich zunächst die Lektüre bei Wiki.

      Der RGB-Farbraum lässt sich eineindeutig durch einen Würfel darstellen. R, G und B bilden die 3 linear unabhängigen Achsen, jede mögliche Farbe lässt sich im Rahmen der Auflösung (üblicherweise von 0 bis 255 pro Kanal) einem Punkt in diesem Würfel zuordnen.

      Der HSV-Farbraum ist nicht eindeutig, denn für S=0 und/oder V=0 kann H jeden beliebigen Wert einnehmen, deshalb wird per Definition in diesem Fall H auf 0 gesetzt (Rot).
      Das Besondere am HSV-Farbraum ist der Unstand, dass die Farben auf dem Umfang eines Kreises angeordnet sind, wodurch sich z.B. eine Farb-Verschiebung durch die Addition eines Wertes auf den H-Wert erzielen lässt.
      Nehmen wir einen Vollkreis mit der Winkel-Koordinate H und der Radius-Koordinate S und stellen mit V = 1 vermöge der Operation { HSV to RGB } einen Farbkreis dar:

      Wie man sieht, stechen die Vielfachen von 60° heraus. Konvertiert man dieses Bild in ein monochromatisches Bild, wird dies noch deutlicher:

      Sehen wir uns die Verläufe der RGB-Kurven an (freundlicher Dank an Wiki, obiger Link),

      leuchtet das natürlich ein.
      Wahrscheinlich ist diese historische Variante der damals zur Verfügung stehenden Rechentechnik und der Kurzsichtigkeit irgend welcher Manager geschuldet.

      Vorschlag:

      Machen wir eine "glatte" Transformation und ersetzen die Trapezoiden durch Sinuiden.
      Die Rechenforschrift selbst ist so elementar und einfach, dass ich mich wundern muss, dass sie damals nicht publiziert und verwendet wurde.
      Die Kurvenform legen wir in einem statischen Feld ab, das vorab berechnet wird.
      Spoiler anzeigen

      C#-Quellcode

      1. private static double[] Cosinus;
      2. static HsvColor()
      3. {
      4. HsvColor.Cosinus = new double[361];
      5. double factor = 2.0 * Math.PI / 360.0;
      6. for (int i = 0; i <= 360; i++)
      7. {
      8. HsvColor.Cosinus[i] = (Math.Cos(i * factor) / 2.0 + 0.5) * 255.0;
      9. }
      10. }

      Die Transformation selbst sieht dann so aus:
      Spoiler anzeigen

      C#-Quellcode

      1. /// <summary>
      2. /// Convert HSV to RGB
      3. /// </summary>
      4. /// <param name="H">h part (0...360)</param>
      5. /// <param name="S">s part (0...1)</param>
      6. /// <param name="V">v part (0...1)</param>
      7. /// <returns>the corresponding Color</returns>
      8. public static Color ToColorNew(double h, double s, double v)
      9. {
      10. h = ((h % 360) + 360) % 360;
      11. int index = (int)Math.Round(h);
      12. double r = HsvColor.Cosinus[index];
      13. double g = HsvColor.Cosinus[(index + 240) % 360];
      14. double b = HsvColor.Cosinus[(index + 120) % 360];
      15. double dr = r + (255.0 - r) * (1 - s);
      16. double dg = g + (255.0 - g) * (1 - s);
      17. double db = b + (255.0 - b) * (1 - s);
      18. int rr = Convert.ToInt32(v * dr);
      19. int gg = Convert.ToInt32(v * dg);
      20. int bb = Convert.ToInt32(v * db);
      21. return Color.FromArgb(rr, gg, bb);
      22. }

      Vermöge dieser Transformation sieht der Farbkreis und sein Graubild so aus:

      Verwenden wir also von nun an die glatte Variante. ;)

      Fortsetzung folgt.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Die Welt ist nicht perfekt, auch mein erster Vorschlag zur "Glättung" der HSV-zu-RGB-Konvertierung nicht.
      Der @ErfinderDesRades hat mich per PM darauf hingewiesen und ist in eine offene Tür gefallen.

      Sehen wir uns den Verlauf der Sinus-förmigen Transformationskurven und ihren linearen Farbverlauf näher an
      (in Post #1 ist mir diesbezüglich ein Lapsus unterlaufen, dort sind die Kurven sinusförmig, es sind keine Sinuiden):


      Wie man sieht, sind die Mischfarben Gelb, Magenta, Cyan nicht mit voller Intensität { { 0, 255, 255 } usw. } darstellbar, das ist ein Mangel dieser Transformation.

      Deswegen machen wir nun die nächste Iterationsstufe.
      Aus dem sinus-förmigen Verlauf machen wir einen sinuiden Verlauf, einem halben Sinus mit konstanter Fortsetzung.
      Spoiler anzeigen

      C#-Quellcode

      1. static HsvColor()
      2. {
      3. HsvColor.Cosinus = new double[361];
      4. //double factor = 2.0 * Math.PI / 360.0;
      5. //for (int i = 0; i <= 360; i++)
      6. //{
      7. // HsvColor.Cosinus[i] = (Math.Cos(i * factor) / 2.0 + 0.5) * 255.0;
      8. //}
      9. double factor = 2.0 * Math.PI / 360.0 * 3;
      10. for (int i = 0; i < 60; i++) { HsvColor.Cosinus[i] = 255; }
      11. for (int i = 60; i < 120; i++) { HsvColor.Cosinus[i] = (-Math.Cos(i * factor) / 2.0 + 0.5) * 255.0; }
      12. for (int i = 120; i < 240; i++) { HsvColor.Cosinus[i] = 0; }
      13. for (int i = 240; i < 300; i++) { HsvColor.Cosinus[i] = (-Math.Cos(i * factor) / 2.0 + 0.5) * 255.0; }
      14. for (int i = 300; i <= 360; i++) { HsvColor.Cosinus[i] = 255; }
      15. }

      Der Farbkreis und dessen Mono-Darstellung sehen so aus:


      Die Homogenität ist nicht mehr ideal, wir befinden uns irgendwo zwischen beiden Darstellungen (der von Wiki und meiner aus Post #1).

      Sehen wir uns nun die Linear-Darstellung der Farbverläufe an:
      Trapez (Wiki)

      Sinuide
      Wir sehen, dass die Mischfarben bei der Sinuide den ihnen zustehenden Platz bekommen haben, deutlich besser als bei Wiki, auch wenn die Verteilung noch nicht ganz homogen ist.

      Ein Fazit dieser Untersuchungen zum HSV-Farbraum ist, dass sich jedermann seine eigene Transformation HSV to RGB generieren kann und dabei seine Kreativität und seine ästhetischen Vorstellungen umsetzen kann.
      Mit dem Wissen, dass die Transformation HSV to RGB über keine eineindeutige Rück-Transformation RGB to HSV verfügt, sollten wir Wiki nicht als "göttliche" Instanz oder Vorlage sehen, sondern als Anhaltspunkt und Aufforderung für eine eigene Kreativität.

      Ich rufe mal die (Hobby-) Programmierer auf, eine Transformation zu entwerfen, die bezüglich Vollständigkeit und Homogenität die nächste Iterationsstufe repräsentiert.
      Dazu ist lediglich das Cosinus-Array entsprechend zu belegen, der Rest passiert im Code.

      Fortsetzung folgt.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Die Homogenität ist nicht mehr ideal, ...
      Also ich finde den neuen Farbkreis durchaus ideal - inklusive, bzw. wegen der dargestellten Struktur der Helligkeitsverteilung.
      Man sieht deutlich die 6 Grund-Farben, und jede hat eine einigermassen breite Zone.
      Ich glaube auch, die Überlagerung aller 3 Sinuiden würde nun wieder einen klassischen Sinus erbringen, mit Maxima in den subtraktiven Grundfarben, und Minima in den additiven Grundfarben.
      (Grundfarben des subtraktives Farb-System: CMY (Cyan-Magenta-Yellow), additive Grundfarben: RGB (Red-Green-Blue)).

      Ich sehe da irgendwie einen Farbraum-Kegel vor mir - ähnlich dem im verlinkten Wiki-Artikel, aber der Deckel ist nicht platt, sondern das Weiss in der Deckel-Mitte ist ein höchster Punkt, und in 3 gewellten "Strahlen" fällt die Deckel-Form zum Rand hin ab.
      So ähnlich wie bei diese Riesen-Muscheln im Meer - die haben auch son gewellten Rand.
      Dein Farbkreis ist also die Draufsicht auf den Deckel dieses "Kegloiden" ;) .

      Dank dir habichmich nu bisserl mit Farben beschäftigt.
      Ich spekuliere grade, welche Farblehre wir wohl hätten, wenn die Menschen über 4-Farb-Sehen verfügten - wie's im Tierreich ja recht häufig anzutreffen ist.
      Der "Farbraum" als 3-D-Modell liesse sich ja garnet denken.

      Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

      @ErfinderDesRades Feine Sache, da hab ich auch schon drüber nachgedacht.
      Neben Rot Infrarot und / oder neben Blau Ultraviolett.
      Ein Problem dabei ist die menschliche Physiologie.
      Die Rot-Zapfen haben nämlich auch im Blauen eine gewisse Empfindlichkeit, so dass der Mensch in der Lage ist, Violett zu erkennen.
      In diesem Sinne ist auch die zirkuläre Darstellung der Hue-Komponente bei HSV gesichert.
      Wenn Du nun eine weitere Grundfarbe "implementieren" willst, müsstest Du auch sehen, dass das Wiedergabegerät (Nassfoto, LED-Bildschirme usw.) das können.
      Ansonsten müsstest Du die 4- (n-)Kanal Daten wieder zusammenschieben und auf RGB verteilen, damit wir sie sehen können.
      Dabei kommt dann so was raus wie eine Falschfarbendarstellung, Beispiel wäre eine Multispektralaufnahme des selben Motivs (=> Erdbeobachtung), das gibt es ja mit beliebig vielen Kanälen.
      Wenn man dort die richtigen Kanäle kombiniert, kann man den Reifezustand von Getreife und solch ermitteln.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!

      ErfinderDesRades schrieb:

      wenn die Menschen über 4-Farb-Sehen verfügten - Der "Farbraum" als 3-D-Modell liesse sich ja garnet denken.
      Was ich meine ist, dass man sich bei 3 Farben jede mögliche Farb-Mischung räumlich vorstellen kann: als Punkt im 3-dimensionalen Farbraum.
      Und der Farbkreis stellt alle möglichen Farb-Mischungen dar, unter Beteiligung mindestens einer Vollton-Komponente - in der Fläche.
      Im kegel-förmigen HSV-Farbraum wäre der Farbkreis quasi der "Deckel" des Kegels - nämlich die Punkte, wo's (bei gleichem Farbton und Sättigung) heller nimmer geht.

      Ascii-Art: Lage der additiven Grundfarben: rgb, der subtraktiven: cym, sowie Weiss im Farbkreis der 3-Farb-Seher

      Quellcode

      1. m b
      2. \ /
      3. r--w--c
      4. / \
      5. y g


      Kommt nun eine vierte Farbe hinzu, geht das nicht mehr auf.
      Also angenommen vier additive Farben: rot grün, blau, neu -> "rgbn"
      Dann ist nicht mehr cyan komplementär zu rot, sondern blau.
      Und grün ist nicht mehr komplementär zu magenta, sondern zu neu:

      Quellcode

      1. rn n nb
      2. \ | /
      3. r--?w?--b
      4. / | \
      5. y g c
      Wo in diesem FarbKreis ist nu der Farbort der VolltonFarbe nbg?
      Und wo ist Magenta, die Addition von rot und blau (rb)?
      (gelb (yellow: y) ist wie gehabt: zwischen rot und grün. Auch Cyan: zwischen grün und blau. Aber Magenta ist irgendwie woanders, weil rot und blau nicht mehr aneinander grenzen (können))

      Oder anders: Weiss ist ja die Addition aller additiven Grundfarben (im Vollton). Im 3-er Farbkreis ist das klar eindeutig addressiert, nämlich die Mitte.
      Bei vier Farben geht das nicht mehr.
      Die Mitte ist nämlich wie man sieht auf drei verschiedene Weisen addressierbar: rgbn (weiss), rb (ah - magenta!), gn (unsagbar).
      (Für einen 4-Farb-Seher entspricht rgbn unserem Weiss, aber rb oder gn entsprechen dem sicher nicht - sondern anderen Farben: rb ist ja Magenta, für gn haben wir kein Wort (macht nix, hat ja auch noch nie einer gesehen))
      Das könnte man nun lösen, indem man n aus der Ebene herausnimmt, und sich 3-dimensional vorstellt an einem Punkt über dem Farbdreieck rgb.
      Also rgbn wäre als Tetraeder vorstellbar.
      Tja Pech - im Farbraum ist die Höhe leider schon belegt: durch die Helligkeit

      Mit anderen Worten: Es fehlt eine Dimension. 4-Farb-Seher bräuchten einen 4-dimensionalen Farbraum, um ihre Farblehre überhaupt denken zu können.
      Was haben wir doch für ein Glück mitte menschlichen Physiologie aus: 3 Farbzapfen für 3 additive Grundfarben, was sich schön als 3-D-Farbraum abbilden lässt.
      Nicht 4 Farbzapfen, wie zB bei die armen Wellensittiche.
      Die Wellensittiche müssen in ihrer Evolution also zunächst die allgemeine Relativitätstheorie entwickeln, und die 4-dimensionale Raumzeit verinnerlichen - ehe sie zu einer für sie physiologisch korrekten Farblehre kommen können, odr?

      ;)

      Puh - und erst deren Regenbogen!
      Unser Regenbogen (Frequenz-Farb-Kontinuum) ist ja farblich vollständig: magenta (alias "purpur"), rot, gelb, grün, cyan, blau, magenta: m r y g c b m
      Dem Wellensittich-Regenbogen hingegen fehlt die Hälfte ihrer Farben; ihr Regenbogen besteht aus: bn n nr r y g c b bn n nb
      (bn ist eiglich "infra-n" am langwelligen Ende, während nb unser ultraviolett ist)
      Fehlt also: rb (Magenta) sowie drei (unsagbare) n-Additive: yn, gn, cn.
      Und es fehlen die vier (noch unsagbareren) Tripel-Additive: rgb (ist bei denen nicht Weiss!), rgn, rbn, gbn

      Dieser Beitrag wurde bereits 11 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Ich denke da wohl ein wenig anders.
      Stell Dir einen Farblaser vor, einen mit durchstimmbarer Wellenlänge, von der aüßeren roten bis zur äußeren blauen Wellenlänge.
      Wichtig hierbei ist doch, dass das Auge oder der Farbsensor jede einzelne Wellenlänge (in einer sinnvollen Toleranz bzw. Schrittweite) von der benachbarten Wellenlänge unterscheiden kann.
      Wenn Du bei sagen wir 1000 diskreten Wellenlängen einen 1000-Kanal-Sensor bzw. ein 1000-zäpfiges Auge hast, ist es nicht erforderlich, einzelne Kanäle durch Mischfarben zu beschreiben, denn sie wären dann nicht gemischt.
      Bei 4 Kanälen musst Du nur immer zwei Wellenlängen-benachbarte Kanäle gleichzeitig ansprechen, um entsprechend der Intensität die eine Farbe aufzulösen.
      Wenn Du durch einem Zug mit vielen Waggons läufst, sagst Du auch, dass Du in Waggon 3 oder 4 oder gerade beim Übergang von 3 zu 4 bist, Du kämst aber nicht auf die Idee, gleichzeitig in Waggon 3 und Waggon 5 sein zu wollen.
      In Deiner Denkweise:
      Da fehlt nicht eine Dimension, sondern es ist ein neues Modell erforderlich.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!

      Die gekoppelte Transformation RGB zu HSV und zurück zu RGB

      Wir transformieren ein Bild aus dem RGB-Raum in den HSV-Raum und wieder zurück.
      Wir berechnen aus dem Array { Original - ToRGB(ToHSV(Original) }
      Maximum, Minimum, Mittelwert und Root-Mean-Square der einzelnen Kanäle R, G, B.
      Die RGB-Werte behandeln wir als vorzeichenbehaftete Werte, um durch eine mögliche Begrenzung { >=0 } keine Effekte zu haben.
      Das Framework bietet uns dafür folgende Methoden (Bill wird wissen, warum im Framework die Transformation nur in eine Richtung angeboten wird):

      Quellcode

      1. H = color.GetHue()
      2. S = color.GetSaturation()
      3. V = color.GetBrightness()
      Alternativ verwenden wir die Transformation RGB zu HSV nach Wiki.
      Die Rücktransformation HSV zu RGB führen wir mit der Methode nach Wiki durch, es ergeben sich also 2 Kombinationen.
      Als Testbild nehmen wir den sinuiden Farbkreis von Post #2.

      Quellcode

      1. Framework & Wiki
      2. Red Min = 0,0 Max = 253,0 Mean = 59,2750 RMS = 47,3946
      3. Green Min = 0,0 Max = 254,0 Mean = 59,2681 RMS = 47,4077
      4. Blue Min = 0,0 Max = 254,0 Mean = 59,2777 RMS = 47,4075
      5. Wiki & Wiki:
      6. Red Min = 0,0 Max = 0,0 Mean = 0,0000 RMS = 0,0000
      7. Green Min = 0,0 Max = 0,0 Mean = 0,0000 RMS = 0,0000
      8. Blue Min = 0,0 Max = 0,0 Mean = 0,0000 RMS = 0,0000
      Die Kombination Wiki & Wiki ist hier eindeutig.
      Ob das allgemeingültig ist kann ich nicht sagen, jedenfalls habe ich das mit einer Reihe von Bildern probiert und stets kam 0 heraus.
      Vielleicht gibt es Mathematiker hier im Forum, die das ganze mal theoretisch durchleuchten.

      Wird die Transformation des Frameworks verwendet, erhalten wir Minima von 0 und Maxima wenig kleiner als 255.
      Grund genug, uns das rücktransformierte Bild als RGB-Bild anzusehen, im Vergleich dazu das Ausgangsbild:
      =>
      Ich möchte meinen: Künstlerisch wertvoll.

      Resultat schrieb:

      Schmeißt die RGB-zu-HSV-Transformation des Frameworks in die Tonne,
      Nehmen wir also die Lösung des Frameworks aus dem Portfolio heraus :!:
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Hallo @RodFromGermany

      RodFromGermany schrieb:

      V = color.GetBrightness()


      Ich vermute das die GetBrightness() nicht den Hellikeitswert liefert denn man erwarten, sondern wie auf Wiki beschrieben sich um einen Wert der Dunkelstufe handelt.

      Ich hab mir jetzt für die Umrechnungen eine eigene Klasse geschrieben. Eventuell kannste sie ja brauchen.

      Freundliche Grüsse

      exc-jdbi

      Spoiler anzeigen

      VB.NET-Quellcode

      1. Dim r, g, b As Int32
      2. Dim rgb As (Int32, Int32, Int32)
      3. Dim hsv, hsl As (Single, Single, Single)
      4. Dim crh = New ColorRgbHsX
      5. r = Rand.Next(0, 255)
      6. g = Rand.Next(0, 255)
      7. b = Rand.Next(0, 255)
      8. hsv = crh.ToHSV(r, g, b)
      9. With hsv
      10. rgb = crh.FromHSV(.Item1, .Item2, .Item3)
      11. End With
      12. Debug.Assert(r = rgb.Item1)
      13. Debug.Assert(g = rgb.Item2)
      14. Debug.Assert(b = rgb.Item3)
      15. hsl = crh.ToHSL(r, g, b)
      16. With hsl
      17. rgb = crh.FromHSL(.Item1, .Item2, .Item3)
      18. End With
      19. Debug.Assert(r = rgb.Item1)
      20. Debug.Assert(g = rgb.Item2)
      21. Debug.Assert(b = rgb.Item3)

      VB.NET-Quellcode

      1. Public Class ColorRgbHsX
      2. Public Function ToHSV(r As Int32, g As Int32, b As Int32) As (Single, Single, Single)
      3. Dim _r, _g, _b As Single
      4. _r = r / 255.0F : _g = g / 255.0F : _b = b / 255.0F
      5. Dim _rgb = {_r, _g, _b}
      6. Dim max = _rgb.Max
      7. Dim min = _rgb.Min
      8. Dim d = max - min
      9. Dim h, s, v As Single
      10. h = Me.ToHue(_r, _g, _b, max, d)
      11. s = If(max = 0, 0, d / max)
      12. v = max
      13. Return (h, s, v)
      14. End Function
      15. Public Function ToHSL(r As Int32, g As Int32, b As Int32) As (Single, Single, Single)
      16. Dim _r, _g, _b As Single
      17. _r = r / 255.0F : _g = g / 255.0F : _b = b / 255.0F
      18. Dim _rgb = {_r, _g, _b}
      19. Dim max = _rgb.Max
      20. Dim min = _rgb.Min
      21. Dim d = max - min
      22. Dim av = (max + min) / 2.0F
      23. Dim h, s, l As Single
      24. h = Me.ToHue(_r, _g, _b, max, d)
      25. l = av
      26. s = If(d = 0, 0, d / (1 - Math.Abs(2 * l - 1)))
      27. Return (h, s, l)
      28. End Function
      29. Public Function FromHSV(h As Single, s As Single, v As Single) As (Int32, Int32, Int32)
      30. 'HSV To RGB
      31. Dim c = s * v
      32. Dim x = c * (1 - Math.Abs(((h / 60) Mod 2) - 1))
      33. Dim m = v - c
      34. Dim _rgb = Me.ToPreRgb(h, c, x, m)
      35. Return (Convert.ToInt32(255 * (_rgb.Item1 + m)),
      36. Convert.ToInt32(255 * (_rgb.Item2 + m)),
      37. Convert.ToInt32(255 * (_rgb.Item3 + m)))
      38. End Function
      39. Public Function FromHSL(h As Single, s As Single, l As Single) As (Int32, Int32, Int32)
      40. 'HSL To RGB
      41. Dim c = s * (1 - Math.Abs(2 * l - 1))
      42. Dim x = c * (1 - Math.Abs(((h / 60) Mod 2) - 1))
      43. Dim m = l - c / 2
      44. Dim _rgb = Me.ToPreRgb(h, c, x, m)
      45. Return (Convert.ToInt32(255 * (_rgb.Item1 + m)),
      46. Convert.ToInt32(255 * (_rgb.Item2 + m)),
      47. Convert.ToInt32(255 * (_rgb.Item3 + m)))
      48. End Function
      49. Private Function ToHue(r As Single, g As Single, b As Single, max As Single, delta As Single) As Single
      50. If delta = 0F Then Return 0F
      51. Dim result As Single
      52. Select Case True
      53. Case max = r : result = Me.FModulo((g - b) / delta, 6.0F)
      54. Case max = g : result = ((b - r) / delta) + 2
      55. Case max = b : result = ((r - g) / delta) + 4
      56. End Select
      57. Return result * 60
      58. End Function
      59. Private Function ToPreRgb(h As Single, c As Single, x As Single, m As Single) As (Single, Single, Single)
      60. Dim r, g, b As Single
      61. Select Case h
      62. Case < 60 : r = c : g = x : b = 0
      63. Case < 120 : r = x : g = c : b = 0
      64. Case < 180 : r = 0 : g = c : b = x
      65. Case < 240 : r = 0 : g = x : b = c
      66. Case < 300 : r = x : g = 0 : b = c
      67. Case Else : r = c : g = 0 : b = x
      68. End Select
      69. Return (r, g, b)
      70. End Function
      71. Private Function FModulo(numeric As Single, m As Single) As Single
      72. numeric = numeric Mod m
      73. If numeric < 0 Then
      74. numeric += m
      75. End If
      76. Return numeric
      77. End Function
      78. End Class

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

      @exc-jdbi Danke für Deine Bemühungen, erläutere bitte den Unterschied zwischen Hellikeitswert und Dunkelstufe.
      Metadaten

      C#-Quellcode

      1. // Zusammenfassung:
      2. // Ruft den HSB-Helligkeitswert (Hue, Saturation, Brightness = Farbton, Sättigung,
      3. // Helligkeit) für diese System.Drawing.Color-Struktur ab.
      4. //
      5. // Rückgabewerte:
      6. // Die Helligkeit dieser System.Drawing.Color.Due Helligkeit liegt zwischen
      7. // 0.0 und 1.0, wobei 0.0 Schwarz und 1.0 Weiß darstellt.
      8. public float GetBrightness();
      ist doch eine klare Beschreibung.

      Wiki schrieb:

      Hellwert (auch Dunkelstufe genannt) (value): (0% = keine Helligkeit, 100% = volle Helligkeit), entspricht einem Intervall von Null bis Eins
      =======
      Und:
      Deine Function FModulo() ist falsch für negative Wertre für numeric.
      Probier mal dies:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Function FModulo(numeric As Single, m As Single) As Single
      2. 'If numeric < 0 Then Return m - numeric
      3. numeric = numeric Mod m
      4. If numeric < 0 Then
      5. numeric += m
      6. End If
      7. Return numeric Mod m
      8. End Function
      mit

      VB.NET-Quellcode

      1. Dim colTrans = New ColorRgbHsX()
      2. For i = -10 To 10
      3. Me.ListBox1.Items.Add(String.Format("{0} - {1}", i, colTrans.FModulo(i, 6)))
      4. Next

      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Danke für den Hinweis. Die FModulo habe ich angepasst. Das ist tatsächlich falsch. Ich bin davon ausgegangen, dass 'numeric' nie den Wert -1 erreichen wird. Doch mit RGB(192, 184, 192) entsteht genau die Situation, und der Hue-Wert wird natürlich falsch ausgegeben.

      Zu Hellikeitswert und Dunkelstufe:
      Ich habe wirklich nur eine Vermutung, und zwar das GetBrightness eben nicht den eigentlichen Brightness-Wert ausgibt, sondern den Lightness-Wert von HSL. Brightness und Lightness dürfen aber nie gleichgestellt werden.
      Wenn man die Prozente der Transformationstabelle genau betrachtet entspricht V immer dem grössten Wert der RGB-%-Komponenten, was bei L nicht der Fall ist. GetBrightness gibt aber anscheinend nicht den grössten Wert der RGB-%-Komponenten aus, also darf es auch nicht V zugewiesen werden.

      Gemäss WIKI
      Der HSL-Farbraum (auch als HLS bezeichnet) hat die Parameter Farbwinkel H, Farbsättigung S und Farbhelligkeit L. Im Gegensatz zum HSV-Farbraum wird er jedoch auf den zwischen Weiß und Schwarz liegenden Graupunkt als neutrales Grau bezogen.

      Gemäss WIKI
      V >> die Helligkeit ist ein Parameter für den Gesamtenergieinhalt bzw. für die maximale Amplitude des Lichts; die Dunkelstufe ergänzt diesen Wert im Gegensätzlichen. Nachteilig bei der Dunkelstufe ist, dass Weiß und ein beliebiger Farbton die gleiche Sättigung haben können.

      Wozu ist der HSV-Farbraum zu verwenden?

      Ihr habt alle schon mal was von Blue-Screen- oder GreenScreen-Technik beim Film gehört.
      Da wird eine Szene vor einem grünen oder blauen Vorhang gedreht, und dann, wie von Geisterhand, erscheint das ganze vor dem finalen Hintergrund. Rot geht da nicht, weil z.B. in der menschlichen Haut zu viel Rot vorkommt. Um den grünen oder blauen Hintergrund ersetzen zu können, werden die Picel in den HSV-Farbraum transformiert, und dann wird alles, was sich im Winkelbereich Blau +-3 Grad (keine Ahnung, wieviel genau) befindet, ersetzt.
      Das geniale an dieser Technik besteht darin, dass bei einem RGB-Verfahren 3 Dimensionen betrachtet werden müssten.
      Im HSV-Raum ist das nur eine einzige, der HUE-Anteil. Durch Weglassen der anderen Dimensionen (S und V) wird das ganze recht robust, und an den Hintergrund selbst werden keine ultra-hohen Anforderungen gestellt.
      Fehler können da natürlich auch passieren, Ihr habt sicher schon mal in einem Film gesehen, dass da irgendwo im Bild der Hintergrund durchflimmert.

      Ein anderes Beispiel ist die Qualitätskontrolle, wo es auf Farben und Fehlfarben ankommt.
      Da werden die guten Farben angelernt und davon ein Hue-Histogramm generiert.
      Von einem Bild von einem fehlerhaften Objekt wird ebenfalls ein Hue-Histogramm generiert.
      Durch Vergleich beider Histogramme mit den richtigen Toleranzen lässt sich schnell ein farb-fehlerhaftes Objekt herausfinden.

      Eine andere Anwendung:
      Nehmen wir als Vorlage das Bild einer Mohnblüte mit Holzbiene.
      Dieses Bild drehen wir im Hue-Kanal in 12 Mal 30°-Schritten, also ein Vollkreis.
      Das Resultat packen wir in eine GIF-Datei.
      Viel Vergnügen.
      =>
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!