This site is under constructiontheWhite's home page
To the Drawings section This is the Computing section To the Writings section To the Professional Works section

The HSB Color Model

  Project Files (VB5.0): HSBColor.zip

The HSB Color Modeller in action

Some time ago, while browsing the posts at the Atlanta VB List, to which I subscribe, I've found this intriguing one:

> I have a logic problem.
> I need to produce a sorted palette.
[Snip]
> I'm trying to come up with logic to group all the blues together,
> then the greens, then the reds, etc. I expect in part that it
> depends on how I define the colors (which will be arbitrary, anyway),
> but I'm unclear how to increment them so that 0,0,255 is close to
> 90,0,255 yet in an appropriate order so that someone with a
> discerning eye will see a logical gradation of color.

> Jim McFadden

This post is implicitly talking about the "RGB Color Model", which is used to represent color in Windows. The name comes from the fact that each screen color is created varying the intensities of the Red, Green and Blue light beams that exist inside the monitor. VB even has a built in function to generate a given color using this model:

 

Function RGB(RedValue, GreenValue, BlueValue) as Long

The post was odd because Jim McFadden is an experienced VB programmer and the subject seemed so simple that any one whith little knowledge about RGB could probably come up with an algorithm right from the top of his/her head.

It certainly was just a matter of varying the intensities of each light beam so we would get a linear pattern of color shades where all the Reds would be grouped together, followed by all the Greens and, finally, all the Blues while the missing colors would be placed between each of these base shades.

Alas, it's not so simple. This is what the latter approach would come up with:

Trying to tame the RGB color model

This seemed like a challenge to me, so I put my battle suit on and went to war. That is, I started looking for answers in the Internet.

After researching the net, I came up with a real better understanding of color (well, I already knew about "Additive" and "Subtractive" colors because of my work with Desktop Publishing).

I also got formally presented to this mathematical color model called HSB, to which I didn't had a clue before. I had seen it when using Photoshop and other similar tools, but I had no idea how it worked and why it was the better way to achieve color categorization in a computer.

What the numbers mean

HSB means "Hue, Saturation and Brightness":

  • Hue: This is the "color" how we use to see it. This value ranges from 0 to 359, starting with Red (0) and going through Orange, Yellow, Green, Blue, Purple and coming back to Red again (359). As you can see, this puts the color in a rainbow-like pattern that is very easy to use.

Hue

  • Saturation: A colored spot can have a variation on the amount of color applied to it, that is, how vivid the color is. This is given by a percentage, where 0% means no color (White) and 100% means "normal" (very vivid).

Saturation

  • Brightness: Finally, the color spot can be classified as how dark or bright it is. This is also a percentage, where 0% means it is very dark (Black) and 100% means it's "normal".

Brightness

 

Looking for HSB desperatelly (almost)

It became clear that, to come up with what Jim was proposing, I had to treat color under a different model than RGB. This is an interesting computing proposal, by the way: putting matters under different lights and perspectives can give you answers that the original approach could not.

The HSB model seemed perfect, but, what was the algorithm to translate forth an back between RGB and HSB? I spent a few hours jumping from site to site, but no one seemed to have this simple (I guessed) information. Then, from an University research site, this tidbit of information crossed my way: "using the Java color library"...

Ops! What is this that you said? That Java has this color library? Well, Java was just a step away, I had just to install VJ++ and browse to the classes source code. And there they were, in the Java.awt.Color.java class: the functions to convert from HSB to RGB and back. Uff!

Armed with the knowledge I needed (and silently blaming Microsoft for the humiliation of having to borrow Java code to use in a VB project) I started coding the class that would do the color conversions and provide other goodies. 

It turns out that the Java library treats the Saturation and Brightness values in a range that goes from 0 to 1.0. It wasn't exactly how I wanted them: my purpose was to package an HSB value in a Long variable, so it had to change slightly. You can find the final conversion code in the accompanying project (ColorConverter.cls). It strikes me because I can't come up with the explanation of how the actual conversion takes place. Although this upsets me somewhat, it does work (kudos to Sun, by the way).

That would be the end of the Color battle, but the war was not over. I had yet to build the application that would use the color conversion class. Building it made use of one or two tricks that I'd like to share.

Using ScaleWidth and ScaleHeight

When plotting the RGB colors converted from each HSB value, I had a few different kinds of graphics to draw. The current Hue, Saturation and Brightness values were kept by the main form in global scope. They could be used as reference points for at least three types of graphics:

  • A Saturation x Brightness graphic, with a fixed Hue value
  • A Hue x Brightness graphic, with a fixed Saturation value, and
  • A Hue x Saturation graphic, with a fixed Brightness value.

I could, of course, derive the necessary positions in the screen based on the width in pixels of the PictureBox where I was painting the graphics and the range for each axis (0-359 for Hue, 0-100 for Saturation and Brightness).

This would be my usual approach, but this time I wanted a simpler way. So I just set the PictureBox's ScaleWidth and ScaleHeight to the maximum value for each axis, and the main loop of the painting routine had simply to iterate the full range of each one. Although very inefficient if the PictureBox dimmension in pixels is less than a particular range, it scales well when the dimmension is greater than that range. Besides, code becomes much more readable.

This is easier to understand, I guess, with a snippet:

'--------------------------------------------------------
Private Sub xHueBrightGraph()
'--------------------------------------------------------
' Draws the Hue x Brightness Graph
' (uses a constant Saturation value)
'--------------------------------------------------------

Dim lX As Long, lY As Long
Dim lColor As Long
Dim lStepX As Long, lStepY As Long
'--------------------------------------------------------
  With pctGraph
    .Cls

    'Sets up each axis' range
    .ScaleWidth = clMaxHue + 1 '360
    .ScaleHeight = clMaxBrightness + 1 '100

    'Converts the quality factor from pixels to the
    'current ScaleMode. Using ScaleX and ScaleY
    'will keep it in the correct proportion:

    lStepX = .ScaleX(mlGraphQuality, vbPixels, .ScaleMode)
    lStepY = .ScaleY(mlGraphQuality, vbPixels, .ScaleMode)
    If lStepX = 0 Then lStepX = 1
    If lStepY = 0 Then lStepY = 1

    'lX iterates the Hue range (0..360)
    For lX = 0 To .ScaleWidth Step lStepX
      'lY iterates the Brightness range (0..100)
      For lY = 0 To .ScaleWidth Step lStepY

        'Converts HSB to RGB
        With mobjColors
          lColor = .HSBToRGB( _
            .HSBToLong(lX, clMaxSaturation, lY))
        End With

        'Draws a box in the desired color
        pctGraph.Line (lX, lY)-Step(lStepX, lStepY), _
        lColor, BF

      Next
    Next
  End With
End Sub

Drawing a Cursor

I wanted the user to drag the mouse over the graphs to alter the H, S and B values of the sample color. The user should be able also to see in the graph the correponding position of these "coordinates". To achieve this, I could use, for instance, an Image control placed over the PictureBox, but a wiser approach, I supposed, would be a Xor cursor.

A Xor cursor is based on the binary Xor operation. The carachteristics of it is that if you take a binary value and Xor it with another value and then Xor the result with the same value again, you'll get the original value back. Besides that, if you Xor any value with a number where each bit is 1, you'll get the binary inverse of the value:

   11110001 XOR 11111111 = 00001110
   00001110 XOR 11111111 = 11110001

Seeing from this description, maybe you wouldn't realize that this simple operation is perfect for cursors: It guarantees that, no matter the color of the pixels where the Xor operation is performed, the cursor will allways be visible. Likewise, to restore the screen to it's original state, we just need to perform the same operation again.

Another use of the Xor binary operation is in creating encripted text: you take a secret key (the user password) and use it's letters as binary values to Xor with a given text. To restore the text back you need the same password again to perform the Xor operation one more time (MS Word used to use this scheme to password protect it's files).

Again, lets see how it cuts in code:

'----------------------------------------
Private Sub xToggleGraphCursor()
'----------------------------------------
' Shows/Hides the Graph cursor
'----------------------------------------

Dim lX As Long, lY As Long
'----------------------------------------
  'Gets the actual 'coordinates' from
  'global variables, based on the
  'current GraphMode:

  Select Case mlGraphMode
  Case gtByHue
    lX = mlCurBrightness
    lY = mlCurSaturation
  Case gtBySaturation
    lX = mlCurHue
    lY = mlCurBrightness
  Case gtByBrightness
    lX = mlCurHue
    lY = mlCurSaturation
  End Select

  With pctGraph
    'The vbInvert mode 'Xors' the pixels
    'with the equivalent to RGB(255,255,255)
    .DrawMode = vbInvert

    'After this operation, it will show or hide
    'the cursor at the lX,lY coordinates:

    pctGraph.Circle (lX, lY), _
    .ScaleX(CURSORSIZE, vbPixels, .ScaleMode)

    .DrawMode = vbCopyPen
  End With
End Sub

Final words (gulp)

As you can see, the HSB color model comes in handy whenever you need to present colors in a categorized way. Being able to pick a given color (er... Hue) by a very specific index and altering this color's Brightness and Saturation is far easier than dealing with RGB values. I hope you enjoy. ;-)

  Related Links
  ZDWebopedia - The CIE Color Model
  Susquehanna University Web Central - RGB Color Model
  Tutorial in Scientific Visualization
  Color Principles - Hue, Saturation and Value
  PostScripting Printing Glossary
  Processing Color Images


 


(c) Branco Medeiros
 

1