使用PIL将RGB转换为HSV

11 投票
2 回答
12337 浏览
提问于 2025-04-16 09:10

我正在尝试自动化处理一些要传输到数字相框的图片。我已经写好了代码,可以调整图片大小,在图片的一个不显眼的角落添加日期和时间,并将一对竖版图片拼接在一起,以避免在相框的41:20低分辨率屏幕上只显示一张竖版图片。

对于那些光线不太好的照片,我实现了一个亮度拉伸的滤镜,使用了colorsys.rgb_to_hsv函数来计算H(色相)、S(饱和度)、V(明度)三个部分,然后对V进行处理,再转换回RGB格式,最后保存为JPEG格式以便在数字相框中使用。显然,这个转换过程耗时很长,即使使用了itertools的一些技巧,我还是花了不少时间。不过,我通过使用psyco改善了一些性能。

然而,我注意到在PIL的Image.convert中,有一个例子提到可以使用一个4×4的矩阵作为第二个参数,将RGB转换为XYZ颜色空间。这让我开始思考:

我该如何在调用convert方法时,使用自定义矩阵将RGB转换为HSV(然后再将HSV转换回RGB)呢?(在这种情况下,轻微的舍入误差并不重要,所以我不介意每个部分用0到255的整数表示)

提前谢谢你。

2 个回答

0

把RGB值转换成HSV值的公式可以在这里找到:http://www.rapidtables.com/convert/color/rgb-to-hsv.htm。我之前需要把这个过程反过来做,所以写了一个函数来实现。

def hsb2rgb(hsb):
    '''
    Transforms a hsb array to the corresponding rgb tuple
    In: hsb = array of three ints (h between 0 and 360, s and v between 0 and 100)
    Out: rgb = array of three ints (between 0 and 255)
    '''
    H = float(hsb[0] / 360.0)
    S = float(hsb[1] / 100.0)
    B = float(hsb[2] / 100.0)

    if (S == 0):
        R = int(round(B * 255))
        G = int(round(B * 255))
        B = int(round(B * 255))
    else:
        var_h = H * 6
        if (var_h == 6):
            var_h = 0  # H must be < 1
        var_i = int(var_h)
        var_1 = B * (1 - S)
        var_2 = B * (1 - S * (var_h - var_i))
        var_3 = B * (1 - S * (1 - (var_h - var_i)))

        if      (var_i == 0):
            var_r = B     ; var_g = var_3 ; var_b = var_1
        elif (var_i == 1):
            var_r = var_2 ; var_g = B     ; var_b = var_1
        elif (var_i == 2):
            var_r = var_1 ; var_g = B     ; var_b = var_3
        elif (var_i == 3):
            var_r = var_1 ; var_g = var_2 ; var_b = B
        elif (var_i == 4):
            var_r = var_3 ; var_g = var_1 ; var_b = B
        else:
            var_r = B     ; var_g = var_1 ; var_b = var_2

        R = int(round(var_r * 255))
        G = int(round(var_g * 255))
        B = int(round(var_b * 255))

    return [R, G, B]
1

虽然我看到有些地方提到HSV颜色空间是从RGB颜色空间通过线性变换得到的,这听起来好像可以用一个矩阵来实现,但我一直没能找到或者自己弄清楚这个矩阵到底长什么样。其实,这也不让我感到意外,因为我也见过很多类似的非矩阵的处理方法——它们的做法看起来并不“线性”。

不过,在研究这个问题时,我偶然发现了一篇有点过时的文章,作者是前SGI的研究员Paul Haeberli,文章标题是图像处理中的矩阵运算,里面描述了如何使用4x4的矩阵进行多种颜色转换,可能对你有帮助。文中给出的所有例子都是直接对RGB颜色图像进行操作的,就像几何矩阵变换一样,任何这些变换的组合都可以通过连接成一个单一的矩阵。

希望这对你有帮助。


[1]: 颜色空间转换 <http://www.poynton.com/PDFs/coloureq.pdf>:

2.7.3 HSL(色相、饱和度和亮度)

这代表了许多类似的颜色空间,其他名称包括HSI(强度)、HSV(值)、HCI(色度/色彩丰富度)、HVC、TSD(色相、饱和度和黑暗)等。大多数这些颜色空间都是从RGB线性变换而来,因此它们依赖于设备,并且是非线性的。它们的优点在于非常直观地指定颜色。选择一个想要的色相,然后通过调整饱和度和强度稍微修改它是非常简单的。

撰写回答