相关文章推荐
逼格高的路灯  ·  C++ std::set ...·  1 年前    · 
阳刚的板凳  ·  MySQL数据库 - ...·  1 年前    · 
魁梧的打火机  ·  postgresql mybatis ...·  1 年前    · 

使用Python PIL,我试图调整一个给定图像的色调。

我对图形的专业术语不是很熟悉,所以我所说的 "调整色调 "是指在Photoshop中进行名为 "调整色调 "的操作。 "色调/饱和度" :这是为了均匀地改变图像的颜色,如下图所示。

  • Original: Original
  • With hue adjusted to +180 (red): hue: -180
  • With hue adjusted to -78 (green): hue: -78
  • 顺便说一下,Photoshop对这个色调设置使用了一个-180到+180的比例(其中-180等于+180),这可能代表了 HSL 色相比例 (expressed in 0-360 degree).

    我在寻找的是 一个函数,给定一个PIL图像和一个浮动的 hue 在[0, 1]范围内(或在[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')
    

    (请不要笑)结果。output.png

    提前感谢!

    Solution: 这里是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
        
    5 个评论
    在colorize(myimage, hueshift)中,myimage必须是一个pil图像,所以必须用以下方法从numpy数组转换为PIl。Image.fromarray(myRGBimage) 。很好!
    Mala
    请注意,你的色调偏移函数实际上并没有进行色调偏移 -- 它设置了一个特定的色调(h = hout),这意味着你的结果图像将被着色为单一的颜色。
    你可以通过将h = hout替换为h = (h + hout) % 1来解决@Mala提到的问题。
    python
    image
    python-imaging-library
    hue
    zopieux
    zopieux
    发布于 2011-09-02
    3 个回答
    unutbu
    unutbu
    发布于 2011-09-02
    已采纳
    0 人赞同

    有Python代码可以将RGB转换为HSV(反之亦然)。标准库中的colorys模块.我的第一次尝试使用了

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

    来对这些函数进行矢量处理。不幸的是,使用np.vectorize会导致代码相当慢。

    我通过将colorsys.rgb_to_hsvcolorsys.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')
    

    yields

    所以它确实需要对numpy数组进行一些操作......我以为它需要的操作会更少,但是,好吧,它完美地工作了。谢谢。
    由于你从一开始就将图像转换为RGB,我相信那里不支持透明度。尽管如此,我认为在操作前进行简单的阿尔法提取,然后在最终结果上使用putalpha()应该会有效果。
    @Zopieux:我修改了代码来处理RGBA,所以不需要putalpha了。
    这里面不是有一个错误吗。目前计算rgb_to_hsv中的最大值的方式,使用切片rgb[...,:2]只考虑R和G通道。它可能应该是rgb[...,:3]
    注意你并没有完全实现 colorsys 算法。对于 R=255, G=255 和 B=0, colorsys 返回:[0.16666666666, 1, 255],而你的返回:[0.83333333 1. 255. ] 。对于旋转色相来说,这不是一个问题,但是当使用这些函数做一些事情时,比如用另一个使用HSV的lib做色度键,就会产生一些问题(它甚至会让人发疯:/)。我还在想这是不是一个错误。
    K3---rnc
    K3---rnc
    发布于 2011-09-02
    0 人赞同

    使用Pillow的最新版本,人们可能应该使用图像.转换():

    def rgb2hsv(image: PIL.Image.Image):
        return image.convert('HSV')
        
    似乎在转换过程中,在内部它试图将字节 "写 "到缓冲区,这导致了。OSError: cannot write mode HSV as PNG
    Paul
    Paul
    发布于 2011-09-02
    0 人赞同