Source Code
 4 vbMedia
 Hue Lightness and Saturation (HLS) Model and Manipulating Colours Pick colours and manipulate colours more easily

 NOTE: this code has been superceded by the version at the new site.

&nbsp

This is a supporting article describing in more detail the Hue Lightness and Saturation colour model used in the vbAccelerator Image Processor.

The Hue Lightness Saturation Model
Normally in computers colours are described in terms of their Red, Green and Blue components. Whilst you can specify all displayable colours this way, it leaves something to be desired when it comes to picking a colour. For example, most people find it very difficult to determine what RGB values you would use to create a Pink or Brown colour (try it!).

There are numerous colour models which attempt to work around this limitation and provide a more intuitive way of getting to the colour you want. One of them is the Hue Lightness and Saturation (HLS) Model.

This HLS model describes colours in the following terms:

• Hue, which is the horizontal axis of square box in the picture above, and varies from magenta - red - yellow - green - cyan - blue - magenta.
• Saturation, which is the vertical axis of the square box, and describes how "grey" the colour.
• Lightness, which is the second picture box and varies from black through the colour to white.
With this model it is easier to pick the correct colour. The model also allows you to do some things in code which you can't really achieve with RGB, such as determining what a lighter or darker tone of a given RGB colour is.

Coding the HLS Model
Normally Hue is expressed as an angle between 0-360 to describe the colour and a value between 0 and 1 to describe Hue and Saturation. I have missed out the conversion to an angle in this implementation so the Hue works as follows:

 Hue Value Colour -1 Magenta 0 Red 1 Yellow 2 Green 3 Aqua 4 Blue 5 Magenta

Here is the code to do a conversion between HLS and RGB and vice-versa:

Public Sub RGBToHLS( _
&nbsp &nbsp ByVal r As Long, ByVal g As Long, ByVal b As Long, _
&nbsp &nbsp h As Single, s As Single, l As Single _
&nbsp &nbsp )
Dim Max As Single
Dim Min As Single
Dim delta As Single
Dim rR As Single, rG As Single, rB As Single

&nbsp &nbsp rR = r / 255: rG = g / 255: rB = b / 255

'{Given: rgb each in [0,1].
' Desired: h in [0,360] and s in [0,1], except if s=0, then h=UNDEFINED.}
&nbsp &nbsp &nbsp &nbsp Max = Maximum(rR, rG, rB)
&nbsp &nbsp &nbsp &nbsp Min = Minimum(rR, rG, rB)
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp l = (Max + Min) / 2'{This is the lightness}
&nbsp &nbsp &nbsp &nbsp '{Next calculate saturation}
&nbsp &nbsp &nbsp &nbsp If Max = Min Then
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp 'begin {Acrhomatic case}
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp s = 0
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp h = 0
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp 'end {Acrhomatic case}
&nbsp &nbsp &nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp 'begin {Chromatic case}
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp '{First calculate the saturation.}
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp If l &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp s = (Max - Min) / (Max + Min)
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp s = (Max - Min) / (2 - Max - Min)
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp End If
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp '{Next calculate the hue.}
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp delta = Max - Min
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp If rR = Max Then
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp h = (rG - rB) / delta'{Resulting color is between yellow and magenta}
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp ElseIf rG = Max Then
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp h = 2 + (rB - rR) / delta '{Resulting color is between cyan and yellow}
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp ElseIf rB = Max Then
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp h = 4 + (rR - rG) / delta '{Resulting color is between magenta and cyan}
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp End If
&nbsp &nbsp &nbsp &nbsp 'end {Chromatic Case}
&nbsp &nbsp End If
End Sub

Public Sub HLSToRGB( _
&nbsp &nbsp ByVal h As Single, ByVal s As Single, ByVal l As Single, _
&nbsp &nbsp r As Long, g As Long, b As Long _
&nbsp &nbsp )
Dim rR As Single, rG As Single, rB As Single
Dim Min As Single, Max As Single

&nbsp &nbsp If s = 0 Then
&nbsp &nbsp
' Achromatic case:
&nbsp &nbsp rR = l: rG = l: rB = l
&nbsp &nbsp Else
&nbsp &nbsp
' Chromatic case:
&nbsp &nbsp ' delta = Max-Min
&nbsp &nbsp If l &nbsp &nbsp &nbsp &nbsp 's = (Max - Min) / (Max + Min)
&nbsp &nbsp &nbsp &nbsp
' Get Min value:
&nbsp &nbsp &nbsp &nbsp Min = l * (1 - s)
&nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp 's = (Max - Min) / (2 - Max - Min)
&nbsp &nbsp &nbsp &nbsp
' Get Min value:
&nbsp &nbsp &nbsp &nbsp Min = l - s * (1 - l)
&nbsp &nbsp End If
&nbsp &nbsp
' Get the Max value:
&nbsp &nbsp Max = 2 * l - Min
&nbsp &nbsp
&nbsp &nbsp
' Now depending on sector we can evaluate the h,l,s:
&nbsp &nbsp If (h &nbsp &nbsp &nbsp &nbsp rR = Max
&nbsp &nbsp &nbsp &nbsp If (h &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rG = Min
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rB = rG - h * (Max - Min)
&nbsp &nbsp &nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rB = Min
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rG = h * (Max - Min) + rB
&nbsp &nbsp &nbsp &nbsp End If
&nbsp &nbsp ElseIf (h &nbsp &nbsp &nbsp &nbsp rG = Max
&nbsp &nbsp &nbsp &nbsp If (h &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rB = Min
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rR = rB - (h - 2) * (Max - Min)
&nbsp &nbsp &nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rR = Min
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rB = (h - 2) * (Max - Min) + rR
&nbsp &nbsp &nbsp &nbsp End If
&nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp rB = Max
&nbsp &nbsp &nbsp &nbsp If (h &nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rR = Min
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rG = rR - (h - 4) * (Max - Min)
&nbsp &nbsp &nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rG = Min
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp rR = (h - 4) * (Max - Min) + rG
&nbsp &nbsp &nbsp &nbsp End If
&nbsp &nbsp &nbsp &nbsp
&nbsp &nbsp End If
&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp
&nbsp &nbsp End If
&nbsp &nbsp r = rR * 255: g = rG * 255: b = rB * 255
End Sub
Private Function Maximum(rR As Single, rG As Single, rB As Single) As Single
&nbsp &nbsp If (rR > rG) Then
&nbsp &nbsp If (rR > rB) Then
&nbsp &nbsp &nbsp &nbsp Maximum = rR
&nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp Maximum = rB
&nbsp &nbsp End If
&nbsp &nbsp Else
&nbsp &nbsp If (rB > rG) Then
&nbsp &nbsp &nbsp &nbsp Maximum = rB
&nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp Maximum = rG
&nbsp &nbsp End If
&nbsp &nbsp End If
End Function
Private Function Minimum(rR As Single, rG As Single, rB As Single) As Single
&nbsp &nbsp If (rR &nbsp &nbsp If (rR &nbsp &nbsp &nbsp &nbsp Minimum = rR
&nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp Minimum = rB
&nbsp &nbsp End If
&nbsp &nbsp Else
&nbsp &nbsp If (rB &nbsp &nbsp &nbsp &nbsp Minimum = rB
&nbsp &nbsp Else
&nbsp &nbsp &nbsp &nbsp Minimum = rG
&nbsp &nbsp End If
End If
End Function

Limitations of the HLS Model
Whilst the HLS Model is simple to implement, and gives a relatively easy colour picking interface, it is not a physically accurate model. That is to say, linear changes in lightness, hue or saturation do not correspond to the a linear change to the eye. More accurate models which overcome these limitations exist, such as the CIE scheme, but I've yet to understand these enough to work them out! Anyway, HLS works well enough unless you are interested in exact colour matching and processing between different display devices.