Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HSV to RGB Color Conversion

Is there a way to convert HSV color arguments to RGB type color arguments using pygame modules in python? I tried the following code, but it returns ridiculous values.

import colorsys
test_color = colorsys.hsv_to_rgb(359, 100, 100)
print(test_color)

and this code returns the following nonsense

(100, -9900.0, -9900.0)

This obviously isn't RGB. What am I doing wrong?

like image 567
AvZ Avatar asked Jul 20 '14 16:07

AvZ


People also ask

Can HSV color be converted to RGB?

RGB = hsv2rgb( HSV ) converts the hue, saturation, and value (HSV) values of an HSV image to red, green, and blue values of an RGB image. rgbmap = hsv2rgb( hsvmap ) converts an HSV colormap to an RGB colormap.

Which method is used to convert RGB color to HSV?

HSV = rgb2hsv( RGB ) converts the red, green, and blue values of an RGB image to hue, saturation, and value (HSV) values of an HSV image. hsvmap = rgb2hsv( rgbmap ) converts an RGB colormap to an HSV colormap.

How do you convert HSV to RGB in Python?

To convert HSV color values to RGB color values in Python, import colorsys library, call hsv_to_rgb() function, and pass the Hue, Saturation, and Value values as arguments. hsv_to_rgb() function takes Hue, Saturation, and Value values as arguments, and returns a tuple containing Red, Blue, and Green values.


6 Answers

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)
like image 139
Cory Kramer Avatar answered Oct 04 '22 10:10

Cory Kramer


If you like performance, it's best to avoid imports and use your own optimized code

Here's the exact code from colorsys slightly modified to make the byte-code slightly faster:

    def hsv_to_rgb(h, s, v):
        if s == 0.0: return (v, v, v)
        i = int(h*6.) # XXX assume int() truncates!
        f = (h*6.)-i; p,q,t = v*(1.-s), v*(1.-s*f), v*(1.-s*(1.-f)); i%=6
        if i == 0: return (v, t, p)
        if i == 1: return (q, v, p)
        if i == 2: return (p, v, t)
        if i == 3: return (p, q, v)
        if i == 4: return (t, p, v)
        if i == 5: return (v, p, q)

output:

>>> hsv_to_rgb(359,1,1)
[1, 0.0, 0.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)

    def hsv_to_rgb(h, s, v):
        if s == 0.0: v*=255; return (v, v, v)
        i = int(h*6.) # XXX assume int() truncates!
        f = (h*6.)-i; p,q,t = int(255*(v*(1.-s))), int(255*(v*(1.-s*f))), int(255*(v*(1.-s*(1.-f)))); v*=255; i%=6
        if i == 0: return (v, t, p)
        if i == 1: return (q, v, p)
        if i == 2: return (p, v, t)
        if i == 3: return (p, q, v)
        if i == 4: return (t, p, v)
        if i == 5: return (v, p, q)

^ this guarantees int() output with a range of 255 (the input is still the same)

>>> hsv_to_rgb(359./360.,1,1)
(255, 0, 0)

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)

like image 23
Tcll Avatar answered Oct 03 '22 10:10

Tcll


The Hue argument should also vary from 0-1.

import colorsys
test_color = colorsys.hsv_to_rgb(359/360.0, 1, 1)
like image 45
Paul Beloff Avatar answered Oct 04 '22 10:10

Paul Beloff


I have prepared a vectorized version, it is cca 10x faster

def hsv_to_rgb(h, s, v):
    shape = h.shape
    i = int_(h*6.)
    f = h*6.-i

    q = f
    t = 1.-f
    i = ravel(i)
    f = ravel(f)
    i%=6

    t = ravel(t)
    q = ravel(q)

    clist = (1-s*vstack([zeros_like(f),ones_like(f),q,t]))*v

    #0:v 1:p 2:q 3:t
    order = array([[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]])
    rgb = clist[order[i], arange(prod(shape))[:,None]]

    return rgb.reshape(shape+(3,))
like image 27
Tomas Avatar answered Oct 03 '22 10:10

Tomas


If you are working with Numpy arrays then matplotlib.colors.hsv_to_rgb is quite direct:

import numpy as np
from matplotlib.colors import hsv_to_rgb
# This will create a nice image of varying hue and value
hsv = np.zeros((512, 512, 3))
hsv[..., 0] = np.linspace(0, 1, 512)
hsv[..., 1] = 1.
hsv[..., 2] = np.linspace(0, 1, 512)[:, np.newaxis]
rgb = hsv_to_rgb(hsv)

Note that the input and output images have values in the range [0, 1].

like image 41
buzjwa Avatar answered Oct 02 '22 10:10

buzjwa


Since the question is tagged pygame, I want to mention that PyGame allows conversion between color schemes. The pygame.Color object can be used to convert between the RGB and HSL/HSV color schemes.

The hsva property:

Gets or sets the HSVA representation of the Color. The HSVA components are in the ranges H = [0, 360], S = [0, 100], V = [0, 100], A = [0, 100].

hsva = pygame.Color((red, green, blue, alpha)).hsva
color = pygame.Color(0)
color.hsva = (hue, saturation, value, alpha)
rgba = (color.r, color.g, color.b, color.a)

The hsla property:

Gets or sets the HSLA representation of the Color. The HSLA components are in the ranges H = [0, 360], S = [0, 100], V = [0, 100], A = [0, 100].

hsla = pygame.Color((red, green, blue, alpha)).hsla
color = pygame.Color(0)
color.hsla = (hue, saturation, lightness, alpha)
rgba = (color.r, color.g, color.b, color.a)

Minimal example:

import pygame

pygame.init()

window = pygame.display.set_mode((450, 300))
clock = pygame.time.Clock()

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.fill((255, 255, 255))
    w, h = window.get_size()
    for i in range(6):
        color = pygame.Color(0)
        color.hsla = (i * 60, 100, 50, 100)
        pygame.draw.circle(window, color, 
            (w//6 + w//3 * (i%3), h//4 + h//2 * (i//3)), 
            round(min(window.get_width() * 0.16, window.get_height() * 0.2)))

    pygame.display.flip()

pygame.quit()
exit()
like image 45
Rabbid76 Avatar answered Oct 02 '22 10:10

Rabbid76