That function expects decimal for s (saturation) and v (value), not percent. Divide by 100.
>>> import colorsys
# Using percent, incorrect
>>> test_color = colorsys.hsv_to_rgb(359,100,100)
>>> test_color
(100, -9900.0, -9900.0)
# Using decimal, correct
>>> test_color = colorsys.hsv_to_rgb(1,1,1)
>>> test_color
(1, 0.0, 0.0)
If you would like the non-normalized RGB tuple, here is a function to wrap the colorsys function.
def hsv2rgb(h,s,v):
return tuple(round(i * 255) for i in colorsys.hsv_to_rgb(h,s,v))
Example functionality
>>> hsv2rgb(0.5,0.5,0.5)
(64, 128, 128)
Answer from Cory Kramer on Stack OverflowThat function expects decimal for s (saturation) and v (value), not percent. Divide by 100.
>>> import colorsys
# Using percent, incorrect
>>> test_color = colorsys.hsv_to_rgb(359,100,100)
>>> test_color
(100, -9900.0, -9900.0)
# Using decimal, correct
>>> test_color = colorsys.hsv_to_rgb(1,1,1)
>>> test_color
(1, 0.0, 0.0)
If you would like the non-normalized RGB tuple, here is a function to wrap the colorsys function.
def hsv2rgb(h,s,v):
return tuple(round(i * 255) for i in colorsys.hsv_to_rgb(h,s,v))
Example functionality
>>> hsv2rgb(0.5,0.5,0.5)
(64, 128, 128)
If you like performance, it's best to avoid imports and use your own optimized code
Here's GIMP's code ported to python, tested at 99% acuracy, and improved for performance:
(this code happens to match colorsys almost exactly)
scalar = float # a scale value (0.0 to 1.0)
def hsv_to_rgb( h:scalar, s:scalar, v:scalar, a:scalar ) -> tuple:
if s:
if h == 1.0: h = 0.0
i = int(h*6.0); f = h*6.0 - i
w = v * (1.0 - s)
q = v * (1.0 - s * f)
t = v * (1.0 - s * (1.0 - f))
if i==0: return (v, t, w, a)
if i==1: return (q, v, w, a)
if i==2: return (w, v, t, a)
if i==3: return (w, q, v, a)
if i==4: return (t, w, v, a)
if i==5: return (v, w, q, a)
else: return (v, v, v, a)
output:
>>> hsv_to_rgb( 359/360.0, 1.0, 1.0, 1.0 )
(1.0, 0.0, 0.016666666666666607, 1.0)
Using an if-chain like above is actually faster than using elif
Using a wrapper, like in Cyber's answer, takes a few extra steps for the interpreter to perform.
To add, the for loop in Cyber's example is a real performance killer when used like that
If you want slightly more performance, simply do this:
(I won't say this is the best possible performance, but it's certainly better)
scalar = float # a scale value (0.0 to 1.0)
def hsv_to_rgb( h:scalar, s:scalar, v:scalar, a:scalar ) -> tuple:
a = int(255*a)
if s:
if h == 1.0: h = 0.0
i = int(h*6.0); f = h*6.0 - i
w = int(255*( v * (1.0 - s) ))
q = int(255*( v * (1.0 - s * f) ))
t = int(255*( v * (1.0 - s * (1.0 - f)) ))
v = int(255*v)
if i==0: return (v, t, w, a)
if i==1: return (q, v, w, a)
if i==2: return (w, v, t, a)
if i==3: return (w, q, v, a)
if i==4: return (t, w, v, a)
if i==5: return (v, w, q, a)
else: v = int(255*v); return (v, v, v, a)
^ this guarantees int() output with a range of 255 (the input is still the same)
>>> hsv_to_rgb( 359/360.0, 1.0, 1.0, 1.0 )
(255, 0, 4, 255)
NOTE: this code tests just as accurate as colorsys to GIMP (99% correct):
TIP: stay away from 3rd-party where possible, try the direct approach if you can.
exculusions: compiled C extensions such as PIL or NumPy, or ctypes wrappers such as PyOpenGL (uses the DLL)
Convert HSV to RGB
Converting HSV to RGB in Python - Stack Overflow
color - HSV to RGB conversion - Blender Stack Exchange
Function to Convert HSV to RGB, for better looking random & gradient colors!
Is color little pointless in OpenSCAD? Sure, maybe.. But it could also be the thing that makes your project preview visually stand out!
Problem is, if you've ever tried to do random or incremental gradient colors using RGB, it can often produces jarring, pale, or otherwise ugly color combinations. This is where HSV color format comes in handy. By specifying colors in HSV (Hue 0-360, Saturation 0-1, Value 0-1), you can get nice looking random or gradient colors every time.
Anyway, with the help of GPT-4, I converted a Python function I frequently use for HSV, into an OpenSCAD function! And it seems to work great, so I figured I'd share here. ;)
// Function to convert HSV color input to RGB output
function hsv2rgb(h, s=1, v=1) = let(
h = h / 360,
i = floor(h * 6),
f = h * 6 - i,
p = v * (1 - s),
q = v * (1 - f * s),
t = v * (1 - (1 - f) * s)
) i % 6 == 0 ? [v, t, p] :
i == 1 ? [q, v, p] :
i == 2 ? [p, v, t] :
i == 3 ? [p, q, v] :
i == 4 ? [t, p, v] :
[v, p, q];
Save as hsv2rgb.scad so you can easily reuse in other scripts via use <hsv2rgb.scad>
Here's an example of what you can do with it: https://i.imgur.com/gjzDFqL.png
And the code for that example:
use <hsv2rgb.scad>
for(i=[0:18:360]){
color(hsv2rgb(i, 1, 1))
rotate([0,0,i]) translate([-40,0,0]) scale([4,1.1,1])
cylinder(1,d=20,$fn=3);
}
text = "HSV in OpenSCAD!";
for (i = [0:len(text)-1]) {
color(hsv2rgb(floor(i/len(text)*360)))
translate([i*8-len(text)*8/2,70,1]) rotate([90,0,0])
linear_extrude(2)
text(text[i],font="DejaVu Sans Mono");
}Edit: Woops.. I just found out BOSL2 contains similar functionality. So now I feel a little silly. Oh well, still a neat compact function.

