Fast, optimized and accurate RGB <-> HSB conversion code in C

11,068

Solution 1

First off

HSB and HLS were developed to specify numerical Hue, Saturation and Brightness (or Hue, Lightness and Saturation) in an age when users had to specify colors numerically. The usual formulations of HSB and HLS are flawed with respect to the properties of color vision. Now that users can choose colors visually, or choose colors related to other media (such as PANTONE), or use perceptually-based systems like L*u*v* and L*a*b*, HSB and HLS should be abandoned [source]

Look at the opensource Java implementation here

Boost library (I know, it's C++) seemed to contains conversion to HSB at one time but nowadays I can only find a luminance conversion (here)

Solution 2

Here is a straightforward implementation in standard C.

This is - without further context - as good as it can get. Perhaps you care to shed some more light on

  • how you store your RGB samples (bits/pixel to begin with !?)
  • how you store your pixel data (do you want to efficiently transform larger buffers, if so, what is the organization)
  • how you want to represent the output (I assumed floats for now)

I could come up with a further optimized version (perhaps one that utilisze SSE4 instructions nicely...)

All that said, when compiled with optimizations, this doesn't work too badly:

#include <stdio.h>
#include <math.h>

typedef struct RGB_t { unsigned char red, green, blue; } RGB;
typedef struct HSB_t { float hue, saturation, brightness; } HSB;

/*
 * Returns the hue, saturation, and brightness of the color.
 */
void RgbToHsb(struct RGB_t rgb, struct HSB_t* outHsb)
{
    // TODO check arguments

    float r = rgb.red / 255.0f;
    float g = rgb.green / 255.0f;
    float b = rgb.blue / 255.0f;
    float max = fmaxf(fmaxf(r, g), b);
    float min = fminf(fminf(r, g), b);
    float delta = max - min;
    if (delta != 0)
    {
        float hue;
        if (r == max)
        {
            hue = (g - b) / delta;
        }
        else
        {
            if (g == max)
            {
                hue = 2 + (b - r) / delta;
            }
            else
            {
                hue = 4 + (r - g) / delta;
            }
        }
        hue *= 60;
        if (hue < 0) hue += 360;
        outHsb->hue = hue;
    }
    else
    {
        outHsb->hue = 0;
    }
    outHsb->saturation = max == 0 ? 0 : (max - min) / max;
    outHsb->brightness = max;
}

Typical usage and test:

int main()
{
    struct RGB_t rgb = { 132, 34, 255 };
    struct HSB_t hsb;

    RgbToHsb(rgb, &hsb);

    printf("RGB(%u,%u,%u) -> HSB(%f,%f,%f)\n", rgb.red, rgb.green, rgb.blue,
           hsb.hue, hsb.saturation, hsb.brightness);
    // prints: RGB(132,34,255) -> HSB(266.606354,0.866667,1.000000)

    return 0;
}

Solution 3

I would suggest using a lookup table to store the HSB and RGB values. First convert the RGB value (which is presumably 8 bits per component) to a 16-bit value (5 bits per component). The HSB values, also 16-bit values, can be converted in the same way, whereby here, the hue component should probably use more bits than the saturation and brightness, probably 8 bits per component, and the saturation and brightness 4 bits each. Of course, the reverse will apply when converting from HSB to RGB.

Share:
11,068

Related videos on Youtube

Cruachan
Author by

Cruachan

IT Consultant and Developer. Currently working mainly on web applications, but ongoing strong interest in spatial data systems, graphics and 3D visualization of all types. Real name if you want to talk to me is Kevin Woolley, but I've been using Cruachan as a handle since helping to run the #Delphi channel on IRC back in the mid-90's (although it's not a unique moniker unfortunately - possibly because it's such a great mountain to climb). 25 years IT experience in numerous business sectors. I've acquired a large cupboard of technologies - from Cobol to Python and OS/360 to iPhone OS with considerable experience as as DBA, Systems Analyst and Project Manager mixed in there too. Obsessive neophile always on the look out for new shiny to play with and still in love with coding - which is why I went Freelance a decade ago so I could make a living doing something I enjoy doing more than anything else. Most recently obsessing over how Python is a really neat language having just completed a medium-sized IronPython project, wondering if I can find any practical excuse to learn Haskell, and finally releasing iPad/iPhone applications (augmented reality!). Oh - and still on the look-out for the project that will make me a million :-)

Updated on June 04, 2022

Comments

  • Cruachan
    Cruachan almost 2 years

    I'm looking for a fast, accurate implementation of RGB to HSB and HSB to RGB in pure C. Note that I'm specifically looking for Hue, Saturation, Brightness and not HSL (Luminosity).

    Of course I have Googled this extensively, but speed is of the utmost importance here and I am looking for any specific recommendations for solid, fast, reliable code.

  • sehe
    sehe almost 13 years
    Good hints on optimization strategies. However, the trade off being made cannot be argued; the OP's requirements are too vague (fast, accurate implementation)
  • AldaronLau
    AldaronLau over 5 years
    Is this in sRGB or linear RGB?
  • AldaronLau
    AldaronLau over 5 years
    Figured it out en.wikipedia.org/wiki/… has the answer: HSV is based on the sRGB colorspace.