Frage

las ich den Artikel Algorithmus zwischen RGB Switch und HSB Farbwerte

Type RGBColor
     Red As Byte
     Green As Byte
     Blue As Byte
End Type

Type HSBColor
     Hue As Double
     Saturation As Double
     Brightness As Double
End Type

Function RGBToHSB(rgb As RGBColor) As HSBColor
     Dim minRGB, maxRGB, Delta As Double
     Dim h, s, b As Double
     h = 0
     minRGB = Min(Min(rgb.Red, rgb.Green), rgb.Blue)
     maxRGB = Max(Max(rgb.Red, rgb.Green), rgb.Blue)
     Delta = (maxRGB - minRGB)
     b = maxRGB
     If (maxRGB <> 0) Then
          s = 255 * Delta / maxRGB
     Else
          s = 0
     End If
     If (s <> 0) Then
          If rgb.Red = maxRGB Then
               h = (CDbl(rgb.Green) - CDbl(rgb.Blue)) / Delta
          Else
               If rgb.Green = maxRGB Then
                    h = 2 + (CDbl(rgb.Blue) - CDbl(rgb.Red)) / Delta
               Else
                    If rgb.Blue = maxRGB Then
                         h = 4 + (CDbl(rgb.Red) - CDbl(rgb.Green)) / Delta
                    End If
               End If
          End If
     Else
          h = -1
     End If
     h = h * 60
     If h < 0 Then h = h + 360
     RGBToHSB.Hue = h
     RGBToHSB.Saturation = s * 100 / 255
     RGBToHSB.Brightness = b * 100 / 255
End Function

Function HSBToRGB(hsb As HSBColor) As RGBColor
     Dim maxRGB, Delta As Double
     Dim h, s, b As Double
     h = hsb.Hue / 60
     s = hsb.Saturation * 255 / 100
     b = hsb.Brightness * 255 / 100
     maxRGB = b
     If s = 0 Then
          HSBToRGB.Red = 0
          HSBToRGB.Green = 0
          HSBToRGB.Blue = 0
     Else
          Delta = s * maxRGB / 255
          If h > 3 Then
               HSBToRGB.Blue = CByte(Round(maxRGB))
               If h > 4 Then
                    HSBToRGB.Green = CByte(Round(maxRGB - Delta))
                    HSBToRGB.Red = CByte(Round((h - 4) * Delta)) + HSBToRGB.Green
               Else
                    HSBToRGB.Red = CByte(Round(maxRGB - Delta))
                    HSBToRGB.Green = CByte(HSBToRGB.Red - Round((h - 4) * Delta))
               End If
          Else
               If h > 1 Then
                    HSBToRGB.Green = CByte(Round(maxRGB))
                    If h > 2 Then
                         HSBToRGB.Red = CByte(Round(maxRGB - Delta))
                         HSBToRGB.Blue = CByte(Round((h - 2) * Delta)) + HSBToRGB.Red
                    Else
                         HSBToRGB.Blue = CByte(Round(maxRGB - Delta))
                         HSBToRGB.Red = CByte(HSBToRGB.Blue - Round((h - 2) * Delta))
                    End If
               Else
                    If h > -1 Then
                         HSBToRGB.Red = CByte(Round(maxRGB))
                         If h > 0 Then
                              HSBToRGB.Blue = CByte(Round(maxRGB - Delta))
                              HSBToRGB.Green = CByte(Round(h * Delta)) + HSBToRGB.Blue
                         Else
                              HSBToRGB.Green = CByte(Round(maxRGB - Delta))
                              HSBToRGB.Blue = CByte(HSBToRGB.Green - Round(h * Delta))
                         End If
                    End If
               End If
          End If
     End If
End Function

Dann war da noch jemand, die Beiträge geschrieben, dass es ein Fehler war, aber viel ging nicht näher

  

Aber ich denke, es muss verwalten, wenn h mehr als 5 ist, zum Beispiel für die Farbe R: 130 G: 65 B: 111

If h > 5 Then
    HSBToRGB.Red = CByte(Round(maxRGB))
If h > 6 Then
    HSBToRGB.Blue= CByte(Round(maxRGB - Delta))
    HSBToRGB.Green= CByte(Round((h - 6) * Delta)) HSBToRGB.Blue
Else
    HSBToRGB.Green= CByte(Round(maxRGB - Delta))
    HSBToRGB.Blue = CByte(HSBToRGB.Green- Round((h - 6) * Delta))
End If

Muss ich in diesem Stück Code hinzufügen? Und ich nehme an es in HSB zu RGB (in meiner C # conversion) gehen sollte

...
if (s != 0) {
    delta = s * maxRGB / 255;
    if (h > 5)
        rgb.Red = Convert.ToByte(Math.Round(maxRGB));
    if (h > 6)
    {
        rgb.Green = Convert.ToByte(Math.Round(maxRGB - delta));
        rgb.Blue = Convert.ToByte(rgb.Green - Math.Round((h - 6) * delta));
    }
    if (h > 3)
    {
        ...

auch, sollte es wie oben sein, oder

if (h > 6) { } 
else if (h > 3)  { }
War es hilfreich?

Lösung

Mit den Methoden in .NET die Color-Objekt gebaut ist ein Rohrkrepierer, weil, wie einige der Antworten weisen darauf hin, sie umgekehrt nicht unterstützen (Umwandlung eine HSB Farbe RGB). Zusätzlich Color.GetBrightness tatsächlich kehrt Leichtigkeit , anstatt Helligkeit / Wert. Es gibt eine Menge Verwirrung über die Unterschiede zwischen dem HSB / HSV und HSL-Farbräume wegen ihrer Ähnlichkeiten ( Wikipedia ). Ich sehe eine Menge Farbauswahl, die den falschen Algorithmus am Ende und / oder Modell.

Die Original-Code sieht für mich wie es fehlt ein paar möglichen Szenarien, wenn sie den Wert für den Farbton berechnet, eine RGB-Farbe. Es ist ein wenig schwierig für mich, die Ergänzungen zu folgen, dass Sie den Code sind betrachtend, aber das erste, was ich herausspringt (und dass Sie scheinen nicht zu deuten darauf hin, Korrektur) ist, dass, wenn die Sättigung = 0, Sie Set Farbton auf -1. Wenn Sie später mehrfach die Farbe von 60, Sie mit -60 am Ende, dann fügen Sie, dass bis 360 (If h < 0 Then h = h + 360), ein Ergebnis von 300 produziert, die nicht korrekt ist.

Ich verwende den folgenden Code (in VB.NET) zwischen RGB und HSB zu konvertieren (die ich HSV nennen). Die Ergebnisse wurden sehr ausgiebig getestet, und die Ergebnisse sind mit denen praktisch identisch mit dem Photoshop-Farbauswahl gegeben (abgesehen von der Entschädigung tut es für Farbprofile). Der wesentliche Unterschied zwischen dem von ihm entsandten Code und mir (abgesehen von dem wichtigen Abschnitt, der den Farbton berechnet) ist, dass ich es vorziehen, die RGB-Werte normalisieren zwischen 0 und 1 sein, um die Berechnungen zu tun, anstatt mit den ursprünglichen Werten zwischen 0 Arbeits und 255 einige der Ineffizienzen und mehrere Konvertierungen im ursprünglichen Code. Dadurch entfällt dass Sie auf dem Laufenden, wie gut.

Public Function RGBtoHSV(ByVal R As Integer, ByVal G As Integer, ByVal B As Integer) As HSV
     ''# Normalize the RGB values by scaling them to be between 0 and 1
     Dim red As Decimal = R / 255D
     Dim green As Decimal = G / 255D
     Dim blue As Decimal = B / 255D

     Dim minValue As Decimal = Math.Min(red, Math.Min(green, blue))
     Dim maxValue As Decimal = Math.Max(red, Math.Max(green, blue))
     Dim delta As Decimal = maxValue - minValue

     Dim h As Decimal
     Dim s As Decimal
     Dim v As Decimal = maxValue

     ''# Calculate the hue (in degrees of a circle, between 0 and 360)
     Select Case maxValue
        Case red
           If green >= blue Then
               If delta = 0 Then
                  h = 0
               Else
                  h = 60 * (green - blue) / delta
               End If
           ElseIf green < blue Then
               h = 60 * (green - blue) / delta + 360
           End If
        Case green
           h = 60 * (blue - red) / delta + 120
        Case blue
           h = 60 * (red - green) / delta + 240
     End Select

     ''# Calculate the saturation (between 0 and 1)
     If maxValue = 0 Then
        s = 0
     Else
        s = 1D - (minValue / maxValue)
     End If

     ''# Scale the saturation and value to a percentage between 0 and 100
     s *= 100
     v *= 100

  ''# Return a color in the new color space
  Return New HSV(CInt(Math.Round(h, MidpointRounding.AwayFromZero)), _
                 CInt(Math.Round(s, MidpointRounding.AwayFromZero)), _
                 CInt(Math.Round(v, MidpointRounding.AwayFromZero)))
End Function

Sie haben den Code nicht schreiben Sie von einer HSB zu konvertieren verwenden (was ich HSV nennen) Farbe RGB, aber hier ist das, was ich benutze, wieder mit Zwischenwerten arbeiten, die zwischen 0 und 1:

Public Function HSVtoRGB(ByVal H As Integer, ByVal S As Integer, ByVal V As Integer) As RGB
     ''# Scale the Saturation and Value components to be between 0 and 1
     Dim hue As Decimal = H
     Dim sat As Decimal = S / 100D
     Dim val As Decimal = V / 100D

     Dim r As Decimal
     Dim g As Decimal
     Dim b As Decimal

     If sat = 0 Then
       ''# If the saturation is 0, then all colors are the same.
       ''# (This is some flavor of gray.)
        r = val
        g = val
        b = val
     Else
        ''# Calculate the appropriate sector of a 6-part color wheel
        Dim sectorPos As Decimal = hue / 60D
        Dim sectorNumber As Integer = CInt(Math.Floor(sectorPos))

        ''# Get the fractional part of the sector
        ''# (that is, how many degrees into the sector you are)
        Dim fractionalSector As Decimal = sectorPos - sectorNumber

        ''# Calculate values for the three axes of the color
        Dim p As Decimal = val * (1 - sat)
        Dim q As Decimal = val * (1 - (sat * fractionalSector))
        Dim t As Decimal = val * (1 - (sat * (1 - fractionalSector)))

        ''# Assign the fractional colors to red, green, and blue
        ''# components based on the sector the angle is in
        Select Case sectorNumber
           Case 0, 6
              r = val
              g = t
              b = p
           Case 1
              r = q
              g = val
              b = p
           Case 2
              r = p
              g = val
              b = t
           Case 3
              r = p
              g = q
              b = val
           Case 4
              r = t
              g = p
              b = val
           Case 5
              r = val
              g = p
              b = q
        End Select
     End If

     ''# Scale the red, green, and blue values to be between 0 and 255
     r *= 255
     g *= 255
     b *= 255

     ''# Return a color in the new color space
     Return New RGB(CInt(Math.Round(r, MidpointRounding.AwayFromZero)), _
                    CInt(Math.Round(g, MidpointRounding.AwayFromZero)), _
                    CInt(Math.Round(b, MidpointRounding.AwayFromZero)))
End Function

EDIT: Dieser Code sieht sehr ähnlich wie in C von Richard J. Ross III zur Verfügung gestellt. Ich suchte so viele verschiedene Algorithmen nach unten, wie ich online finden konnte, eine Menge Code neu geschrieben, das Beste aus jedem von ihnen zu leihen, und führte umfangreiche Tests, um die Genauigkeit der Ergebnisse zu überprüfen. Ich vernachlässigt zu beachten, die geliehenen ich Code aus, da dies nur für eine private Bibliothek war. Vielleicht wird die VB-Version jemand helfen, der nicht will eine Umwandlung von C zu tun: -)

Andere Tipps

Hier ist meine Version, wie das zu tun (in C, sorry, aber sollte nicht schwer zu konvertieren, sondern nur die des int * ersetzen und double * die mit out oder ref Ints, und verwenden Sie Zeiger Syntax nicht)

void colorlib_hsbtorgb(double hue, double saturation, double brightness, int *red, int *green, int *blue)
{   
    if (saturation == 0)
    {
        *red = *green = *blue = brightness;
    }
    else
    {
        // the color wheel consists of 6 sectors. Figure out which sector you're in.
        double sectorPos = hue / 60.0;
        int sectorNumber = (int)(floor(sectorPos));
        // get the fractional part of the sector
        double fractionalSector = sectorPos - sectorNumber;

        // calculate values for the three axes of the color. 
        double p = brightness * (1.0 - saturation);
        double q = brightness * (1.0 - (saturation * fractionalSector));
        double t = brightness * (1.0 - (saturation * (1 - fractionalSector)));

        // assign the fractional colors to r, g, and b based on the sector the angle is in.
        switch (sectorNumber)
        {
            case 0:
                *red = brightness;
                *green = t;
                *blue = p;
                break;
            case 1:
                *red = q;
                *green = brightness;
                *blue = p;
                break;
            case 2:
                *red = p;
                *green = brightness;
                *blue = t;
                break;
            case 3:
                *red = p;
                *green = q;
                *blue = brightness;
                break;
            case 4:
                *red = t;
                *green = p;
                *blue = brightness;
                break;
            case 5:
                *red = brightness;
                *green = p;
                *blue = q;
                break;
        }
    }
}

RGB zu HSB:

void colorlib_rgbtohsb(int red, int green, int blue, double *hue, double *saturation, double *brightness)
{
    double dRed = red / 255;
    double dGreen = green / 255;
    double dBlue = blue / 255;

    double max = fmax(dRed, fmax(dGreen, dBlue));
    double min = fmin(dRed, fmin(dGreen, dBlue));

    double h = 0;
    if (max == dRed && dGreen >= dBlue)
    {
        h = 60 * (dGreen - dBlue) / (max - min);
    }
    else if (max == dRed && dGreen < dBlue)
    {
        h = 60 * (dGreen - dBlue) / (max - min) + 360;
    }
    else if (max == dGreen)
    {
        h = 60 * (dBlue - dRed) / (max - min) + 120;
    }
    else if (max == dBlue)
    {
        h = 60 * (dRed - dGreen) / (max - min) + 240;
    }

    double s = (max == 0) ? 0.0 : (1.0 - (min / max));

    *hue = h;
    *saturation = s;
    *brightness = max;
}

Wenn ich meinen Code in C # finden, werde ich diese Antwort bearbeiten ....

Was über die Verwendung von Farbe GetBrightness, GetHue und GetSaturation Methoden?

Wenn Sie .net verwenden, warum das Rad neu erfinden?

Dim c = Color.FromArgb(myRed, myGreen, myBlue)
Dim h = c.GetHue()
Dim s = c.GetSaturation()
Dim b = c.GetBrightness()

Die Umwandlung von RGB zu HSB ziemlich einfach sein sollte, die Color Struktur mit:

Function RGBToHSB(rgb As RGBColor) As HSBColor
  Dim c As Color = Color.FromArgb(rgb.Red, rgb.Green, rgb.Blue)
  RGBToHSB.Hue = c.GetHue()
  RGBToHSB.Saturation = c.GetSaturation()
  RGBToHSB.Brightness = c.GetBrightness()
End Function

Es ist nicht das Gegenteil unterstützen, though.

Lösung

Sie können die Helligkeitskomponente berechnen ganz einfach, da es das Maximum von R, G ist, und B (Referenz: Formel für RGB zu HSV vom Rochester Institute of Technology ). Sie können es skalieren, wie Sie wollen, indem von 255 multipliziert mit der Skala geteilt wird. Dies ist das gleiche wie in Ihrem vorhandenen Code getan:

maxRGB = Max(Max(rgb.Red, rgb.Green), rgb.Blue)
b = maxRGB    
...    
RGBToHSB.Brightness = b * 100 / 255

So, am Ende können Sie die integrierte .NET-Funktionen verwenden und einfach Ihre Helligkeit berechnen. Vollständiger Code wäre (ohne Ihre Typen):

Function RGBToHSB(rgb As RGBColor) As HSBColor
  Dim maxRGB As Double
  maxRGB = Max(Max(rgb.Red, rgb.Green), rgb.Blue)

  Dim c As Color = Color.FromArgb(rgb.Red, rgb.Green, rgb.Blue)
  RGBToHSB.Hue = c.GetHue()
  RGBToHSB.Saturation = c.GetSaturation() * 100
  RGBToHSB.Brightness = maxRGB * 100 / 255
End Function

Bit A über HSB (gleich wie HSV)

Darel Rex Finley :

  

in dem HSV-System (auch genannt HSB), die Helligkeit einer Farbe ist die V-Komponente. Diese Komponente ist einfach definiert als der Maximalwert von einem der drei RGB-Komponenten der Farbe -. Die beiden anderen RGB-Komponenten werden ignoriert, wenn V Bestimmung

Nach dem Microsoft Dokumentation Color.GetBrightness:

  

Ruft die Farbton-Sättigung-Helligkeit ( HSB ) Helligkeitswert für diese Color-Struktur.

Ich habe einige Referenzen sagen die MSDN verwendet HSB gefunden, wenn es bedeutet, HSL wie dieses von MSDN Blogs (siehe Kommentare). Ein schneller Test beweist dies um wahr zu sein (in C #):

// Define a color which gives different HSL and HSB value
Color c = Color.FromArgb(255, 0, 0);
// Get the brightness, scale it from 0.0 - 1.0 up to 0 - 255
int bright = (int)(c.GetBrightness() * 255.00);
// Output it
Console.WriteLine(bright.ToString());

Diese ergibt einen Wert von 127, die eindeutig HSL ist. Wenn es HSB war sollte der Wert der max von R G und B (d 255).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top