It’s time to see how to calculate difference between two colors.

I am using the **CIE1994** formula because it’s quite accurate and not that complex to calculate.

Here it is, assuming I have two colors in Lab format

where

(thanx to **Bruce Lindbloom**)

First, I am turning the scripts explained at Color difference algorithm into functions, this way:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
function rgb_to_xyz($rgb){ $red = $rgb[0]; $green = $rgb[1]; $blue = $rgb[2]; $_red = $red/255; $_green = $green/255; $_blue = $blue/255; if($_red>0.04045){ $_red = ($_red+0.055)/1.055; $_red = pow($_red,2.4); } else{ $_red = $_red/12.92; } if($_green>0.04045){ $_green = ($_green+0.055)/1.055; $_green = pow($_green,2.4); } else{ $_green = $_green/12.92; } if($_blue>0.04045){ $_blue = ($_blue+0.055)/1.055; $_blue = pow($_blue,2.4); } else{ $_blue = $_blue/12.92; } $_red *= 100; $_green *= 100; $_blue *= 100; $x = $_red * 0.4124 + $_green * 0.3576 + $_blue * 0.1805; $y = $_red * 0.2126 + $_green * 0.7152 + $_blue * 0.0722; $z = $_red * 0.0193 + $_green * 0.1192 + $_blue * 0.9505; return(array($x,$y,$z)); } |

and…

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
function xyz_to_lab($xyz){ $x = $xyz[0]; $y = $xyz[1]; $z = $xyz[2]; $_x = $x/95.047; $_y = $y/100; $_z = $z/108.883; if($_x>0.008856){ $_x = pow($_x,1/3); } else{ $_x = 7.787*$_x + 16/116; } if($_y>0.008856){ $_y = pow($_y,1/3); } else{ $_y = (7.787*$_y) + (16/116); } if($_z>0.008856){ $_z = pow($_z,1/3); } else{ $_z = 7.787*$_z + 16/116; } $l= 116*$_y -16; $a= 500*($_x-$_y); $b= 200*($_y-$_z); return(array($l,$a,$b)); } |

Now, it’s time to determine color difference, using the above formula:

1 2 3 4 5 6 7 8 9 10 11 12 13 |
function de_1994($lab1,$lab2){ $c1 = sqrt($lab1[1]*$lab1[1]+$lab1[2]*$lab1[2]); $c2 = sqrt($lab2[1]*$lab2[1]+$lab2[2]*$lab2[2]); $dc = $c1-$c2; $dl = $lab1[0]-$lab2[0]; $da = $lab1[1]-$lab2[1]; $db = $lab1[2]-$lab2[2]; $dh = sqrt(($da*$da)+($db*$db)-($dc*$dc)); $first = $dl; $second = $dc/(1+0.045*$c1); $third = $dh/(1+0.015*$c1); return(sqrt($first*$first+$second*$second+$third*$third)); } |

And you’ll find the difference between colors.

Next time, a real application using all this boring theory… (you will be surprised…)

#### Want to learn more? Learn by example!

Get the full commented source code of an actual commercial cross platform HTML5 game!!

## Comments 12

great snippet … i will love to see a function that can generate lighter or darker color by a given color value through parameter

this will be very handy when we want to auto generate color themes bye given color value by user

Pingback: How to Choose Colours Procedurally (Algorithms) ยป devmag.org.za

I trying to transfer this code to pascal. I don’t understan the following operation:

$_red *= 100;

$_green *= 100;

$_blue *= 100;

Could you explain to me?

This is frickin’ awesome.I ported it to Actionscript.

I tried the RGB distance method which worked ok, but had some errors. Then i tried converting to HSB which worked well for the RGB errors but has some other error.

This algorithm is sweet!

Eduardo it means that the variable is set to its current value times 100;

i.e. red=2;

red*=100; (red is now 200, all further code that uses the variable “red” will now use 200 rather than 2);

Thanks for great snippet Emanuele !

Just one point – shouldn’t be used abs(…) for all delta computations in de_1994() ?

Thanks anyway !

Thanks for explaining this stuff, and for your snippets of code )

I’d like to use those snippets in our project, but in your post you don’t mention it anywhere, so can I ask you if it’s okay to reuse them? And if so, can you please put a license note on them, so they will be legally accessible?

Author

Hello Igor,

use it as you want, there’s no restriction, ok?

Thanks for this, it saved me A LOT of time.

I had to change Line 8 of de_1994 to $dh = sqrt(abs(($da*$da)+($db*$db)-($dc*$dc)));

Change line 8 of de_1994 to:

$dh = sqrt(($da*$da)+($db*$db)+($dc*$dc));

You are going to kill me!!! Ignore the nonsense I posted earlier…

Change line 8 of de_1994 to:

$dh = ($da * $da) + ($db * $db) – ($dc * $dc);

if ($dh < 0) { $dh = 0; } else { $dh = sqrt($dh); }

I guess the problem is an excessively large delta C resulting in a sqrt of a negative number. This was causing NaN on many comparisons.

Where’s the next part? I want to see how these functions are used!