Python - Find similar colors, best way

Instead of this:

if px[0] == r and px[1] == g and px[2] == b:

Try this:

if max(map(lambda a,b: abs(a-b), px, (r,g,b))) < tolerance:

Where tolerance is the maximum difference you're willing to accept in any of the color channels.

What it does is to subtract each channel from your target values, take the absolute values, then the max of those.


Here is an optimized Python version adapted from Bruno's asnwer:

def ColorDistance(rgb1,rgb2):
    '''d = {} distance between two colors(3)'''
    rm = 0.5*(rgb1[0]+rgb2[0])
    d = sum((2+rm,4,3-rm)*(rgb1-rgb2)**2)**0.5
    return d

usage:

>>> import numpy
>>> rgb1 = numpy.array([1,1,0])
>>> rgb2 = numpy.array([0,0,0])
>>> ColorDistance(rgb1,rgb2)
2.5495097567963922

Assuming that rtol, gtol, and btol are the tolerances for r,g, and b respectively, why not do:

if abs(px[0]- r) <= rtol and \
   abs(px[1]- g) <= gtol and \
   abs(px[2]- b) <= btol:
    return x, y

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/