Solved

RGB to HVS?

Posted on 2003-11-30
14
1,398 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
 
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
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

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…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

746 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now