This solution is based on Paul's code. I fixed DivByZero Bug and implemented RGB to HSL. There is also HSL to RGB:
import numpy
def rgb_to_hsl_hsv(a, isHSV=True):
"""
Converts RGB image data to HSV or HSL.
:param a: 3D array. Retval of numpy.asarray(Image.open(...), int)
:param isHSV: True = HSV, False = HSL
:return: H,S,L or H,S,V array
"""
R, G, B = a.T
m = numpy.min(a, 2).T
M = numpy.max(a, 2).T
C = M - m #chroma
Cmsk = C != 0
# Hue
H = numpy.zeros(R.shape, int)
mask = (M == R) & Cmsk
H[mask] = numpy.mod(60 * (G[mask] - B[mask]) / C[mask], 360)
mask = (M == G) & Cmsk
H[mask] = (60 * (B[mask] - R[mask]) / C[mask] + 120)
mask = (M == B) & Cmsk
H[mask] = (60 * (R[mask] - G[mask]) / C[mask] + 240)
H *= 255
H /= 360 # if you prefer, leave as 0-360, but don't convert to uint8
# Saturation
S = numpy.zeros(R.shape, int)
if isHSV:
# This code is for HSV:
# Value
V = M
# Saturation
S[Cmsk] = ((255 * C[Cmsk]) / V[Cmsk])
# H, S, and V are now defined as integers 0-255
return H.swapaxes(0, 1), S.swapaxes(0, 1), V.swapaxes(0, 1)
else:
# This code is for HSL:
# Value
L = 0.5 * (M + m)
# Saturation
S[Cmsk] = ((C[Cmsk]) / (1 - numpy.absolute(2 * L[Cmsk]/255.0 - 1)))
# H, S, and L are now defined as integers 0-255
return H.swapaxes(0, 1), S.swapaxes(0, 1), L.swapaxes(0, 1)
def rgb_to_hsv(a):
return rgb_to_hsl_hsv(a, True)
def rgb_to_hsl(a):
return rgb_to_hsl_hsv(a, False)
def hsl_to_rgb(H, S, L):
"""
Converts HSL color array to RGB array
H = [0..360]
S = [0..1]
l = [0..1]
http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL
Returns R,G,B in [0..255]
"""
C = (1 - numpy.absolute(2 * L - 1)) * S
Hp = H / 60.0
X = C * (1 - numpy.absolute(numpy.mod(Hp, 2) - 1))
# initilize with zero
R = numpy.zeros(H.shape, float)
G = numpy.zeros(H.shape, float)
B = numpy.zeros(H.shape, float)
# handle each case:
mask = (Hp >= 0) == ( Hp < 1)
R[mask] = C[mask]
G[mask] = X[mask]
mask = (Hp >= 1) == ( Hp < 2)
R[mask] = X[mask]
G[mask] = C[mask]
mask = (Hp >= 2) == ( Hp < 3)
G[mask] = C[mask]
B[mask] = X[mask]
mask = (Hp >= 3) == ( Hp < 4)
G[mask] = X[mask]
B[mask] = C[mask]
mask = (Hp >= 4) == ( Hp < 5)
R[mask] = X[mask]
B[mask] = C[mask]
mask = (Hp >= 5) == ( Hp < 6)
R[mask] = C[mask]
B[mask] = X[mask]
m = L - 0.5*C
R += m
G += m
B += m
R *=255.0
G *=255.0
B *=255.0
return R.astype(int),G.astype(int),B.astype(int)
def combineRGB(r,g,b):
"""
Combines separated R G B arrays into one array = image.
scipy.misc.imsave("rgb.png", combineRGB(R,G,B))
"""
rgb = numpy.zeros((r.shape[0],r.shape[1],3), 'uint8')
rgb[..., 0] = r
rgb[..., 1] = g
rgb[..., 2] = b
return rgb
scikits.image.color.rgb2hsv()
to get HSV values, which is nice if you can afford to install numpy/scipy/et al. But @paul I would wager that HSV functions aren't in PIL because there aren't any image binary formats that store their data as HSV values. Also, not much of anything has been added in PIL of late... <frownyface /> - fish2000