Manipulating Colors

RGB, HSL, HSV, and HCW

RGB to HCW Color Conversion

/Home /Professional /Papers /ColorHCW

Contents

I often create simple graphics for my web sites. When I use clip art from various sources I encounter various situations where I need to manipulate colors. My web site is non-profit and non-revenue so I am not interested in buying suitable pictures or paying a royalty. Therefore the graphics I find to use are often of poor quality because they are usually in low resolution with JPEG artifacts when I try to scale them. I also use only PAINT because it is a free tool included with Windows.

One recent graphic was a nice drawing of an angel I wanted to use on my web site. There were the usual problems with the graphic. It was in the JPG format so it was degraded and would not scale well. I wanted to paste it onto another graphic so I needed to have it surrounded with a completely black background.

Example of JPEG artifacts and non-black background. In these examples the graphic is shown 200% and black has been pasted to white to show the difference between true black and near black.

JPEG artifacts example

I did an intial crude manual erase around the image. I used to do serious software development so I decided to write a program to manipulate the image. Later I added some crude algorithms to smooth out the JPEG artifacts. Then I wanted to do color shifts. In the process I realized it was very awkward to work with RGB values and I embarked on research into an alternate color representation.

Example of smoothed JPEG artifacts and blackened background.

Smoothed result example

I was initially led into the use of HSB because it is a part of the .NET Framework Color structure. I quickly discovered I had a problem because the conversion provided was only from RGB to HSB and not back.

RGB Color Representation

First let me make some observations about the RGB color representation which are a significant factor in where this line of research took me. RGB is a direct integer representation of the hardware control of a color display. The 0 to 255 range of values for each of the color primaries is more than enough to smoothly describe a full range of colors.

The problem with the RGB color representation is it does not easily relate to how human beings perceive color. Primary colors are pretty easy but when you get into shades, tones, and tints you are almost lost.

Integer representation is important because it is computationally simple and fast. This factor is lost in almost all other color representations which use floating point in the values they use to represent color or the conversion methods they use and usually both.

A direct relationship to the hardware is also important to maintain in the color representation because it provides an existing frame of reference for simple understanding.

HSL/HSV Color Representation

Initially, I hoped to simply learn how to program the conversion from HSB to RGB. I quickly learned the HSB conversion was not well documented and there were many other representations from which to choose. The best and relatively brief introduction to the subject is not surprisingly found at Wikipedia.

http://en.wikipedia.org/wiki/HSL_and_HSV

I am not interested in trying to be scientifically accurate in describing color according to human perception. I only needed it to be close enough for general intents and purposes. My goal was for a representation which had as simple a conversion procedure as practical.

There was no representation which did not include floating point in both the values used to represent color and the conversion process. I was confident I could pick a representation which could be modified in a straightforward manner to use integer representation and integer conversion methods.

I picked the HSV method to modify in this process. The representation I created is called HCW or Hue, Chroma, and White. I carefully analyzed the names used to describe the various representations and their descriptions. I looked for something which was highly accurate but as easy to understand and as simple as practical.

HCW Color Representation

I created the Hue, Chroma, White (HCW) color representation. The HCW color system directly relates to the RGB color system for better or worse. This system has many similarities with the Munsell color system.

http://en.wikipedia.org/wiki/Munsell_color_system

Hue is a somewhat technical term used by almost all color representations to indicate the degrees of the color wheel. Red is always 0 which is easy to remember because Red is the first letter R of RGB. Stepping through the letters R, G, and B in order produces the colors of the wheel. Yellow (combining RG) is 60 degrees, Green is 120 degrees, Cyan (combining GB) is 180 degrees, Blue is 240 degrees, Magenta (combining BR) is 300 degrees, and 360 degrees wraps back to Red or 0.

Floating point is avoided in the HCW format by defining the value of hue in decidegrees or tenths of a degree. The range 0 to 3599 fits compactly in an unsigned or signed two byte representation. There are over 2 decidegrees between each primary color shade on the color wheel which provides plenty of resolution.

I considered using the highly non-technical term Color but the meaning is just too ambiguous. Hue is acceptable because it is a very common term among professionals and is part of the Munsell color system.

Chroma is also a somewhat technical term which indicates the tone or brightness of the hue. Other representations use the term saturation which Wikipedia disparages and I find their logic compelling. The chroma is a value between 0 and 255. A value of 0 is always black.

I strongly considered using the highly non-technical term Black and reversing the range of values. Chroma is acceptable because it is a common term among professionals and is part of the Munsell color system.

White is a highly non-technical term I use to refer to how close the color is to white. White is a value between 0 and 255. A value of 255 is always white. The Munsell color system uses the term "value" which is just too ambiguous.

White is a tint or pastel value which can never be greater than chroma. When white equals chroma the color is a grey scale and hue is meaningless. It is important to note the value of Hue remembers the original hue when Chroma and White are being dynamically adjusted and pass through a grey scale.

The HCW representation is a simple and direct mapping of the RGB structure which maintains an integer basis for all values and conversions. Hue is the ratio of the maximum value of the RGB representation to the next lower value offset from the primary color. Chroma is the maximum value of the RGB representation. White is the minimum value of the RGB representation.

This may seem like an overly simple way to represent color but you will find the results highly effective.

In this partial example chart of some common colors, values indicated with a '?' are either undefined, fixed, meaningless, or variable.

Examples:

ColorRGBHCW
DescriptionRRGGBBHueChromaWhite
Black0000000?00?
Gray8080800?128128
Dark Red80000001280
Redff000002550
Pastel Redff80800255128
Dark Yellow8080006001280
Yellowffff006002550
Pastel Yellowffff80600255128
Dark Green00800012001280
Green00ff0012002550
Pastel Green80ff801200255128
Dark Cyan00808018001280
Cyan00ffff18002550
Pastel Cyan80ffff1800255128
Dark Blue00008024001280
Blue0000ff24002550
Pastel Blue8080ff2400255128
Dark Magenta80008030001280
Magentaff00ff30002550
Pastel Magentaff80ff3000255128
Silverc0c0c00?192192
Whiteffffff0?255?255

Visual Representations

A graphical representation of the RGB color space is a cube. The 3D graphic (using typical positional cues) is specifically arranged to show the hue beginning with red at the twelve o'clock position (of the flat representation) with the degree of the hue increasing clockwise. (Black is not visible in the back of the cube.)

RGB Cube visualization

The following description shows a graphical representation of how to morph the RGB color space to the HCW color space which can be viewed as a hexcone similar to what is described by Wikipedia. Begin with an RGB cube showing the primary color nodes. The arrangement is designed to approximately match the above graphic. (Graphic adapted from Wikipedia)

RGB Cube showing primary color nodes.

Orient the RGB cube with the white node to the top and the black node to the bottom. The order of the color nodes is reversed from the above graphic to match the orientation on the next graphic. Diagonal seams are added to show the new edges where the nodes are going to be moved. (Graphic adapted from Wikipedia)

RGB cube shown the white node to the top and the black node to the bottom

Lower the 6 color nodes to the same plane as the black. The cone is shown with the bottom tilted up. Again the goal is to show red at the twelve o'clock position with the degree of hue increasing clockwise.(Graphic adapted from Wikipedia)

HCW Hexcone visualization

This graphic illustrates the full color view of the base (White = 0) of the hexcone which is the complete Chroma range from 0 at the center to 255 at the outside for all possible hues. Hue ranges from 0 at the top clockwise through the entire range.

Hue/Chroma range graphic hexagon

This graphic illustrates the full color view (Chroma = 255) looking down from the top of the cone. This is the complete White range from 255 at the center to 0 at the outside for all possible hues. Hue ranges from 0 at the top clockwise through the entire range. The order of the primary colors is reversed from the previous graphic to maintain the clockwise order for the degree of hue. The graphic is a projection rendered identically to the RGB cube though it is conceptually quite different.

Hue/White range graphic hexagon

This is a graphical representation of how to morph a conical projection of the HCW color space to a cylinder and then a rectangular projection similar to what is described by Wikipedia. Begin with the hexcone of the color space. (Graphic adapted from Wikipedia)

HCW Hexcone visualization

Stretch the top of the 6 horizontal segments to create a hexagonal cylinder. (Graphic adapted from Wikipedia)

HCW cylindrical visualization

Round the segments to create a cylinder. (Graphic adapted from Wikipedia)

HCW cylindrical visualization

This graphic illustrates the cylindrical visualization of the outer surface (Chroma = 255) of the hexcone with the complete White range from 0 at the bottom to 255 at the top. Hue ranges from 0 at the left going right through the entire range with a small amount of overlap.

Hue/White range graphic

RGB to HCW Color Conversion

This is the C# code for the conversion methods from a class which maintains the _hue, _chroma, _white values.

///  
/// return an RGB equivalent value converted from HCW
///  
public Color RGB ()
{
  byte red, green, blue;
  int sextant, offset;

// integer sixth part of a circle
  sextant = _hue / 600;
// offset scaled to byte
  offset = ((_hue % 600) * (_chroma - _white)) / 600;

  switch (sextant)
  {
    case 0:  // 0 Red
      red = _chroma;
      if (_chroma == _white)
        green = _white;
      else
        green = (byte) (offset + _white);
      blue = _white;
      break;
    case 1:  // 600 Yellow
      red = (byte) (_chroma - offset);
      green = _chroma;
      blue = _white;
      break;
    case 2:  // 1200 Green
      red = _white;
      green = _chroma;
      blue = (byte) (offset + _white);
      break;
    case 3:  // 1800 Cyan
      red = _white;
      green = (byte) (_chroma - offset);
      blue = _chroma;
      break;
    case 4:// 2400 Blue
      red = (byte) (offset + _white);
      green = _white;
      blue = _chroma;
      break;
    case 5:  // 3000 Magenta
    default:
      red = _chroma;
      green = _white;
      blue = (byte) (_chroma - offset);
      break;
  }
  return Color.FromArgb (red, green, blue);
}

///  
/// set the HCW equivalent value converted from individual RGB values
///  
/// red value in the range 0 to 255
/// green value in the range 0 to 255
/// blue value in the range 0 to 255
public void RGB (byte red, byte green, byte blue)
{  
  int sextant, offset;

  if (red >= green)
    if (green >= blue)
      sextant = 0;
    else
      if (red >= blue)
        sextant = 5;
      else
        sextant = 4;
  else
    if (red >= blue)
      sextant = 1;
    else
      if (green >= blue)
        sextant = 2;
      else
        sextant = 3;

  switch (sextant)
  {
    case 0:  // 0 Red
      offset = red - blue;
      if (0 >= offset)
        _hue = 0;
      else
        _hue = (short) (((green - blue)
          * 600 + (offset - 1)) / offset);
      _chroma = red;
      _white = blue;
      break;
    case 1:  // 600 Yellow
      offset = green - blue;
      _hue = (short) (1200 - ((red - blue)
          * 600) / offset);
      _chroma = green;
      _white = blue;
      break;
    case 2:  // 1200 Green
      offset = green - red;
      _hue = (short) (1200 + (((blue - red)
          * 600 + (offset - 1)) / offset));
      _chroma = green;
      _white = red;
      break;
    case 3:  // 1800 Cyan
      offset = blue - red;
      _hue = (short) (2400 - ((green - red)
          * 600) / offset);
      _chroma = blue;
      _white = red;
      break;
    case 4:// 2400 Blue
      offset = blue - green;
      _hue = (short) (2400 + (((red - green)
          * 600 + (offset - 1)) / offset));
      _chroma = blue;
      _white = green;
      break;
    case 5:  // 3000 Magenta
    default:
      offset = red - green;
      _hue = (short) (3600 - ((blue - green)
          * 600) / offset);
      _chroma = red;
      _white = green;
      break;
  }
}
This class and other functionality is implemented in the HCW-Modify program.

The complete Microsoft Visual Studio 2010 Express (Visual C# 2010 Express) HCW-Modify project test files:

HCW-Modify.zip

Free Microsoft Visual Studio 2010 Express download:

http://www.microsoft.com/express/Downloads/#2010-Visual-CS


Revised 2011-03-25