Select to view content in your preferred language

ArcGIS python HSV to RGB colour conversion

2976
3
02-12-2024 07:06 PM
JohnMcGlynn
Regular Contributor

I am trying to populate 3 fields in a feature class with the symbology colour in RGB.
My conversion code takes the H, S and V values given by the layer.symbology.renderer.symbol.color function.

A sample of the output from the color function is:  {'HSV': [61, 50, 55, 100]}

The values must be munged to cater for the ArcGIS colour model ;

My code is:

    def colourHSVtoRGB(self,H,S,V):
        # The ArcGIS HSV model is strange - Hue 0-240, Saturation 0 - 255, Value 0 - 255
        from matplotlib.colors import hsv_to_rgb
        # Convert hval to 360 and make it 0 - 1
        hval = 3.6 * (H / 240)
        sval = S / 255
        vval = V / 255

        invals = [hval, sval, vval]
        rg = hsv_to_rgb(invals)
        R = rg[0]
        G = rg[1]
        B = rg[2]

        # Convert to 0 - 255
        R = int(round((R * 255), 0))
        G = int(round((G * 255), 0))
        B = int(round((B * 255), 0))

 

Unfortunately this gives the incorrect RGB values.

From a colour web site, the RGB for HSV = 61, 50, 55 should be 139, 140, 70, which also looks like the correct colour.

My function outputs RGB values;  49, 55, 44 - clearly wrong.
The input values to the matplotlib function are all 0 - 1. I'm sure my interpretation of the calculation for this input could use some improvement.

Thanks,

J

 

Tags (2)
3 Replies
JohnMcGlynn
Regular Contributor

I was able to fix this by using the algorithm at rapidtables.

Unlike the data given in the ESRI documentation (hue = 0 - 240, saturation = 0 - 255, value = 0 - 255) the actual HSV format is hue 0 - 360, saturation 0 - 100, value 0 - 100

The code is now:

    def colourHSVtoRGB(self,H,S,V):
        # The ArcGIS HSV model is - Hue 0-360, Saturation Pct, Value Pct
        # Algorithm from https://www.rapidtables.com/convert/color/hsv-to-rgb.html
        hval = H
        if hval == 360:
            hval = 0
        sval = S / 100
        vval = V / 100

        C = sval * vval
        tr = abs((hval / 60 % 2) - 1)
        X = C * (1 - tr)
        if 0 <= H and H < 60:
            R = C
            G = X
            B = 0
        elif 60 <= H and H < 120:
            R = X
            G = C
            B = 0
        elif 120 <= H and H < 180:
            R = 0
            G = C
            B = X
        elif 180 <= H and H < 240:
            R = 0
            G = X
            B = C
        elif 240 <= H and H < 300:
            R = X
            G = 0
            B = C
        elif 300 <= H and H < 360:
            R = C
            G = 0
            B = X

        m = vval - C
        R = int(round(255 * (R + m),0))
        G = int(round(255 * (G + m),0))
        B = int(round(255 * (B + m),0))

        return R, G, B

 John

Jeff-Reinhart
Frequent Contributor

Nice work! Thank you! You just saved me a mess of boring clicks. 🎉

0 Kudos
Jeff-Reinhart
Frequent Contributor

A small amendment. The hval var is set to H. Then if hval is 360, hval is set to zero.

The conditional does not allow H to be processed if it is still 360:

elif 300 <= H and H < 360

Thus R, G, B are never associated with a value if H is 360.

Replacing H with hval in the conditionals resolves this as so:

def colourHSVtoRGB(H,S,V):
    # The ArcGIS HSV model is - Hue 0-360, Saturation Pct, Value Pct
    # Algorithm from https://www.rapidtables.com/convert/color/hsv-to-rgb.html
    hval = H
    if hval == 360:
        hval = 0
    sval = S / 100
    vval = V / 100

    C = sval * vval
    tr = abs((hval / 60 % 2) - 1)
    X = C * (1 - tr)
    if 0 <= hval and hval < 60:
        R = C
        G = X
        B = 0
    elif 60 <= hval and hval < 120:
        R = X
        G = C
        B = 0
    elif 120 <= hval and hval < 180:
        R = 0
        G = C
        B = X
    elif 180 <= hval and hval < 240:
        R = 0
        G = X
        B = C
    elif 240 <= hval and hval < 300:
        R = X
        G = 0
        B = C
    elif 300 <= hval and hval < 360:
        R = C
        G = 0
        B = X

    m = vval - C
    R = int(round(255 * (R + m),0))
    G = int(round(255 * (G + m),0))
    B = int(round(255 * (B + m),0))

    return R, G, B
0 Kudos