javascript - hsv到rgb颜色转换背后的数学

标签 javascript colors rgb hsv color-theory

我正在研究将 hsv 转换为 rgb 颜色空间的算法,并在 wikipdia 上找到了这个。 https://en.wikipedia.org/wiki/HSL_and_HSV .
我在这里找到了这个算法的实现。 https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c .

但据我所知,两者是如何相关的,以及这些计算背后的数学原理是什么。

这是代码

/**
 * Converts an HSV color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
 * Assumes h, s, and v are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   Number  h       The hue
 * @param   Number  s       The saturation
 * @param   Number  v       The value
 * @return  Array           The RGB representation
 */
function hsvToRgb(h, s, v){
    var r, g, b;

    var i = Math.floor(h * 6);
    var f = h * 6 - i;
    var p = v * (1 - s);
    var q = v * (1 - f * s);
    var t = v * (1 - (1 - f) * s);

    switch(i % 6){
        case 0: r = v, g = t, b = p; break;
        case 1: r = q, g = v, b = p; break;
        case 2: r = p, g = v, b = t; break;
        case 3: r = p, g = q, b = v; break;
        case 4: r = t, g = p, b = v; break;
        case 5: r = v, g = p, b = q; break;
    }

    return [r * 255, g * 255, b * 255];
}.

我想了解它背后的逻辑以及用于推导转换算法中使用的这些特定值的数学。

最佳答案

最简单的方法是自己设计(然后检查差异),相反的方法更容易:从 RGB 到 HSV。你的公式应该只是数学上的逆运算(用浮点数做,否则你会丢失信息)。在下面的解释中,我将使用从 0 到 1 的值(如果您使用 8 位 RGB,则通过除以 255 进行缩放)。

值(value) 只是定义为 RGB 的最大值(只是为了让事情更简单),如果你需要亮度,你应该加权 3 个 channel 并将它们相加。有了这个(值的)定义,我们可以得到最亮的蓝色、红色和绿色,它们的值相同,这对于颜色选择器来说很方便。 OTOH,我们知道完整的蓝屏(全是 [0,0,255])比全绿屏 [0,255,0] 更暗。

色相 表示纯色(如果完全饱和),即色轮上的颜色。这些是通过仅混合 R、G、B 的两个分量来完成的(第三个分量应该是 0)。为什么这个?取一个典型的 CIE xy 图(例如在 https://en.wikipedia.org/wiki/SRGB 上)。纯色是光谱颜色,因此只有一个波长(外部颜色)加上紫色线(下部线),因此将较深的紫色与较深的红色混合。使用 RGB,我们可以只显示三 Angular 形的内容(+ 缺失的 z(或 Y)轴上的颜色)。所以最相似和最纯的颜色是R、G、B点之间的三 Angular 形边缘的颜色。三 Angular 形上的点只有一两个分量。 [CIE xy 数字很好,因为混合两种颜色应该在两种颜色之间的线上]。

好的色轮(用于混合,而不是感知)的属性之一是:通过将一种颜色与相反的颜色(在轮上)混合,一种颜色变灰。所以相反的颜色在轮子上也是相反的。所以我们有 6 种颜色:红色 [255,0,0]、黄色 [255,255,0]、绿色 [0,255,0]、青色 [0,255,255]、蓝色 [0,0,255] 和洋红色 [255,0,255]。这是六个案例,相隔60度。所以如果你有 [255, 20, 0] 你是 20/255 从红色到黄色(其中 255/255 是 60 度)。如果你写下所有情况,你会发现你最终可以简化计算[通常在公共(public)库中完成]

饱和度 :完全饱和就像色调(所以一个分量为零),完全不饱和的颜色是灰色(或黑色或白色),所以所有分量都具有相同的值。所以最大分量与最小分量的差异是饱和的。

为什么不像某些公式那样取最小值?这也是一个很好的定义(也许更准确),并在某些地方使用。但是较暗的颜色似乎也不饱和(因此“混合”黑色或白色应该具有相似的行为,因此差异而不是最小)。在他的方式(差异)中,饱和度与值无关,对于颜色选择器来说更直观。然后将饱和度除以最大分量值。这也只是为每个案例都有一个 0 到 1 的数字。

异常(exception) :那么有一些期望(你会看到你是否实现了计算,例如,如果所有组件值都相等,则色调被定义为零(没关系:完全不饱和的颜色没有色调)。黑色的饱和度不能计算(零除以零),但它是不饱和颜色,所以我们将其设置为 0。

如果你推导出逆,你会看到你的公式。

注意:这些计算通常是针对 RGB 进行的(因此它们不是真正的色相或饱和度或亮度),对于颜色选择器,因此标准化值是从 0 到 1(或 100,或 360 的色调)。实际上,最小饱和度(因此最大色彩)取决于色调。饱和度应该取决于亮度等。所以更物理的颜色选择器不应该是圆形(圆柱体,双锥体),而是形状更复杂的图形。这对存储效率不高(丢失信息,例如通过输入整数:并非所有组合都是有效的),而且通常不太直观。

关于javascript - hsv到rgb颜色转换背后的数学,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51203917/

相关文章:

javascript - 获取div的X,Y位置

javascript - 从百分比获取颜色值

c++ - 如何最有效地修改 R/G/B 值?

javascript - Fabric.js - 绘制正八边形

javascript - 如何使用下一步按钮加载内容

javascript - 在代理处理程序中,如何区分获取属性 (var) 与调用方法?

html - 可以用 bg 颜色填充表格单元格吗?

python - 无需导入非标准库即可查找给定位置的像素颜色

Android - 通过引用其他定义的颜色来定义颜色

javascript - 如何使用 JavaScript 从图像区域获取 RGB 数据