【问题标题】:Calculate new RGB by saturation通过饱和度计算新的RGB
【发布时间】:2015-10-16 02:47:33
【问题描述】:

我在 Google 上搜索过,但无济于事。

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

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

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

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

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

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

我注意到随着饱和度的变化,最大值没有变化。 r,g,b 数之间没有找到比率。

我可以使用 RGB 计算新的颜色而不先将其转换为 HSV 颜色吗?

【问题讨论】:

  • Here 是我在颜色空间之间转换时所做的答案的链接,这可能会有所帮助
  • @PaulS。饱和度与色调有直接联系吗?或者你只是简化代码,所以s 不只是=饱和?
  • 饱和度与色调并没有直接联系,而是因为您正在改变坐标系统,R、G 和 B 都依赖于所有 3 个值。
  • 在您的具体示例中,如果您更改饱和度B = 200; R = B - B * Saturation,您可以轻松计算出R(最小值)和B(最大值),但是你怎么知道 G 没有经过色调和价值?你只知道R < G < B
  • @PaulS。我现在知道 ;) 看看我的回答。

标签: javascript php colors


【解决方案1】:

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

解决方案

包含一些 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's answer的知识,中间值有

    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 []
    

    更改要容易得多

    // 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)
        ];
    }
    

    【讨论】:

    • 感谢您的参与!对此,我真的非常感激。已经很晚了,我没有时间简化它,我真的很想分享我的答案:) 尽管有人已经得到了有效的答案,但你真的投入了时间。
    • 即使我这么懒,我也很少回答已经有答案的问题
    • 另外,arr[mid]可以进一步简化为Math.round(x * (1-s(1+b/a)),你可以将b直接插入其中。
    猜你喜欢
    • 2012-07-24
    • 2017-03-01
    • 2011-01-23
    • 2012-06-16
    • 2014-07-05
    • 1970-01-01
    • 2011-09-22
    • 2011-05-17
    • 2011-07-22
    相关资源
    最近更新 更多