Использование методов, встроенных в объект Color в .NET, не является началом, поскольку, как указывают некоторые ответы, они не поддерживают обратное (преобразование цвета HSB в RGB).Кроме того, Color.GetBrightness
фактически возвращает легкость , а не яркость / значение.Существует много путаницы в отношении различий между цветовыми пространствами HSB / HSV и HSL из-за их сходства ( Wikipedia ).Я вижу множество палитр цветов, которые в конечном итоге используют неправильный алгоритм и / или модель.
Исходный код выглядит для меня так, будто он пропускает несколько возможных сценариев, когда вычисляет значение для оттенка, учитывая цвет RGB.Мне немного сложно следить за дополнениями, которые вы рассматриваете в коде, но первое, что бросается в глаза (и вы не предлагаете исправить), это то, что когда насыщенность = 0, вы устанавливаетеОттенок до -1.Когда вы затем умножаете оттенок на 60, вы получаете -60, затем добавляете это значение к 360 (If h < 0 Then h = h + 360
), получая результат 300, что неверно.
Я использую следующий код(в VB.NET) для преобразования между RGB и HSB (который я называю HSV).Результаты были очень тщательно протестированы, и результаты практически идентичны результатам, полученным с помощью средства выбора цвета в Photoshop (за исключением компенсации, которую он дает для цветовых профилей).Основное различие между опубликованным кодом и моим (кроме важной части, которая вычисляет оттенок) заключается в том, что я предпочитаю нормализацию значений RGB в диапазоне от 0 до 1, а не в работе с исходными значениями от 0 до 255.Это также устраняет некоторые неэффективности и множественные преобразования в исходном коде, который вы разместили.
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
Вы не опубликовали код, который вы используете для преобразования из HSB (который я называю HSV)цвет в RGB, но вот что я использую, снова работая с промежуточными значениями от 0 до 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
РЕДАКТИРОВАТЬ: Этот код выглядит очень похоже на тот, который предоставляется в CРичард Дж. Росс III.Я выискал столько разных алгоритмов, сколько смог найти в Интернете, переписал много кода, позаимствовав лучшее из каждого из них, и провел обширное тестирование, чтобы проверить точность результатов.Я забыл отметить, у кого заимствовал код, так как это было только для частной библиотеки.Возможно, версия VB поможет кому-то, кто не хочет делать преобразование из C.: -)