Question

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.

enter image description here

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.

Was it helpful?

Solution

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top