Solved

RGB to HVS?

Posted on 2003-11-30
14
1,420 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
  • 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
Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

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.

 
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: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

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 I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

860 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