为什么RGB与HLS颜色系统之间的转换不精确?

2 投票
1 回答
1845 浏览
提问于 2025-04-18 05:24

我有一个应用程序需要把颜色从RGB格式转换成HLS格式,反过来也需要。查了一下,发现Python的标准库里有一个叫做colorsys的模块可以做到这一点。

不过,问题是这些转换有时候不太准确,得到的结果和这个在线颜色转换器的结果稍微有点不同。

下面是我写的两个小函数,方便使用:

from __future__ import division

import colorsys

def convert_rgb_to_hls(r, g, b):
    h, l, s = colorsys.rgb_to_hls(r/255, g/255, b/255)
    return "HLS(" + str(int(round(h * 359))) + ", " + str(int(round(l * 100))) + ", " + str(int(round(s * 100))) + ")"

def convert_hls_to_rgb(h, l, s):
    r, g, b = colorsys.hls_to_rgb(h/359, l/100, s/100)
    return "RGB(" + str(int(round(r * 255))) + ", " + str(int(round(g * 255))) + ", " + str(int(round(b * 255))) + ")"

根据这个在线颜色转换器,RGB(123, 243, 61)应该等于HLS(100, 60, 88)。但是我用colorsys函数得到的结果却不一样:

>>> convert_rgb_to_hls(123, 243, 61)
'HLS(99, 59, 88)'   # should be HLS(100, 60, 88)

>>> convert_hls_to_rgb(100, 60, 88)
'RGB(122, 243, 63)' # should be RGB(123, 243, 61)

我最开始以为这只是个四舍五入的问题,但仔细看61和63之间的差别,似乎还有其他原因。那么,究竟是什么呢?是否有可能保证颜色系统之间的转换绝对精确呢?

1 个回答

4
from __future__ import division

import colorsys

def convert_rgb_to_hls(r, g, b):
    h, l, s = colorsys.rgb_to_hls(r/255, g/255, b/255)
    return "HLS(" + str(int(round(h * 360))) + ", " + str(int(round(l * 100))) + ", " + str(int(round(s * 100))) + ")"

def convert_hls_to_rgb(h, l, s):
    r, g, b = colorsys.hls_to_rgb(h/360, l/100, s/100)
    return "RGB(" + str(int(round(r * 255))) + ", " + str(int(round(g * 255))) + ", " + str(int(round(b * 255))) + ")"

更改内容:

  • 使用360而不是359,因为范围是[0, 360)(维基百科)。
  • convert_rgb_to_hls(r, g, b)中缺少了两个舍入步骤。
  • 添加了Python 3的除法,以防你使用的是Python 2。

测试:

>>> convert_rgb_to_hls(123, 243, 61)    
'HLS(100, 60, 88)'

>>> convert_hls_to_rgb(100, 60, 88)
'RGB(123, 243, 63)'

你说得对,确实存在舍入错误,但61和63之间的差别是因为舍入时会失去精度。为了更好的精度,不要进行舍入:

>>> (r_orig, g_orig, b_orig) = (123, 243, 61)
>>> h,l,s = colorsys.rgb_to_hls(r_orig/255, g_orig/255, b_orig/255)
>>> r, g, b = colorsys.hls_to_rgb(h, l, s)
>>> r*255, g*255, b*255
(123.00000000000003, 242.99999999999997, 61.000000000000036)

撰写回答