HSI到RGB的颜色转换



我正在尝试实现恒生指数<=>RGB颜色转换
wiki上有公式https://en.wikipedia.org/wiki/HSL_and_HSV#HSI_to_RGB

RGB到HSI似乎工作良好。
然而,我有困难HSI到RGB。

我将用Ruby编写,示例将在Ruby中,但是如果你用JS/Python/等编写,我认为它也将是可以理解的,因为它只是数学。
在线ruby解释器。
def hsi_to_rgb(hsi_arr)
# to float
hue, saturation, intensity = hsi_arr.map(&:to_f)
hue /= 60
z = 1 - (hue % 2 - 1).abs
chroma = (3 * intensity * saturation) / (1 + z)
x = chroma * z
point = case hue
when 0..1 then [chroma, x, 0]
when 1..2 then [x, chroma, 0]
when 2..3 then [0, chroma, x]
when 3..4 then [0, x, chroma]
when 4..5 then [x, 0, chroma]
when 5..6 then [chroma, 0, x]
else [0, 0, 0]
end
# calculation rgb & scaling into range 0..255
m = intensity * (1 - saturation)
point.map { |channel| ((channel + m) * 255).round }
end

所以,简单的html颜色,一切似乎工作。直到我尝试这样的值:

p hsi_to_rgb([0,   1,   1])    # => [765, 0, 0]
p hsi_to_rgb([360, 1,   1])    # => [765, 0, 0]
p hsi_to_rgb([357, 1,   1])    # => [729, 0, 36]
p hsi_to_rgb([357, 1, 0.5])    # => [364, 0, 18]

得到的值明显不正确,超出了0 ~ 255的范围。

我也见过使用三角函数的实现:
https://hypjudy.github.io/images/dip/hsi2rgb.jpg
然而,我也没有得到正确的结果。

我发现的唯一在线RGB到HSI转换器:https://www.picturetopeople.org/color_converter.html
只是为了比较它。

你的实现看起来是正确的(假设维基百科是正确的)。

唯一缺少的部分是将RGB输出限制为[0,255]。

  • 正如Giacomo Catenazzi所评论的那样,如果最大值大于255,最好将R,G,B除以max(R, G,B),而不是剪切到[0,255]。

在大多数颜色空间转换公式中,有一些值在源颜色空间的有效范围内,但不在目标颜色空间的有效范围内。
常见的解决方案是将结果裁剪到有效范围内。

在某些情况下存在未定义的值。
看一下示例表的前3行。
Hue标记为N/A适用于白色、黑色和灰色。

您选择的所有样本HSI值:
[0, 1, 1]
[360, 1, 1]
[357, 1, 1]
[357, 1, 0.5]
落在RGB色彩空间的有效范围之外(在HSI到RGB转换之后)。


我建议您从示例表中测试有效的元组:

H       S       I                R       G       B
---    ----    ----             ----    ----    ----
0    100%   33.3%             100%      0%      0%
60    100%     50%              75%     75%      0%
120    100%   16.7%               0%     50%      0%
180     40%   83.3%              50%    100%    100%
240     25%   66.7%              50%     50%    100%
300   57.1%   58.3%              75%     25%     75%
61.8   69.9%   47.1%            62.8%   64.3%   14.2%
251.1   75.6%   42.6%            25.5%   10.4%   91.8%
134.9   66.7%   34.9%            11.6%   67.5%   25.5%
49.5   91.1%   59.3%            94.1%   78.5%    5.3%
283.7   68.6%   59.6%            70.4%   18.7%   89.7%
14.3   44.6%     57%            93.1%   46.3%   31.6%
56.9   36.3%   83.5%            99.8%   97.4%   53.2%
162.4     80%   49.5%             9.9%   79.5%   59.1%
248.3   53.3%   31.9%            21.1%   14.9%   59.7%
240.5   13.5%     57%            49.5%   49.3%   72.1%

我不知道Rubi编程语言的语法,但是你的实现看起来是正确的。

下面是一个与维基百科中的转换公式匹配的Python实现:

def hsi_to_rgb(hsi):
"""
Convert HSI tuple to RGB tuple (without scaling the result by 255) 
Formula: https://en.wikipedia.org/wiki/HSL_and_HSV#HSI_to_RGB        
H - Range [0, 360] (degrees)
S - Range [0, 1]
V - Range [0, 1]
The R,G,B output range is [0, 1]
"""
H, S, I = float(hsi[0]), float(hsi[1]), float(hsi[2])
Htag = H / 60
Z = 1 - abs(Htag % 2 - 1)
C = (3 * I * S) / (1 + Z)
X = C * Z
if 0 <= Htag <= 1:
R1, G1, B1 = C, X, 0
elif 1 <= Htag <= 2:
R1, G1, B1 = X, C, 0
elif 2 <= Htag <= 3:
R1, G1, B1 = 0, C, X
elif 3 <= Htag <= 4:
R1, G1, B1 = 0, X, C
elif 4 <= Htag <= 5:
R1, G1, B1 = X, 0, C
elif 5 <= Htag <= 6:
R1, G1, B1 = C, 0, X
else:
R1, G1, B1 = 0, 0, 0  # Undefined
# Calculation rgb
m = I * (1 - S)
R, G, B = R1 + m, G1 + m, B1 + m
# Limit R, G, B to valid range:
#R = max(min(R, 1), 0)
#G = max(min(G, 1), 0)
#B = max(min(B, 1), 0)
# Handling RGB values above 1:
# -----------------------------
# Avoiding weird colours - see the comment of Giacomo Catenazzi.
# Find the maximum between R, G, B, and if the value is above 1, divide the 3 channels with such numbers.
max_rgb = max((R, G, B))
if max_rgb > 1:
R /= max_rgb
G /= max_rgb
B /= max_rgb
return (R, G, B)

def rgb2percent(rgb):
""" Convert rgb tuple to percentage with one decimal digit accuracy """
rgb_per = (round(rgb[0]*1000.0)/10, round(rgb[1]*1000.0)/10, round(rgb[2]*1000.0)/10)
return rgb_per

print(rgb2percent(hsi_to_rgb([    0,    100/100,   33.3/100])))  # => (99.9,   0.0,   0.0)   Wiki:  100%      0%      0%
print(rgb2percent(hsi_to_rgb([   60,    100/100,     50/100])))  # => (75.0,  75.0,   0.0)   Wiki:   75%     75%      0%
print(rgb2percent(hsi_to_rgb([  120,    100/100,   16.7/100])))  # => ( 0.0,  50.1,   0.0)   Wiki:    0%     50%      0%
print(rgb2percent(hsi_to_rgb([  180,     40/100,   83.3/100])))  # => (50.0, 100.0, 100.0)   Wiki:   50%    100%    100%
print(rgb2percent(hsi_to_rgb([  240,     25/100,   66.7/100])))  # => (50.0,  50.0, 100.0)   Wiki:   50%     50%    100%
print(rgb2percent(hsi_to_rgb([  300,   57.1/100,   58.3/100])))  # => (74.9,  25.0,  74.9)   Wiki:   75%     25%     75%
print(rgb2percent(hsi_to_rgb([ 61.8,   69.9/100,   47.1/100])))  # => (62.8,  64.3,  14.2)   Wiki: 62.8%   64.3%   14.2%
print(rgb2percent(hsi_to_rgb([251.1,   75.6/100,   42.6/100])))  # => (25.5,  10.4,  91.9)   Wiki: 25.5%   10.4%   91.8%
print(rgb2percent(hsi_to_rgb([134.9,   66.7/100,   34.9/100])))  # => (11.6,  67.6,  25.5)   Wiki: 11.6%   67.5%   25.5%
print(rgb2percent(hsi_to_rgb([ 49.5,   91.1/100,   59.3/100])))  # => (94.1,  78.5,   5.3)   Wiki: 94.1%   78.5%    5.3%
print(rgb2percent(hsi_to_rgb([283.7,   68.6/100,   59.6/100])))  # => (70.4,  18.7,  89.7)   Wiki: 70.4%   18.7%   89.7%
print(rgb2percent(hsi_to_rgb([ 14.3,   44.6/100,     57/100])))  # => (93.2,  46.3,  31.6)   Wiki: 93.1%   46.3%   31.6%
print(rgb2percent(hsi_to_rgb([ 56.9,   36.3/100,   83.5/100])))  # => (99.9,  97.4,  53.2)   Wiki: 99.8%   97.4%   53.2%
print(rgb2percent(hsi_to_rgb([162.4,     80/100,   49.5/100])))  # => ( 9.9,  79.5,  59.1)   Wiki:  9.9%   79.5%   59.1%
print(rgb2percent(hsi_to_rgb([248.3,   53.3/100,   31.9/100])))  # => (21.1,  14.9,  59.7)   Wiki: 21.1%   14.9%   59.7%
print(rgb2percent(hsi_to_rgb([240.5,   13.5/100,     57/100])))  # => (49.5,  49.3,  72.2)   Wiki: 49.5%   49.3%   72.1%

可以看到,结果与Wikipedia中的示例表相匹配。

与WIKI颜色表的比较:

def print_rgb(rgb)
puts "[%s]" % rgb.map {|val| "%5.1f" % ((val / 255.0) * 100) }.join(", ")
end
print_rgb hsi_to_rgb([    0,    100/100.0,   33.3/100.0])  # => [100.0,   0.0,   0.0]   Wiki:  100%      0%      0%
print_rgb hsi_to_rgb([   60,    100/100.0,     50/100.0])  # => [ 74.9,  74.9,   0.0]   Wiki:   75%     75%      0%
print_rgb hsi_to_rgb([  120,    100/100.0,   16.7/100.0])  # => [  0.0,  50.2,   0.0]   Wiki:    0%     50%      0%
print_rgb hsi_to_rgb([  180,     40/100.0,   83.3/100.0])  # => [ 49.8, 100.0, 100.0]   Wiki:   50%    100%    100%
print_rgb hsi_to_rgb([  240,     25/100.0,   66.7/100.0])  # => [ 50.2,  50.2, 100.0]   Wiki:   50%     50%    100%
print_rgb hsi_to_rgb([  300,   57.1/100.0,   58.3/100.0])  # => [ 74.9,  25.1,  74.9]   Wiki:   75%     25%     75%
print_rgb hsi_to_rgb([ 61.8,   69.9/100.0,   47.1/100.0])  # => [ 62.7,  64.3,  14.1]   Wiki: 62.8%   64.3%   14.2%
print_rgb hsi_to_rgb([251.1,   75.6/100.0,   42.6/100.0])  # => [ 25.5,  10.6,  91.8]   Wiki: 25.5%   10.4%   91.8%
print_rgb hsi_to_rgb([134.9,   66.7/100.0,   34.9/100.0])  # => [ 11.8,  67.5,  25.5]   Wiki: 11.6%   67.5%   25.5%
print_rgb hsi_to_rgb([ 49.5,   91.1/100.0,   59.3/100.0])  # => [ 94.1,  78.4,   5.1]   Wiki: 94.1%   78.5%    5.3%
print_rgb hsi_to_rgb([283.7,   68.6/100.0,   59.6/100.0])  # => [ 70.6,  18.8,  89.8]   Wiki: 70.4%   18.7%   89.7%
print_rgb hsi_to_rgb([ 14.3,   44.6/100.0,     57/100.0])  # => [ 93.3,  46.3,  31.8]   Wiki: 93.1%   46.3%   31.6%
print_rgb hsi_to_rgb([ 56.9,   36.3/100.0,   83.5/100.0])  # => [100.0,  97.3,  53.3]   Wiki: 99.8%   97.4%   53.2%
print_rgb hsi_to_rgb([162.4,     80/100.0,   49.5/100.0])  # => [  9.8,  79.6,  59.2]   Wiki:  9.9%   79.5%   59.1%
print_rgb hsi_to_rgb([248.3,   53.3/100.0,   31.9/100.0])  # => [ 21.2,  14.9,  59.6]   Wiki: 21.1%   14.9%   59.7%
print_rgb hsi_to_rgb([240.5,   13.5/100.0,     57/100.0])  # => [ 49.4,  49.4,  72.2]   Wiki: 49.5%   49.3%   72.1%

值略有不同,因为该方法返回0..255范围内的整数RGB值

Rotem我说,我试图转换为RGB的HSI值超出了RGB范围。
所有其他16.7M颜色的RGB值被正确转换。

相关内容

  • 没有找到相关文章

最新更新