将RGB数组转换为HSL

时间:2014-10-10 04:46:09

标签: python numpy rgb hsl

首先是免责声明,我对Python不是很熟练,你们有我的钦佩。

我的问题: 我需要从模板(128px到128px)生成10k +图像,具有各种色调和亮度。

我加载图像并将它们转换为数组

image = Image.open(dir + "/" + file).convert('RGBA')
arr=np.array(np.asarray(image).astype('float'))

据我所知,以这种方式处理numpy数组比循环遍历每个像素和使用colorsys要快得多。

现在,我偶然发现了一些将rgb转换为hsv的函数。 这有助于我生成具有不同色调的图像,但我还需要使用亮度,以便有些可以是黑色,有些可以是白色。

def rgb_to_hsv(rgb):
    # Translated from source of colorsys.rgb_to_hsv
    hsv=np.empty_like(rgb)
    hsv[...,3:]=rgb[...,3:]
    r,g,b=rgb[...,0],rgb[...,1],rgb[...,2]
    maxc = np.max(rgb[...,:2],axis=-1)
    minc = np.min(rgb[...,:2],axis=-1)    
    hsv[...,2] = maxc   
    hsv[...,1] = (maxc-minc) / maxc
    rc = (maxc-r) / (maxc-minc)
    gc = (maxc-g) / (maxc-minc)
    bc = (maxc-b) / (maxc-minc)
    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
    idx=(minc == maxc)
    hsv[...,0][idx]=0.0
    hsv[...,1][idx]=0.0
    return hsv

def hsv_to_rgb(hsv):
    # Translated from source of colorsys.hsv_to_rgb
    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

修改这些函数以转换为HSL和从HSL转换是多么容易? 将HSV转换为HSL的任何技巧?

非常感谢您能给我的任何信息,谢谢!

2 个答案:

答案 0 :(得分:1)

是的, numpy ,即矢量化代码,可以加快色彩转换。

对于10k +位图的大量生产越多,您可能希望重新使用现成的专业转换,或者如果它与您的首选亮度模型不完全匹配则重新使用它。

计算机视觉库OpenCV,目前可用作 cv2 模块的python,可以处理颜色系统转换,无需任何额外编码,只需:

现成的转换单线

out = cv2.cvtColor(   anInputFRAME, cv2.COLOR_YUV2BGR ) # a bitmap conversion

cv2中提供的一些颜色系统列表(您可能会注意到 RGB 被称为 BRG 由于OpenCV惯例对图像的不同排序 B lue- R ed- G reen颜色平面,< / p>

(对称适用COLOR_YCR_CB2BGR&lt; - | - &gt; COLOR_BGR2YCR_CB并非显示所有对)

>>> import cv2
>>> for key in dir( cv2 ):                              # show all ready conversions
...     if key[:7] == 'COLOR_Y':
...         print key

COLOR_YCR_CB2BGR
COLOR_YCR_CB2RGB
COLOR_YUV2BGR
COLOR_YUV2BGRA_I420
COLOR_YUV2BGRA_IYUV
COLOR_YUV2BGRA_NV12
COLOR_YUV2BGRA_NV21
COLOR_YUV2BGRA_UYNV
COLOR_YUV2BGRA_UYVY
COLOR_YUV2BGRA_Y422
COLOR_YUV2BGRA_YUNV
COLOR_YUV2BGRA_YUY2
COLOR_YUV2BGRA_YUYV
COLOR_YUV2BGRA_YV12
COLOR_YUV2BGRA_YVYU
COLOR_YUV2BGR_I420
COLOR_YUV2BGR_IYUV
COLOR_YUV2BGR_NV12
COLOR_YUV2BGR_NV21
COLOR_YUV2BGR_UYNV
COLOR_YUV2BGR_UYVY
COLOR_YUV2BGR_Y422
COLOR_YUV2BGR_YUNV
COLOR_YUV2BGR_YUY2
COLOR_YUV2BGR_YUYV
COLOR_YUV2BGR_YV12
COLOR_YUV2BGR_YVYU
COLOR_YUV2GRAY_420
COLOR_YUV2GRAY_I420
COLOR_YUV2GRAY_IYUV
COLOR_YUV2GRAY_NV12
COLOR_YUV2GRAY_NV21
COLOR_YUV2GRAY_UYNV
COLOR_YUV2GRAY_UYVY
COLOR_YUV2GRAY_Y422
COLOR_YUV2GRAY_YUNV
COLOR_YUV2GRAY_YUY2
COLOR_YUV2GRAY_YUYV
COLOR_YUV2GRAY_YV12
COLOR_YUV2GRAY_YVYU
COLOR_YUV2RGB
COLOR_YUV2RGBA_I420
COLOR_YUV2RGBA_IYUV
COLOR_YUV2RGBA_NV12
COLOR_YUV2RGBA_NV21
COLOR_YUV2RGBA_UYNV
COLOR_YUV2RGBA_UYVY
COLOR_YUV2RGBA_Y422
COLOR_YUV2RGBA_YUNV
COLOR_YUV2RGBA_YUY2
COLOR_YUV2RGBA_YUYV
COLOR_YUV2RGBA_YV12
COLOR_YUV2RGBA_YVYU
COLOR_YUV2RGB_I420
COLOR_YUV2RGB_IYUV
COLOR_YUV2RGB_NV12
COLOR_YUV2RGB_NV21
COLOR_YUV2RGB_UYNV
COLOR_YUV2RGB_UYVY
COLOR_YUV2RGB_Y422
COLOR_YUV2RGB_YUNV
COLOR_YUV2RGB_YUY2
COLOR_YUV2RGB_YUYV
COLOR_YUV2RGB_YV12
COLOR_YUV2RGB_YVYU
COLOR_YUV420P2BGR
COLOR_YUV420P2BGRA
COLOR_YUV420P2GRAY
COLOR_YUV420P2RGB
COLOR_YUV420P2RGBA
COLOR_YUV420SP2BGR
COLOR_YUV420SP2BGRA
COLOR_YUV420SP2GRAY
COLOR_YUV420SP2RGB
COLOR_YUV420SP2RGBA

我为Luminance转换做了一些原型设计(基于&gt;&gt;&gt; http://en.wikipedia.org/wiki/HSL_and_HSV

但未经测试发布。

def        get_YUV_V_Cr_Rec601_BRG_frame( brgFRAME ):                   # For the Rec. 601 primaries used in gamma-corrected sRGB, fast, VECTORISED MUL/ADD CODE
    out =  numpy.zeros( brgFRAME.shape[0:2] )
    out += 0.615 / 255 * brgFRAME[:,:,1]    # // Red                    # normalise to <0.0 - 1.0> before vectorised MUL/ADD, saves [usec] ... on 480x640 [px] faster goes about 2.2 [msec] instead of 5.4 [msec]
    out -= 0.515 / 255 * brgFRAME[:,:,2]    # // Green
    out -= 0.100 / 255 * brgFRAME[:,:,0]    # // Blue                   # normalise to <0.0 - 1.0> before vectorised MUL/ADD
    return out

答案 1 :(得分:0)

# -*- coding: utf-8 -*-
# @File    : rgb2hls.py
# @Info    : @ TSMC
# @Desc    :


import colorsys

import numpy as np
import scipy.misc
import tensorflow as tf
from PIL import Image


def rgb2hls(img):
    """ note: elements in img is a float number less than 1.0 and greater than 0.
    :param img: an numpy ndarray with shape NHWC
    :return:
    """
    assert len(img.shape) == 3
    hue = np.zeros_like(img[:, :, 0])
    luminance = np.zeros_like(img[:, :, 0])
    saturation = np.zeros_like(img[:, :, 0])
    for x in range(height):
        for y in range(width):
            r, g, b = img[x, y]
            h, l, s = colorsys.rgb_to_hls(r, g, b)
            hue[x, y] = h
            luminance[x, y] = l
            saturation[x, y] = s
    return hue, luminance, saturation


def np_rgb2hls(img):
    r, g, b = img[:, :, 0], img[:, :, 1], img[:, :, 2]

    maxc = np.max(img, -1)
    minc = np.min(img, -1)
    l = (minc + maxc) / 2.0
    if np.array_equal(minc, maxc):
        return np.zeros_like(l), l, np.zeros_like(l)
    smask = np.greater(l, 0.5).astype(np.float32)

    s = (1.0 - smask) * ((maxc - minc) / (maxc + minc)) + smask * ((maxc - minc) / (2.001 - maxc - minc))
    rc = (maxc - r) / (maxc - minc + 0.001)
    gc = (maxc - g) / (maxc - minc + 0.001)
    bc = (maxc - b) / (maxc - minc + 0.001)

    rmask = np.equal(r, maxc).astype(np.float32)
    gmask = np.equal(g, maxc).astype(np.float32)
    rgmask = np.logical_or(rmask, gmask).astype(np.float32)

    h = rmask * (bc - gc) + gmask * (2.0 + rc - bc) + (1.0 - rgmask) * (4.0 + gc - rc)
    h = np.remainder(h / 6.0, 1.0)
    return h, l, s


def tf_rgb2hls(img):
    """ note: elements in img all in [0,1]
    :param img: a tensor with shape NHWC
    :return:
    """
    assert img.get_shape()[-1] == 3
    r, g, b = img[:, :, 0], img[:, :, 1], img[:, :, 2]
    maxc = tf.reduce_max(img, -1)
    minc = tf.reduce_min(img, -1)

    l = (minc + maxc) / 2.0

    # if tf.reduce_all(tf.equal(minc, maxc)):
    #     return tf.zeros_like(l), l, tf.zeros_like(l)
    smask = tf.cast(tf.greater(l, 0.5), tf.float32)

    s = (1.0 - smask) * ((maxc - minc) / (maxc + minc)) + smask * ((maxc - minc) / (2.001 - maxc - minc))
    rc = (maxc - r) / (maxc - minc + 0.001)
    gc = (maxc - g) / (maxc - minc + 0.001)
    bc = (maxc - b) / (maxc - minc + 0.001)

    rmask = tf.equal(r, maxc)
    gmask = tf.equal(g, maxc)
    rgmask = tf.cast(tf.logical_or(rmask, gmask), tf.float32)
    rmask = tf.cast(rmask, tf.float32)
    gmask = tf.cast(gmask, tf.float32)

    h = rmask * (bc - gc) + gmask * (2.0 + rc - bc) + (1.0 - rgmask) * (4.0 + gc - rc)
    h = tf.mod(h / 6.0, 1.0)

    h = tf.expand_dims(h, -1)
    l = tf.expand_dims(l, -1)
    s = tf.expand_dims(s, -1)

    x = tf.concat([tf.zeros_like(l), l, tf.zeros_like(l)], -1)
    y = tf.concat([h, l, s], -1)

    return tf.where(condition=tf.reduce_all(tf.equal(minc, maxc)), x=x, y=y)


if __name__ == '__main__':
    """
    HLS: Hue, Luminance, Saturation
    H: position in the spectrum
    L: color lightness
    S: color saturation
    """
    avatar = Image.open("hue.jpg")
    width, height = avatar.size
    print("width: {}, height: {}".format(width, height))
    img = np.array(avatar)
    img = img / 255.0
    print(img.shape)

    # # hue, luminance, saturation = rgb2hls(img)
    # hue, luminance, saturation = np_rgb2hls(img)

    img_tensor = tf.convert_to_tensor(img, tf.float32)
    hls = tf_rgb2hls(img_tensor)
    h, l, s = hls[:, :, 0], hls[:, :, 1], hls[:, :, 2]

    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        hue, luminance, saturation = sess.run([h, l, s])
        scipy.misc.imsave("hls_h_.jpg", hue)
        scipy.misc.imsave("hls_l_.jpg", luminance)
        scipy.misc.imsave("hls_s_.jpg", saturation)