Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - Find similar colors, best way

I've made a function to find a color within a image, and return x, y. Now I need to add a new function, where I can find a color with a given tolerence. Should be easy?

Code to find color in image, and return x, y:

def FindColorIn(r,g,b, xmin, xmax, ymin, ymax):
    image = ImageGrab.grab()
    for x in range(xmin, xmax):
        for y in range(ymin,ymax):
            px = image.getpixel((x, y))
            if px[0] == r and px[1] == g and px[2] == b:
                return x, y

def FindColor(r,g,b):
    image = ImageGrab.grab()
    size = image.size
    pos = FindColorIn(r,g,b, 1, size[0], 1, size[1])
    return pos

Outcome:

Taken from the answers the normal methods of comparing two colors are in Euclidean distance, or Chebyshev distance.

I decided to mostly use (squared) euclidean distance, and multiple different color-spaces. LAB, deltaE (LCH), XYZ, HSL, and RGB. In my code, most color-spaces use squared euclidean distance to compute the difference.

For example with LAB, RGB and XYZ a simple squared euc. distance does the trick:

if ((X-X1)^2 + (Y-Y1)^2 + (Z-Z1)^2) <= (Tol^2) then
  ...

LCH, and HSL is a little more complicated as both have a cylindrical hue, but some piece of math solves that, then it's on to using squared eucl. here as well.

In most these cases I've added "separate parameters" for tolerance for each channel (using 1 global tolerance, and alternative "modifiers" HueTol := Tolerance * hueMod or LightTol := Tolerance * LightMod).


It seems like colorspaces built on top of XYZ (LAB, LCH) does perform best in many of my scenarios. Tho HSL yields very good results in some cases, and it's much cheaper to convert to from RGB, RGB is also great tho, and fills most of my needs.

like image 689
JHolta Avatar asked Jan 14 '12 17:01

JHolta


People also ask

How do you compare two colors?

The most common method would be a visual color comparison by looking at two physical color samples side by side under a light source. Color is very relative, so you can compare colors in terms of the other color across dimensions such as hue, lightness and saturation (brightness).

Is the Euclidean distance function a better or worse way to compare colors Why or why not?

No, the Euclidean distance in the RGB space does not correspond to the way the human eye perceives differences between colors. This is the entire reason that color spaces like Lab were created.


1 Answers

Computing distances between RGB colours, in a way that's meaningful to the eye, isn't as easy a just taking the Euclidian distance between the two RGB vectors.

There is an interesting article about this here: http://www.compuphase.com/cmetric.htm

The example implementation in C is this:

typedef struct {
   unsigned char r, g, b;
} RGB;

double ColourDistance(RGB e1, RGB e2)
{
  long rmean = ( (long)e1.r + (long)e2.r ) / 2;
  long r = (long)e1.r - (long)e2.r;
  long g = (long)e1.g - (long)e2.g;
  long b = (long)e1.b - (long)e2.b;
  return sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}

It shouldn't be too difficult to port to Python.

EDIT:

Alternatively, as suggested in this answer, you could use HLS and HSV. The colorsys module seems to have functions to make the conversion from RGB. Its documentation also links to these pages, which are worth reading to understand why RGB Euclidian distance doesn't really work:

  • http://www.poynton.com/ColorFAQ.html
  • http://www.cambridgeincolour.com/tutorials/color-space-conversion.htm

EDIT 2:

According to this answer, this library should be useful: http://code.google.com/p/python-colormath/

like image 133
Bruno Avatar answered Oct 17 '22 08:10

Bruno