Does anybody know the correct formula to get the saturation level from an RGB color?
I already have a function that does it. I've tried loads of them posted on the internet but only this one seemed to work (first-time) for me, apart from the saturation level being occasionally slightly out.
rgb(204,153,51)
should equal hsl(40,60,50)
, instead I have hsl(40,75,50)
. As you can see my hue and lightness are correct, in-fact, the saturation is mostly correct too, but sometimes it's not and I need to correct that if I can.
This is what I've built so far, so I can check all the color values are correct for my images, before storing them in a database for my search engine.
And this is the function in question where I believe the saturation is being calculated incorrectly:
function RGBtoHSL($red, $green, $blue)
{
$r = $red / 255.0;
$g = $green / 255.0;
$b = $blue / 255.0;
$H = 0;
$S = 0;
$V = 0;
$min = min($r,$g,$b);
$max = max($r,$g,$b);
$delta = ($max - $min);
$L = ($max + $min) / 2.0;
if($delta == 0) {
$H = 0;
$S = 0;
} else {
$S = $delta / $max;
$dR = ((($max - $r) / 6) + ($delta / 2)) / $delta;
$dG = ((($max - $g) / 6) + ($delta / 2)) / $delta;
$dB = ((($max - $b) / 6) + ($delta / 2)) / $delta;
if ($r == $max)
$H = $dB - $dG;
else if($g == $max)
$H = (1/3) + $dR - $dB;
else
$H = (2/3) + $dG - $dR;
if ($H < 0)
$H += 1;
if ($H > 1)
$H -= 1;
}
$HSL = ($H*360).', '.($S*100).', '.round(($L*100),0);
return $HSL;
}
One clue I have, as to why this doesn't work 100%, is that I'm first converting a HEX color to an RGB, then the RGB to an HSL. Would this be a problem due to web-safe colors or can you spot anything else that may cause this in the function? Or is this just how it is?
UPDATE 1
Trying other images, it appears to be mostly 'beige' (approx.) colors that are slightly out on saturation. Using a color picker, if I move the saturation bar to where it should be there isn't a huge difference, so maybe my search feature won't pick up on this too much. It would be nice to solve it though, before I run it on 500,000 photos.
THE FIX
Thanks to OmnipotentEntity, below, he noticed I missing piece to my function. I changed:
$S = $delta / $max;
to:
$S = $L > 0.5 ? $delta / (2 - $max - $min) : $delta / ($max + $min);
and now produces 100% correct results.
FRIENDLY NOTE
If anybody would like the code to produce this color table, just ask.
It looks like you’re missing a piece of the calculation for saturation if your luma is > .5 as shown here in this JavaScript HSL code.
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With