Changing image hue with Python PIL

前端 未结 3 675
野趣味
野趣味 2020-11-27 04:40

Using Python PIL, I\'m trying to adjust the hue of a given image.

I\'m not very comfortable with the jargon of graphics, so what I mean by “adjusting hue” is doing t

相关标签:
3条回答
  • 2020-11-27 05:16

    There is Python code to convert RGB to HSV (and vice versa) in the colorsys module in the standard library. My first attempt used

    rgb_to_hsv=np.vectorize(colorsys.rgb_to_hsv)
    hsv_to_rgb=np.vectorize(colorsys.hsv_to_rgb)
    

    to vectorize those functions. Unfortunately, using np.vectorize results in rather slow code.

    I was able to obtain roughly a 5 times speed up by translating colorsys.rgb_to_hsv and colorsys.hsv_to_rgb into native numpy operations.

    import Image
    import numpy as np
    
    def rgb_to_hsv(rgb):
        # Translated from source of colorsys.rgb_to_hsv
        # r,g,b should be a numpy arrays with values between 0 and 255
        # rgb_to_hsv returns an array of floats between 0.0 and 1.0.
        rgb = rgb.astype('float')
        hsv = np.zeros_like(rgb)
        # in case an RGBA array was passed, just copy the A channel
        hsv[..., 3:] = rgb[..., 3:]
        r, g, b = rgb[..., 0], rgb[..., 1], rgb[..., 2]
        maxc = np.max(rgb[..., :3], axis=-1)
        minc = np.min(rgb[..., :3], axis=-1)
        hsv[..., 2] = maxc
        mask = maxc != minc
        hsv[mask, 1] = (maxc - minc)[mask] / maxc[mask]
        rc = np.zeros_like(r)
        gc = np.zeros_like(g)
        bc = np.zeros_like(b)
        rc[mask] = (maxc - r)[mask] / (maxc - minc)[mask]
        gc[mask] = (maxc - g)[mask] / (maxc - minc)[mask]
        bc[mask] = (maxc - b)[mask] / (maxc - minc)[mask]
        hsv[..., 0] = np.select(
            [r == maxc, g == maxc], [bc - gc, 2.0 + rc - bc], default=4.0 + gc - rc)
        hsv[..., 0] = (hsv[..., 0] / 6.0) % 1.0
        return hsv
    
    def hsv_to_rgb(hsv):
        # Translated from source of colorsys.hsv_to_rgb
        # h,s should be a numpy arrays with values between 0.0 and 1.0
        # v should be a numpy array with values between 0.0 and 255.0
        # hsv_to_rgb returns an array of uints between 0 and 255.
        rgb = np.empty_like(hsv)
        rgb[..., 3:] = hsv[..., 3:]
        h, s, v = hsv[..., 0], hsv[..., 1], hsv[..., 2]
        i = (h * 6.0).astype('uint8')
        f = (h * 6.0) - i
        p = v * (1.0 - s)
        q = v * (1.0 - s * f)
        t = v * (1.0 - s * (1.0 - f))
        i = i % 6
        conditions = [s == 0.0, i == 1, i == 2, i == 3, i == 4, i == 5]
        rgb[..., 0] = np.select(conditions, [v, q, p, p, t, v], default=v)
        rgb[..., 1] = np.select(conditions, [v, v, v, q, p, p], default=t)
        rgb[..., 2] = np.select(conditions, [v, p, t, v, v, q], default=p)
        return rgb.astype('uint8')
    
    
    def shift_hue(arr,hout):
        hsv=rgb_to_hsv(arr)
        hsv[...,0]=hout
        rgb=hsv_to_rgb(hsv)
        return rgb
    
    img = Image.open('tweeter.png').convert('RGBA')
    arr = np.array(img)
    
    if __name__=='__main__':
        green_hue = (180-78)/360.0
        red_hue = (180-180)/360.0
    
        new_img = Image.fromarray(shift_hue(arr,red_hue), 'RGBA')
        new_img.save('tweeter_red.png')
    
        new_img = Image.fromarray(shift_hue(arr,green_hue), 'RGBA')
        new_img.save('tweeter_green.png')
    

    yields

    enter image description here

    and

    enter image description here

    0 讨论(0)
  • 2020-11-27 05:27

    With a recent copy of Pillow, one should probably use Image.convert():

    def rgb2hsv(image: PIL.Image.Image):
        return image.convert('HSV')
    
    0 讨论(0)
  • 2020-11-27 05:29

    Good question. PIL does not convert to to a HSV or HSL colorspace, but this is the conversion you need to do in order to alter the hue without any changes to the lightness and saturation of the image.

    What you need to do is convert to HSV, then increment all the H values by some degree, then convert back to RGB.

    Half the work is done for you in an answer (by me) some time ago. It employs another python module called NumPy and converts RGB colorspace to HSV. It would not be too much trouble to write the reverse conversion.

    0 讨论(0)
提交回复
热议问题