使用Python PIL,我正在尝试调整给定图像的色调。
我对图形的术语不太满意,所以我所说的“调整色调”就是做了名为“Hue/saturation”的Photoshop操作:这是统一改变图像的颜色,如下所示:
仅供参考,Photoshop为此色调设置使用-180到+180的比例(其中-180等于+180),这可能代表HSL hue scale(表示为0-360度)。
我正在寻找的是一个函数,给定PIL图像和[0,1]内的浮点 hue (或[0,360]中的int,它不会无所谓),返回图像,其色调偏移 hue ,如上例所示。
到目前为止,我所做的是荒谬的,显然没有给出理想的结果。它只是将原始图像与填充颜色的图层混合了一半。
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')
(请不要笑)结果:
提前致谢!
解决方案:这是更新的unutbu代码,因此它完全符合我的描述。
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
答案 0 :(得分:17)
在colorsys module in the standard library中有Python代码将RGB转换为HSV(反之亦然)。我的第一次尝试使用
rgb_to_hsv=np.vectorize(colorsys.rgb_to_hsv)
hsv_to_rgb=np.vectorize(colorsys.hsv_to_rgb)
矢量化这些功能。不幸的是,使用np.vectorize
导致代码速度相当慢。
通过将colorsys.rgb_to_hsv
和colorsys.hsv_to_rgb
翻译成原生的numpy操作,我获得了大约5倍的加速。
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')
产量
和
答案 1 :(得分:13)
最近有一份Pillow,应该使用
def rgb2hsv(image):
return image.convert('HSV')
答案 2 :(得分:1)
好问题。 PIL不会转换为HSV或HSL颜色空间,但这是您需要进行的转换,以便在不改变图像的亮度和饱和度的情况下改变色调。
您需要做的是转换为HSV,然后将所有H值递增一定程度,然后转换回RGB。
前一段时间,answer(由我)完成了一半的工作。它采用另一个名为NumPy的python模块,将RGB色彩空间转换为HSV。编写反向转换并不会太麻烦。