Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HSV to RGB (and back) without floating point math in Python

Tags:

python

rgb

hsv

Anyone know of a good python algorithm for converting HSV color to RGB (and vice versa) that doesn't depend on any external modules? I'm working on some animation generation code and want to support the HSV colorspace, but it's running on a Raspberry Pi and I'm trying to avoid any floating point.

like image 210
Adam Haile Avatar asked Oct 18 '25 23:10

Adam Haile


1 Answers

This site here takes you through the steps, including how to do it using integer division. Here is a python port of the RGB to HSV function described in there

def RGB_2_HSV(RGB):
    ''' Converts an integer RGB tuple (value range from 0 to 255) to an HSV tuple '''

    # Unpack the tuple for readability
    R, G, B = RGB

    # Compute the H value by finding the maximum of the RGB values
    RGB_Max = max(RGB)
    RGB_Min = min(RGB)

    # Compute the value
    V = RGB_Max;
    if V == 0:
        H = S = 0
        return (H,S,V)


    # Compute the saturation value
    S = 255 * (RGB_Max - RGB_Min) // V

    if S == 0:
        H = 0
        return (H, S, V)

    # Compute the Hue
    if RGB_Max == R:
        H = 0 + 43*(G - B)//(RGB_Max - RGB_Min)
    elif RGB_Max == G:
        H = 85 + 43*(B - R)//(RGB_Max - RGB_Min)
    else: # RGB_MAX == B
        H = 171 + 43*(R - G)//(RGB_Max - RGB_Min)

    return (H, S, V)

Which gives correct results when compared to the colorsys functions

import colorsys
RGB = (127, 127, 127)

Converted_2_HSV = RGB_2_HSV(RGB)
Verify_RGB_2_HSV = colorsys.rgb_to_hsv(RGB[0], RGB[1], RGB[2])

print Converted_2_HSV
>>> (0, 0, 127)

print Verify_RGB_2_HSV # multiplied by 255 to bring it into the same scale
>>> (0.0, 0.0, 127.5)

And you can check that the output is still in fact an integer

type(Converted_2_HSV[0])
>>> <type 'int'>

Now for the reverse function. The original source can be found here, and here is the Python port.

def HSV_2_RGB(HSV):
    ''' Converts an integer HSV tuple (value range from 0 to 255) to an RGB tuple '''

    # Unpack the HSV tuple for readability
    H, S, V = HSV

    # Check if the color is Grayscale
    if S == 0:
        R = V
        G = V
        B = V
        return (R, G, B)

    # Make hue 0-5
    region = H // 43;

    # Find remainder part, make it from 0-255
    remainder = (H - (region * 43)) * 6; 

    # Calculate temp vars, doing integer multiplication
    P = (V * (255 - S)) >> 8;
    Q = (V * (255 - ((S * remainder) >> 8))) >> 8;
    T = (V * (255 - ((S * (255 - remainder)) >> 8))) >> 8;


    # Assign temp vars based on color cone region
    if region == 0:
        R = V
        G = T
        B = P
    
    elif region == 1:
        R = Q; 
        G = V; 
        B = P;

    elif region == 2:
        R = P; 
        G = V; 
        B = T;

    elif region == 3:
        R = P; 
        G = Q; 
        B = V;

    elif region == 4:
        R = T; 
        G = P; 
        B = V;

    else: 
        R = V; 
        G = P; 
        B = Q;


    return (R, G, B)

And we can verify the result in the same way as before

interger_HSV = (127, 127, 127)
Converted_2_RGB = HSV_2_RGB(interger_HSV)
Verify_HSV_2_RGB = colorsys.hsv_to_rgb(0.5, 0.5, 0.5)

print Converted_2_RGB
>>> (63, 127, 124)

print type(Converted_2_RGB[0])
>>> <type 'int'>

print Verify_HSV_2_RGB # multiplied these by 255 so they are on the same scale
>>> (63.75, 127.5, 127.5)

The integer arithmetic does introduce some errors, however depending on the application these might be ok.

like image 94
Ashok Fernandez Avatar answered Oct 21 '25 12:10

Ashok Fernandez



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!