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 the Photoshop operation called “Hue/saturation”: this is to change the color of the image uniformly as shown below:
- Original:
- With hue adjusted to +180 (red):
- With hue adjusted to -78 (green):
FYI, Photoshop uses a scale of -180 to +180 for this hue setting (where -180 equals +180), that may represents the HSL hue scale (expressed in 0-360 degree).
What I'm looking for is a function that, given an PIL image and a float hue within [0, 1] (or int within [0, 360], it doesn't matter), returns the image with its hue shifted by hue as in the example above.
What I've done so far is ridiculous and obviously doesn't give the desired result. It just half-blend my original image with a color-filled layer.
import Image
im = Image.open('tweeter.png')
layer = Image.new('RGB', im.size, 'red') # "hue" selection is done by choosing a color...
output = Image.blend(im, layer, 0.5)
output.save('output.png', 'PNG')
(Please-don't-laugh-at-) result:
Thanks in advance!
Solution: here is the unutbu code updated so it fits exactly what I've described.
import Image
import numpy as np
import colorsys
rgb_to_hsv = np.vectorize(colorsys.rgb_to_hsv)
hsv_to_rgb = np.vectorize(colorsys.hsv_to_rgb)
def shift_hue(arr, hout):
r, g, b, a = np.rollaxis(arr, axis=-1)
h, s, v = rgb_to_hsv(r, g, b)
h = hout
r, g, b = hsv_to_rgb(h, s, v)
arr = np.dstack((r, g, b, a))
return arr
def colorize(image, hue):
"""
Colorize PIL image `original` with the given
`hue` (hue within 0-360); returns another PIL image.
"""
img = image.convert('RGBA')
arr = np.array(np.asarray(img).astype('float'))
new_img = Image.fromarray(shift_hue(arr, hue/360.).astype('uint8'), 'RGBA')
return new_img
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.
There is Python code to convert RGB to HSV (and vice versa) in the colorsys module in the standard library. My first attempt used
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
andcolorsys.hsv_to_rgb
into native numpy operations.yields
and
With a recent copy of Pillow, one should probably use