Solved

RGB to HVS?

Posted on 2003-11-30
14
1,433 Views
Last Modified: 2007-12-19
Hi!

I would like to create a routine that converts RGB to HVS colors...
(Needed to immitate the disabled menu-items)

Does somebody know how can can derive Hue, Saturation and Value from Red, Green and Blue??


Thanks for advance!
0
Comment
Question by:ChristopH1987
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 5
  • 2
  • +1
14 Comments
 
LVL 5

Accepted Solution

by:
arjanh earned 250 total points
ID: 9844937
From http://www.efg2.com/Lab/Graphics/Colors/HSV.htm:

USES
  Math,        // MaxValue
  IEEE754,  // NaN, IsNaN
  SysUtils;    // Exception

TYPE
  EColorError = CLASS(Exception);
  TReal = DOUBLE;
...
// RGB, each 0 to 255, to HSV.
// H = 0.0 to 360.0 (corresponding to 0..360.0 degrees around hexcone)
// S = 0.0 (shade of gray) to 1.0 (pure color)
// V = 0.0 (black) to 1.0 {white)

// Based on C Code in "Computer Graphics -- Principles and Practice,"
// Foley et al, 1996, p. 592.

PROCEDURE RGBToHSV (CONST R,G,B: TReal; VAR H,S,V: TReal);
  VAR
    Delta: TReal;
    Min : TReal;
BEGIN
  Min := MinValue( [R, G, B] );    // USES Math
  V := MaxValue( [R, G, B] );

  Delta := V - Min;

  // Calculate saturation: saturation is 0 if r, g and b are all 0
  IF       V = 0.0
  THEN S := 0
  ELSE S := Delta / V;

  IF       S = 0.0
  THEN H := NaN    // Achromatic: When s = 0, h is undefined
  ELSE BEGIN       // Chromatic
    IF       R = V
    THEN // between yellow and magenta [degrees]
      H := 60.0 * (G - B) / Delta
    ELSE
      IF       G = V
      THEN // between cyan and yellow
        H := 120.0 + 60.0 * (B - R) / Delta
      ELSE
        IF       B = V
        THEN // between magenta and cyan
          H := 240.0 + 60.0 * (R - G) / Delta;

    IF H < 0.0
    THEN H := H + 360.0
  END
END {RGBtoHSV};
 

 

HSVtoRGB
 
// Based on C Code in "Computer Graphics -- Principles and Practice,"
// Foley et al, 1996, p. 593.
//
// H = 0.0 to 360.0 (corresponding to 0..360 degrees around hexcone)
// NaN (undefined) for S = 0
// S = 0.0 (shade of gray) to 1.0 (pure color)
// V = 0.0 (black) to 1.0 (white)

PROCEDURE HSVtoRGB (CONST H,S,V: TReal; VAR R,G,B: TReal);
  VAR
    f : TReal;
    i : INTEGER;
    hTemp: TReal; // since H is CONST parameter
    p,q,t: TReal;
BEGIN
  IF       S = 0.0    // color is on black-and-white center line
  THEN BEGIN
    IF       IsNaN(H)
    THEN BEGIN
      R := V;           // achromatic: shades of gray
      G := V;
      B := V
    END
    ELSE RAISE EColorError.Create('HSVtoRGB: S = 0 and H has a value');
  END

  ELSE BEGIN // chromatic color
    IF       H = 360.0         // 360 degrees same as 0 degrees
    THEN hTemp := 0.0
    ELSE hTemp := H;

    hTemp := hTemp / 60;     // h is now IN [0,6)
    i := TRUNC(hTemp);        // largest integer <= h
    f := hTemp - i;                  // fractional part of h

    p := V * (1.0 - S);
    q := V * (1.0 - (S * f));
    t := V * (1.0 - (S * (1.0 - f)));

    CASE i 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;
      5: BEGIN R := V; G := p; B := q  END
    END
  END
END {HSVtoRGB};
0
 
LVL 2

Author Comment

by:ChristopH1987
ID: 9845006
Thanks!

But it seems that there are some problems...

I think you know the MSPaint application. But if I use the HSV values from MSPaint as parameters i don't get the correct RGB values from MSPaint!

Do you know how to get the right values?
0
 
LVL 5

Expert Comment

by:arjanh
ID: 9845140
// H = 0.0 to 360.0 (corresponding to 0..360.0 degrees around hexcone)
// S = 0.0 (shade of gray) to 1.0 (pure color)
// V = 0.0 (black) to 1.0 {white)

Perhaps you need to do a correction to values in the rang 0..255 ??

I don't have paint installed, but Paint Shop Pro colors and the output of the HSV tool from http://www.efg2.com/Lab/Graphics/Colors/HSV.htm seem to match.
There is also an integer version of above functions, in HSVLibrary.pas in the .zip file you can download at that site.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 4

Assisted Solution

by:StevenB
StevenB earned 50 total points
ID: 9848350
The comments here might prove enlightening:

http://oldlook.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_10023634.html


Regards,
Steven
0
 
LVL 2

Assisted Solution

by:odissey1
odissey1 earned 200 total points
ID: 9848638
Hi ChristopH1987,

If you need just fainted image do this way. On the form below just 2 Images, 1 button and 2 Trackbars to adjust Gamma and Intensity. Once you slide TrackBars the Output Image2 will show desaturated bleached copy of the original Image1. Note: example below works with 24 bit bitmaps only.

Ask for details or email for complete project
regards,
<odissey1>

unit DisableImage_1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, ExtCtrls, jpeg, GIFImage,
  Math;

type
  TForm1 = class(TForm)
    Image1: TImage;
    TrackBar1: TTrackBar;
    Button1: TButton;
    Image2: TImage;
    TrackBar2: TTrackBar;
    procedure Button1Click(Sender: TObject);
    procedure TrackBar1Change(Sender: TObject);
    procedure TrackBar2Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Gamma: double = 0.5;
  Scale: integer = 255;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
CONST
   PixelCountMax = 32768;
TYPE
  pRGBTripleArray = ^TRGBTripleArray;
  TRGBTripleArray = ARRAY[0..PixelCountMax-1] OF TRGBTriple;
var
   i, j, BitWidth, BitHeigt : integer;
   Bitmap1, Bitmap2 : TBitmap;
   Row1, Row2:  pRGBTripleArray;
   k : integer;
   Clr: TRGBTriple;
   V: double;
function AdjustGamma(Color: double): Integer;
begin
     if Color = 0 then result := 0 //don't want 0^x = 1 for x <> 0
     else result := round(Scale{255} * Power(Color/255, Gamma) );
end;

begin

    Bitmap1 := Image1.Picture.Bitmap;
    Bitmap2 := TBitmap.create;
    try
       Bitmap2.PixelFormat := pf24bit; //always first!
       Bitmap2.height := Bitmap1.Height;
       Bitmap2.Width  := Bitmap1.Width;
       Form1.Caption:='W:'+IntTostr(Bitmap2.Width)+' H:'+IntTostr(Bitmap2.Height);

       for i := 0 to (Bitmap2.Height - 1)  do begin
          Row1 := Bitmap1.ScanLine[i];
          Row2 := Bitmap2.ScanLine[i];
          for j := 0 to (Bitmap2.Width - 1) do begin
//              Clr  :=Row1^[j];
//              Clr.rgbtRed  :=Row1^[j].rgbtRed;
//              Clr.rgbtGreen:=Row1^[j].rgbtGreen;
//              Clr.rgbtBlue :=Row1^[j].rgbtBlue;

              V:=0.299*Row1^[j].rgbtRed+0.587*Row1^[j].rgbtGreen+0.114*Row1^[j].rgbtBlue;
//              k:=round(V);
              k:=AdjustGamma(V);
              Clr.rgbtRed  :=k;
              Clr.rgbtGreen:=k;
              Clr.rgbtBlue :=k;

              Row2[j] := Clr;
          end;
       end;
       Image2.Picture.Graphic :=Bitmap2;

    finally
       Form1.Caption:='W:'+IntTostr(Bitmap2.Width)+' H:'+IntTostr(Bitmap2.Height);
       Bitmap2.free;
    end;

end;

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
     Gamma:=0.01* TrackBar1.Position;
     Button1Click(Self);
end;

procedure TForm1.TrackBar2Change(Sender: TObject);
begin
     Scale:=TrackBar2.Position;
     Button1Click(Self);

end;

end.
0
 
LVL 2

Expert Comment

by:odissey1
ID: 9860994
Hi ChristopH1987,

any success?

regards,
odissey1
0
 
LVL 2

Expert Comment

by:odissey1
ID: 9862188
This thread is dead or something...

:(
0
 
LVL 2

Author Comment

by:ChristopH1987
ID: 9865707
Hey!

Sorry guys...      I had problems with Internet and my Linux...


Thanks for you solutions... They seem to work well, but does somebody know how I can convert RGB to TColor?

PS: I need that to use my Delphi 6 code for Kylix 3. Its the only Win-API that I used but know i need it in Linux 9!


Thanks for Advance.

PS: After this question i will split the points ;) ( But i don't like to open a new Question for this and you seem to be fit in Colors :O )
0
 
LVL 2

Author Comment

by:ChristopH1987
ID: 9865741
Odissey1 : Thanks for your complete solution, but I found an easier way to make this (you will get points of course)!
                   ( You derive the brightness of a RGB value and then you set with this brightness a new blue color for this pixel
                     [its a little more complex to derive the blue color of the brightness but it looks really like in Office 2003])
                  If you want i can give you the code for this effekt....


arjahn : Your solution works know but i found out, that I only need the Brightness of an RGB-color to realize the blue-effekt.
             So I used Sqrt(r²+b²+g²) to derive the brightness. But Thanks....




0
 
LVL 2

Expert Comment

by:odissey1
ID: 9868076
Hi Christoph1987,

>how I can convert RGB to TColor?

     Color := RGB(240, 240, 240);

>But i don't like to open a new Question for..

Note, this threads seems to be dead, I do not det e-mail notifications any more (other probably too).

> If you want i can give you the code for this effekt....

Yes, please. Could you drop it to 'botadjik@nmsu.edu'?

Regards,
odissey1


0
 
LVL 2

Author Comment

by:ChristopH1987
ID: 9884662
I know RGB(). But OK!

I use StrToInt('$' + IntToHex(b,2) + IntToHex(g,2)+ IntToStr(r,2)) to convert RGB to Color.

I will send you the code at weekend...


Bye!
0
 
LVL 2

Expert Comment

by:odissey1
ID: 9885018
Hi ChristopH1987,

>  StrToInt('$' + IntToHex(b,2) + IntToHex(g,2)+ IntToStr(r,2)) to convert RGB to Color.
-possibly the slowest way! In graphic applications timing is everything. The best is to use pointers or ASM.

odissey1

0
 
LVL 2

Author Comment

by:ChristopH1987
ID: 9887626
Maybe...

But I only need it for little pictures and to inizialize pens...

I have no problems with speed.  Sure, if you want to use it in direct X you will get problems...


Thanks for Advance!


I will close this topic now.
0
 
LVL 2

Author Comment

by:ChristopH1987
ID: 9892505
Try this one:


function GetDisabledColor(Brightness : Integer):TColor;
begin
  Result := RGB(
    Round(109 + (0.32549 * Brightness)),
    Round(150 + (0.20392 * Brightness)),
    Round(208 + (0.05490 * Brightness)));
end;

// For brightness you have to put in a value between 0 and 255; You should derive it from an RGB-Value... Maybe with
// RGBToHSV() and then put in Round(V)


0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

751 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question