2004. május 2., vasárnap

RGB and HSV conversions


Problem/Question/Abstract:

Sometimes it is best to deal with colors as HSV rather than RGB. The artical explains a little bit what HSV is and includes source for converting between the two.

Answer:

HSV is Hue, Saturation, and Value.

HSV:

Hard to explain without a picture so you will have to use your imagination...

Hue:

Draw a circle in your head, the circle is 0 to 360 degrees (or 359 :-) ).  On the outer edge of the circle, place a red dot at 0 degrees, a green dot at 120 degrees and a blue dot at 240 degrees.  Those are the main points.  The other points between these 3 colors are interpolated... for example yellow is between red and green at 60 degrees (equal red + green = yellow), cyan is between green and blue at 180 degrees, magenta is between blue and red at 300 degrees.  Then between yellow and red is another and you keep breaking it down until your circle is full.  The outer edge from 0 to 360 degrees is the hue.

Saturation:

The center of the circle is white.  The color blends with the other colors to white as you go from the outside of the circle to the center.  The outer egde is saturation of 1 and the center is 0 (white).

Value:

Value is simply the intensity of the color.

You already know RGB I assume since you are a programmer.

I played around with my digital camera and took a picture of my brown computer chair.  I created an algorithm that turned my chair green.  It was easy with HSV, I simply used photoshop to see what the hue was of the chair.  Then I rotated the hue so that the chair was in the green range.  Boom, the chair was green.

Here they are:

http://www.eggcentric.com/eimages/greenchair.jpg
http://www.eggcentric.com/eimages/brownchair.jpg

Here is the source of procedures to convert between RGB and HSV and back again.  You can also download it from the link.

unit RGBHSV;
{
  William Egge, public@eggcentric.com
  http://www.eggcentric.com

  This unit converts between RGB and HSV color models.

  procedure HSVToRGB(const H, S, V: Single; out R, G, B: Single);
    in
    H = Hue.  Range is from 0..1.  0.5 = 180 degrees, 1 = 360. or H < 0 for gray
    S = Satration.  Range is 0..1 where 0 is white and 1 is no saturation.
    V = Value.  Range is 0..255

    out
    R = 0..255
    G = 0..255
    B = 0..255

    If H < 0 then the result is a gray value R=V, G=V, B=V

  procedure RGBToHSV(const R, G, B: Single; out H, S, V: Single);
    in
    R = 0..255
    G = 0..255
    B = 0..255

    out
    H = Hue. -1 for grey scale or range 0..1.  0..1 represents 0..360 degrees
    S = Saturation. Range = 0..1. 0 = white, 1 = no saturation.
    V = Value or intensity. Range 0..255
}

interface
uses
  Math;

procedure HSVToRGB(const H, S, V: Single; out R, G, B: Single);
procedure RGBToHSV(const R, G, B: Single; out H, S, V: Single);

implementation

procedure HSVToRGB(const H, S, V: Single; out R, G, B: Single);
const
  SectionSize = 60 / 360;
var
  Section: Single;
  SectionIndex: Integer;
  f: single;
  p, q, t: Single;
begin
  if H < 0 then
  begin
    R := V;
    G := R;
    B := R;
  end
  else
  begin
    Section := H / SectionSize;
    SectionIndex := Floor(Section);
    f := Section - SectionIndex;
    p := V * (1 - S);
    q := V * (1 - S * f);
    t := V * (1 - S * (1 - f));
    case SectionIndex of
      0:
        begin
          R := V;
          G := t;
          B := p;
        end;
      1:
        begin
          R := q;
          G := V;
          B := p;
        end;
      2:
        begin
          R := p;
          G := V;
          B := t;
        end;
      3:
        begin
          R := p;
          G := q;
          B := V;
        end;
      4:
        begin
          R := t;
          G := p;
          B := V;
        end;
    else
      R := V;
      G := p;
      B := q;
    end;
  end;
end;

procedure RGBToHSV(const R, G, B: Single; out H, S, V: Single);
var
  RGB: array[0..2] of Single;
  MinIndex, MaxIndex: Integer;
  Range: Single;
begin
  RGB[0] := R;
  RGB[1] := G;
  RGB[2] := B;

  MinIndex := 0;
  if G < R then
    MinIndex := 1;

  if B < RGB[MinIndex] then
    MinIndex := 2;

  MaxIndex := 0;
  if G > R then
    MaxIndex := 1;

  if B > RGB[MaxIndex] then
    MaxIndex := 2;

  Range := RGB[MaxIndex] - RGB[MinIndex];

  // Check for a gray level
  if Range = 0 then
  begin
    H := -1; // Can't determine on greys, so set to -1
    S := 0; // Gray is at the center;
    V := R; // could choose R, G, or B because they are all the same value.
  end
  else
  begin
    case MaxIndex of
      0: H := (G - B) / Range;
      1: H := 2 + (B - R) / Range;
      2: H := 4 + (R - G) / Range;
    end;
    S := Range / RGB[MaxIndex];
    V := RGB[MaxIndex];
    H := H * (1 / 6);
    if H < 0 then
      H := 1 + H;
  end;
end;

end.


Component Download: http://www.eggcentric.com/download/rgbhsv.zip

Nincsenek megjegyzések:

Megjegyzés küldése