I'm currently trying to convert hsl color codes to hsv and vice versa in Python, but can't find an easy way to do this.
I tried converting the codes indirectly by converting hsl to rgb and rgb to hsv using the colorsys
package. Unfortunately, this doesn't seem to work for some reason. I always get incredibly small values (< 0
, so that doesn't make any sense).
Here's what I did:
import colorsys
def hsv_to_hsl(hsv):
h, s, v = hsv
rgb = colorsys.hsv_to_rgb(h, s, v)
r, g, b = rgb
hls = colorsys.rgb_to_hls(r, g, b)
return hls
hsv = (300, 65, 40)
print(hsv)
print(hsv_to_hsl(hsv))
I also tried writing my own function based on a JavaScript function I found on GitHub, but I get the same weird values there (see code for converting hsv to hsl below). The problem is I don't really get the formula on Wikipedia, so to be honest I don't even know if what I computed below makes any sense.
import math
def hsv_to_hsl(hsv):
h, sat, val = hsv
# hue h stays the same
# saturation s
if (2-sat)*val < 1:
s = sat*val / ((2-sat)*val)
else: s = sat*val / (2-(2-sat)*val)
# lightness l
l = 2-sat * val/2
# return code as tuple
return (h, s, l)
Is there an easy way to do this using a package or do you have an idea of what I could do differently in my function?
You need to make sure to normalize the values according to the matching ranges. According to your values (and the range hints in this website), it seems you're using values of H in the range [0, 360]
; S and V in the range [0, 100]
. On the other hand, the built-in library colorsys
uses all [0, 1]
ranges. So a bit of normalization will give you the required results:
import colorsys
def hsv_to_hsl(hsv):
h, s, v = hsv
rgb = colorsys.hsv_to_rgb(h/360, s/100, v/100)
r, g, b = rgb
h, l, s = colorsys.rgb_to_hls(r, g, b)
return h*360, s*100, l*100
hsv = (300, 65, 40)
print(hsv)
print(hsv_to_hsl(hsv))
Now gives the expected:
(300, 65, 40)
(300.0, 48.148148148148145, 27.0)
If you are looking for a manual implementation, you can use the algorithm described here (now the values are: H in range [0, 360]
and S,V and L are in [0, 1]
):
def hsv_to_hsl(hsv):
h, s, v = hsv
l = v * (1 - s/2)
s = 0 if l in (0, 1) else (v - l)/min(l, 1-l)
return h, s, l
def hsl_to_hsv(hsl):
h, s, l = hsl
v = l + s * min(l, 1-l)
s = 0 if v == 0 else 2*(1 - l/v)
return h, s, v
To compare the result with colorsys
:
h, s, l = (300, 48.148, 27)
custom = hsl_to_hsv((h, s/100, l/100))
print("Custom function: ", custom[0], custom[1]*100, custom[2]*100)
expected = colorsys.rgb_to_hsv(*colorsys.hls_to_rgb(h/360, l/100, s/100))
print("Expected result: ", expected[0]*360, expected[1]*100, expected[2]*100)
Indeed gives:
Custom function: 300 64.99986499986498 39.99996
Expected result: 300.0 64.999864999865 39.99996