algorithmcolorsrgbcolor-spacehsl

Double cone model of HSI Color Space to RGB


I've come across a rather trigonometric implementation for converting colours from RGB to HSI. In particular, converting from RGB to the "HSI-colour space, given by a double cone", which I presume is another name for the bi-hexcone model of HSL.

The authors describe equations for "their preferred choice of transformation" of RGB-->HSI, which I have implemented in Python as below. Nothing is given the reverse transformation, HSI-->RGB.

def rgb_to_hsi(r, g, b):
    # r, g, b in [0..1]
    x = min(r, g, b)
    y = max(r, g, b)
    I = (x + y) / 2.0
    S = y - x
    c1 = r - (g + b) / 2.0
    c2 = (np.sqrt(3) * (b - g)) / 2.0
    H = np.arctan2(c2, c1)
    H = np.mod(-H, 2 * pi) # re-range to [0..2PI], rotating from red at 0 to green at 2/3PI, etc.

    return [H, S, I] # H in [0..2PI], S in [0..1], I in [0..1]

Both the algorithm and my implementation seem to be correct, and provide results that accord with this diagram (i.e. red (rgb(1,0,0)) gives [0.0, 1, 0.5]):

enter image description here

But I'm unable to find, or derive, a working inverse of this conversion – a hsi_to_rgb() method.

I've tried a few implementations but they tend to map hsi(0.0, 1, 0.5) to rgb(0.5, 0, 0) (red at half brightness, rather than full).

I suspect this is because most HSL implementations use the cylindrical model of HSL, and not the double cone model – is this true?

Either way, what is a working (and ideally trigonometric) algorithm for converts from the HSL double cone model to rgb?


Solution

  • Here you go:

    SQRT3BY2 = math.sqrt(3)/2.0
    
    def hsi_to_rgb(H, S, I):
        c2 = math.sin(-H)*SQRT3BY2
        c1 = math.cos(-H)
        # (r,g,b) = A*c1*(1, -.5, -.5) + A*c2*(0, -1, 1) + B*(1,1,1)
        r = c1
        g = c1*-0.5 - c2
        b = c1*-0.5 + c2
        # multiply to match S
        fac = S/(max(r,g,b)-min(r,g,b))
        r *= fac
        g *= fac
        b *= fac
        # add white to match I
        x = I - (S / 2.0)
        w = x - min(r,g,b)
        r += w
        g += w
        b += w
        return [r, g, b]