通过饱和度计算新的RGB值

3

我在谷歌上搜索了但没有结果。

如果我有以下颜色rgb(50,100,200)。 我可以用以下公式计算HSV饱和度:(200-50)/200,其结果为0.75。 如果我想要不同饱和度的颜色阴影,我该如何计算?

我正在使用一个颜色选择器来获取这些测试数据:

saturation 1.00 = r:0   g:66    b:200

saturation 0.75 = r:50  g:100   b:200

saturation 0.50 = r:100 g:134   b:200

saturation 0.25 = r:150 g:167   b:200

我注意到饱和度的变化,不会影响到最大值(即蓝色通道)。
在RGB数值之间没有找到比例关系。

我能否使用RGB计算新的颜色,而不是先将其转换为HSV颜色?


这是我回答的一个有关在颜色空间之间转换的链接,可能会很有帮助。 - Paul S.
@PaulS。饱和度与色调直接相关吗?还是您只是简化了代码,所以s不仅等于饱和度? - Daniel Cheung
并不是饱和度直接与色调相关,而是因为你正在改变坐标系,R、G和B都依赖于所有3个值。 - Paul S.
在您的具体示例中,如果您更改饱和度 B = 200; R = B - B * Saturation,则可以轻松计算出 R (min) 和 B (max),但是如何在不经过色调和值的情况下知道 G 呢?您只知道 R < G < B - Paul S.
@PaulS。我现在知道了;) 请看我的答案。 - Daniel Cheung
2个回答

3
在Excel绘图和数小时的复杂公式构建之后,解决方案并不是那么复杂!

Excel plotting

解决方案

它包含了一点JQuery,用于查找最大和最小rgb值的索引。

function saturation(i,v) { //i as in input, v as saturation value
    var min = $.inArray(Math.min.apply(this, i), i), //returns the index of min, max and mid.
        max = $.inArray(Math.max.apply(this, i), i),
        mid = parseInt([0, 1, 2].filter(function (j) {return Array(min, max).indexOf(j) < 0;})),
        r = (i[max] - i[mid]) / (i[mid] - i[min]), //ratio, because it is always constant, 
                                                   //we use this to calc mid value
        o = []; //o as in output
    if (min !== max) {
        o[max] = Math.round(i[max]);
        o[min] = Math.round(i[max] * (1 - v));
        o[mid] = Math.round(o[max] / (r + 1) * v + i[max] * (1 - v));
    }
    return o;
}

使用方法

saturation([52,132,220], 0.5) //Array [ 110, 162, 220 ]
saturation([52,132,220], 0) //Array [ 220, 220, 220 ]
saturation([52,132,220], 1) //Array [ 0, 105, 220 ]

哇!我为自己感到骄傲!这里真的很晚了。

如果你在处理与颜色公式相关的问题时遇到困难,我建议你绘制一个图表。


2

使用OP的答案提供的知识,中间值具有

new_mid = max / (r + 1) * sat + max * (1 - sat)
r = (max - mid) / (mid - min)

Can simplify... 
new_mid = max / (((max - mid) / (mid - min)) + 1) * sat + max * (1 - sat)
        = max * (sat / (((max - mid) / (mid - min)) + 1) + (1 - sat))
        = max * ((1 - sat) + sat / (((max - mid) / (mid - min)) + ((mid - min)  / (mid - min))))
        = max * ((1 - sat) + sat / (((max - mid) + (mid - min)) / (mid - min)))
        = max * ((1 - sat) + sat * (mid - min) / ((max - mid) + (mid - min)))
        = max * ((1 - sat) + sat * (mid - min) / (max - min))
let
a = max - min
b = mid - min
=>
new_mid = max * ((1 - sat) + sat * b / a)

我已经重新编写了这个方法,不再使用 jQuery,减少了除法操作并接受更多的输入。

// Inputs
// Array rgb colour data, s new hsl saturation
// Outputs
// Array rgb colour data
function saturation(rgb, s) {
    var min = rgb.indexOf(Math.min.apply(null, rgb)), // index of min
        max = rgb.indexOf(Math.max.apply(null, rgb)), // index of max
        mid = [0, 1, 2].filter(function (i) {return i !== min && i !== max;})[0],
        a = rgb[max] - rgb[min],
        b = rgb[mid] - rgb[min],
        x = rgb[max],
        arr = [x, x, x];
    if (min === max) {
        min = 2; // both max = min = 0, => mid = 1, so set min = 2
        a = 1;   // also means a = b = 0, don't want division by 0 in `b / a`
    }

    arr[max] = x;
    arr[min] = Math.round(x * (1 - s));
    arr[mid] = Math.round(x * ((1 - s) + s * b / a));

    return arr;
}

现在和以前一样,

saturation([52, 132, 220], 0.5); // [ 110, 162, 220 ]
saturation([52, 132, 220], 0);   // [ 220, 220, 220 ]
saturation([52, 132, 220], 1);   // [ 0, 105, 220 ]

但是也适用于具有相等部分的值

saturation([80, 80, 80], 0.5); // [80, 40, 40] vs []

改变 value 是非常容易的。

// Inputs
// Array rgb colour data, v new hsl value
// Outputs
// Array rgb colour data
function nvalue(rgb, v) {
    var x = Math.max.apply(null, rgb);
    if (x === 0)
        return [
            Math.round(255 * v),
            Math.round(255 * v),
            Math.round(255 * v)
        ];
    x = 255 * v / x;
    return [
        Math.round(rgb[0] * x),
        Math.round(rgb[1] * x),
        Math.round(rgb[2] * x)
    ];
}

谢谢您的参与!我非常感激。当时已经很晚了,我没有时间简化它,但我真的想分享我的答案 :) 尽管有人已经得到了一个可行的答案,但您仍然花费了时间。 - Daniel Cheung
即使我很懒,我也很少回答已经有解决方法的问题。 - Daniel Cheung
此外,arr[mid] 可以进一步简化为 Math.round(x * (1-s(1+b/a)),你可以直接将 b 插入其中。 - Daniel Cheung

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接