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]
):
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?
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]