Recent

Author Topic: Color similarity  (Read 7814 times)

bigeno

  • Sr. Member
  • ****
  • Posts: 250
Color similarity
« on: October 18, 2013, 09:43:07 pm »
Hi,
I need assign to my base colors (red,pink,yellow,blue,...) some imported colors (TColor). This colors have various hex, but I need assign to my set of base colors.
Is there some  "similarity function" to assign a color?

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Color similarity
« Reply #1 on: October 19, 2013, 12:24:13 am »
If I understood your question right. You have a variable of type TColor and you want to find the nearest "color" of your fixed "base colors" to this variable. Your "base colors" are stored in an array of TColor as well.

My suggestion is to compare your colors based on hue values. That means you need to convert your TColor (red, green , blue values) to hue value (byte or single) . You can do a search for that if you care to code it yourself, or you could use Graphics32 it has a procedure to do that conversion in a unit called GR32.pas

Code: [Select]
procedure RGBtoHSL(RGB: TColor32; out H, S, L: Byte);
var
  R, G, B, D, Cmax, Cmin, HL: Integer;
begin
  R := (RGB shr 16) and $ff;
  G := (RGB shr 8) and $ff;
  B := RGB and $ff;

  Cmax := Max(R, G, B);
  Cmin := Min(R, G, B);
  L := (Cmax + Cmin) div 2;

  if Cmax = Cmin then
  begin
    H := 0;
    S := 0
  end
  else
  begin
    D := (Cmax - Cmin) * 255;
    if L <= $7F then
      S := D div (Cmax + Cmin)
    else
      S := D div (255 * 2 - Cmax - Cmin);

    D := D * 6;
    if R = Cmax then
      HL := (G - B) * 255 * 255 div D
    else if G = Cmax then
      HL := 255 * 2 div 6 + (B - R) * 255 * 255 div D
    else
      HL := 255 * 4 div 6 + (R - G) * 255 * 255 div D;

    if HL < 0 then HL := HL + 255 * 2;
    H := HL;
  end;
end;

or

Code: [Select]
procedure RGBtoHSL(RGB: TColor32; out H, S, L : Single);
var
  R, G, B, D, Cmax, Cmin: Single;
begin
  R := RedComponent(RGB) / 255;
  G := GreenComponent(RGB) / 255;
  B := BlueComponent(RGB) / 255;
  Cmax := Max(R, Max(G, B));
  Cmin := Min(R, Min(G, B));
  L := (Cmax + Cmin) / 2;

  if Cmax = Cmin then
  begin
    H := 0;
    S := 0
  end
  else
  begin
    D := Cmax - Cmin;
    if L < 0.5 then S := D / (Cmax + Cmin)
    else S := D / (2 - Cmax - Cmin);
    if R = Cmax then H := (G - B) / D
    else
      if G = Cmax then H  := 2 + (B - R) / D
      else H := 4 + (R - G) / D;
    H := H / 6;
    if H < 0 then H := H + 1
  end;
end;

It shouldn't be difficult for you to adjust either procedures above to use TColor instead of TColor32. Your target is H. Then your problem should be more or less finding where does your variable color H value fit among your base colors H values.  :)

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Color similarity
« Reply #2 on: October 19, 2013, 01:05:08 am »
I attached an image here as an example. The gradient part on the left has the same hue value (would be considered identical color), while the small section on the right has increasing hue value going up.


avra

  • Hero Member
  • *****
  • Posts: 2003
    • Additional info
Re: Color similarity
« Reply #3 on: October 21, 2013, 09:20:23 am »
If simple colors similarity is needed with just a little variance over RGB, CMYK or some other color space, then classic algorithms would do the job. Unfortunatelly, if you do a lot of color mixing, and you would like to guess that some color is skin color, earth color, yelowish green, bluish green, or whatever color names we have in use today, then you should study fuzzy logic to implement a smart human like color recognizer. Once you understand the principles, it is not hard to implement it.

In short, any human experience that can be written down as a set of rules can be used to develop fuzzy rules for a simple fuzzy logic engine. It's powerful and not resource hungry - even 8-bit microcontrollers can use it. It's common use is in various 'smart' devices (air conditioner, washer machine, refrigirator), games AI, autonomous vehicles, optimal control loops...

http://en.wikipedia.org/wiki/Fuzzy_control
« Last Edit: October 21, 2013, 09:29:02 am by avra »
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

bigeno

  • Sr. Member
  • ****
  • Posts: 250
Re: Color similarity
« Reply #4 on: October 21, 2013, 11:34:56 pm »
Thanks for help guys, I've "fuzzy logic" on studying "long time ago"  :D but I think I do work on expand my base colors to RGB, it would be simpler and better.  ;)

wp

  • Hero Member
  • *****
  • Posts: 7553
Re: Color similarity
« Reply #5 on: October 22, 2013, 01:02:56 am »
A comment on engkin's posting at the top: Procedures for rgb-to-hls conversion and vice versa are available also in GraphUtils (ColorToHLS, RGBToHLS, HLSToColor, HLSToRGB)
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Color similarity
« Reply #6 on: October 22, 2013, 01:25:27 am »
A comment on engkin's posting at the top: Procedures for rgb-to-hls conversion and vice versa are available also in GraphUtils (ColorToHLS, RGBToHLS, HLSToColor, HLSToRGB)

Thank you so much for letting me know. :) I had used Graphics32 before knowing about Lazarus/FPC. Everyday I learn something I like here. Thanks again.

Edit:
The unit name is GraphUtil (graphutil.pp) without the s. These functions did exist in Delphi as well.
« Last Edit: October 22, 2013, 02:00:01 am by engkin »

circular

  • Hero Member
  • *****
  • Posts: 3451
    • Personal webpage
Re: Color similarity
« Reply #7 on: October 27, 2013, 01:24:03 am »
If you are not looking for maximum speed but for best quality, BGRABitmap provides BGRADiff and BGRAWordDiff, and conversions between RGB and HSL taking into account gamma correction and hue correction. You could just copy those functions without using BGRABitmap library, in this case however you need also GammaExpansion function which needs GammaExpansionTab array.
Conscience is the debugger of the mind

 

TinyPortal © 2005-2018