Changing image hue with Python PIL

前端 未结 3 771
野趣味
野趣味 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

提交回复
热议问题