Domanda

ho letto l'articolo Algoritmo per passare tra RGB e HSB colori valori

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

Poi c'è stato qualcuno che ha postato che c'è stato un errore, ma non ha elaborato molto

  

Ma penso necessità di gestire quando h è superiore a 5, ad esempio per il colore 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

Devo aggiungere in quel pezzo di codice? E presumo che dovrebbe andare in HSB a RGB (nel mio C # di conversione)

...
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)
    {
        ...

Inoltre, dovrebbe essere come sopra, o

if (h > 6) { } 
else if (h > 3)  { }
È stato utile?

Soluzione

Utilizzando i metodi integrati in oggetto Color di .NET è un non-starter perché, come molte delle risposte sottolineano, che non supportano il contrario (la conversione di un colore HSB per RGB). Inoltre, Color.GetBrightness restituisce effettivamente leggerezza , anziché luminosità / valore. C'è un sacco di confusione sulle differenze tra il HSB / HSV e spazi colore HSL a causa delle loro somiglianze ( Wikipedia ). Vedo un sacco di raccoglitrici di colore che finiscono con l'algoritmo e / o modello sbagliato.

Gli sguardi codice originale a me come manca alcuni scenari possibili quando si calcola il valore per la tonalità, dato un colore RGB. E 'un po' difficile per me seguire le aggiunte che si sta contemplando al codice, ma la prima cosa che salta fuori di me (e che non sembrano suggerire la correzione) è che quando la saturazione = 0, si imposta tonalità a -1. Quando successivamente moltiplicare la tonalità 60, si finisce con -60, quindi si aggiunge che a 360 (If h < 0 Then h = h + 360), producendo un risultato di 300, che non è corretto.

Io uso il seguente codice (in VB.NET) per la conversione tra RGB e HSB (che io chiamo HSV). I risultati sono stati testati molto ampiamente, ed i risultati sono praticamente identici a quelli trovati selettore di colori di Photoshop (a parte la compensazione avviene per profili colore). La principale differenza tra il codice distaccato e miniera (a parte la porzione importante che calcola la tonalità) è che preferisco normalizzando i valori RGB per essere tra 0 e 1 per eseguire i calcoli, piuttosto che lavorare con i valori originali tra 0 e 255 . Questo elimina alcune delle inefficienze e le conversioni multiple nel codice originale che hai postato, pure.

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

Non hai inviare il codice da utilizzare per convertire da un HSB (che io chiamo HSV) di colore RGB, ma ecco quello che io uso, ancora una volta a lavorare con valori intermedi che sono compresi tra 0 e 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

Modifica Questo codice è molto simile a quella fornita in C da Richard J. Ross III. Ho cacciato giù come molti algoritmi diversi, come ho potuto trovare on-line, ha riscritto un sacco di codice prendere in prestito il meglio da ognuno di loro, e ha fatto numerosi test per verificare l'accuratezza dei risultati. Ho trascurato di notare che ho preso in prestito codice, in quanto questo era solo per una biblioteca privata. Forse la versione VB aiuterà qualcuno che non vuole fare una conversione da C.: -)

Altri suggerimenti

Ecco la mia versione su come farlo (in C, mi dispiace, ma non dovrebbe essere difficile da convertire, basta sostituire int * o double * interi del out e ref è con, e non utilizzare la sintassi del puntatore)

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 a 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;
}

Se trovo il mio codice in C #, mi permetterà di modificare questa risposta ....

Cosa succede ad usare colori GetBrightness, GetHue e GetSaturation metodi?

Se stai usando .net, perché reinventare la ruota?

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

La conversione da RGB a HSB dovrebbe essere piuttosto facile utilizzando la struttura Color:

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

E 'non supporta il contrario, però.

Soluzione

È possibile calcolare il componente di luminosità molto semplicemente in quanto è il massimo di R, G e B (di riferimento: formula per RGB per HSV dal Rochester Institute of Technology ). È possibile scalare che più vi piace dividendo per 255 e moltiplicando per la scala. Questo è lo stesso come fatto nel codice esistente:

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

Così, alla fine, è possibile utilizzare il built-in funzioni Net e solo calcolare la luminosità. Codice completa sarebbe (escluse le tipologie):

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

Un po 'di HSB (lo stesso di HSV)

Darel Rex Finley :

  

Nel sistema HSV (chiamato anche HSB), la luminosità del colore è la sua componente V. Tale componente è definito semplicemente come valore massimo di uno qualsiasi dei tre componenti RGB del colore -. Gli altri due componenti RGB vengono ignorati nel determinare V

Secondo la Microsoft Documentation Color.GetBrightness:

  

Ottiene la tonalità-saturazione luminosità ( HSB ) valore di luminosità per questa struttura Color.

Ho trovato alcuni riferimenti dicendo che il MSDN utilizza HSB quando significa HSL come questo uno da MSDN blog (vedi i commenti). Un test rapido dimostra che questo è vero (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());

Questo si traduce in un valore di 127, che è chiaramente HSL. Se era HSB il valore deve essere al massimo di R G e B (cioè 255).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top