Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Incorrect saturation calculation in RGB to HSL function

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.

like image 302
TheCarver Avatar asked Jul 25 '12 23:07

TheCarver


1 Answers

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;
like image 88
OmnipotentEntity Avatar answered Oct 16 '22 08:10

OmnipotentEntity