Sign in to follow this  
Dark Star

Algorithm to compare the likeness of or distance between two colours

Recommended Posts

Hi Gamedev, was just wandering if anyone knew of or could point me in the direction of any algorithms that can compare how alike two colours are like in a percentage or scale value or the distance between each one based on their rgb components. For example say I have a method called compare() I would use it like this likeness = compareColour(0xFF0000,0xFFFF00) the value in likeness could be a percentage or something else maybe Just wandering. Thanks in advance. DarkStar UK

Share this post


Link to post
Share on other sites
I'd be tempted to simply use the euclidean distance in [0,1]3. Then, you could go looking for a chart determining ocular precision (which is greater in some areas of the cube, and smaller in others) and scale your distance based on this.

Then again, any distance is a valid distance in theory. Now, if you need specific properties to be true for that distance...

Share this post


Link to post
Share on other sites
It depends on what you mean by alike. For general purposes, just take the colors as 3D vectors and take the Euclidean distance between them as mentioned by ToohrVyk. Since RGB is an orthogonal space, it should be generally OK.

However, RGB is not a perceptually uniform space to human eyes (which is I think what ToohrVyk was getting at with ocular precision). Two colors that are an equal distance away from white might not look equally different from white, if that makes sense. Logluv is a perceptually uniform color space, if you really need it, but chances are all of this is overkill and RGB distance is good enough.

Share this post


Link to post
Share on other sites
maybe something like this, just a weighted euclidean distance...

(r1,g1,b1 and r2,g2,b2 float channels for the two colours)

float r3 = r1 - r2;
float g3 = g1 - g2;
float b3 = b1 - b2;

return sqrt( 0.2126f * r3 * r3 + 0.7152f * g3 * g3 + 0.0722f * b3 * b3 );

Share this post


Link to post
Share on other sites
I think the best you could do would be to convert from RGB to YUV, and then take the Eucledian distance as proposed above. A bit pseudo-code:
Y = 0.299R + 0.587G + 0.114B;
U = 0.492(B - Y);
V = 0.877(R - Y);
clamp( Y, 0, 255 );
clamp( U, 0, 255 );
clamp( V, 0, 255 );

dist = sqrt( (Y1-Y2)*(Y1-Y2) + (U1-U2)*(U1-U2) + (V1-V2)*(V1-V2) );


Share this post


Link to post
Share on other sites
Hi,

Just done this myself.

As others have stated a simple weighting/distance check will work, although you can drop the squareroot since you're comparing the same things. You may also want to try doing this with luminace and not actual colours, depending on the 'type' of matches you are looking for.

Also don't get fooled into checking for a 'near' distance fit, as this can lead to poor results. For example if you use (r*r)+(g*g)+(b*b) < 15 then both a colour that is 15 units out on the red, but not green or blue, will pass just as if each red,green,blue is out say 3 units each - i.e its the overall closeness of the components that is examined, not the closeness on a per component basis. So always look for a 'bestfit' its slower, but you'll get better results.


If you want to get more advanced have a look at Colour Metric and the C code snippet on that page. You might also want to browse through the colour space FAQ

Share this post


Link to post
Share on other sites
Quote:
Orignial post by noisecrime
Also don't get fooled into checking for a 'near' distance fit, as this can lead to poor results. For example if you use (r*r)+(g*g)+(b*b) < 15 then both a colour that is 15 units out on the red, but not green or blue, will pass just as if each red,green,blue is out say 3 units each - i.e its the overall closeness of the components that is examined, not the closeness on a per component basis. So always look for a 'bestfit' its slower, but you'll get better results.



This my thought when I first read the OP. Here's what I came up with just now as something that might work:


int r, g, b;

r = abs(r1 - r2);
g = abs(g1 - g2);
b = abs(b1 - b2);

if (r / 100 > 5)
return false;
if (g / 100 > 5)
return false;
if (b / 100 > 5)
return false;

return true;


This checks that all component values are within 5 percent and returns false otherwise. Hope this help you out some [smile].

-AJ

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this