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

math behind hsv to rgb conversion of colors

我正在研究将 hsv 颜色转换为 rgb 颜色的算法 space 并在维基百科上找到了它。 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个通道进行加权并求和。通过这个(值)定义,我们可以得到最亮的蓝色、红色和绿色,它们具有相同的 value,这对于颜色选择器来说很方便。 OTOH 我们知道一个完整的蓝屏(充满 [0,0,255])比一个完全绿屏 [0,255,0] 更暗。

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

好的色轮属性之一(用于混合,不是感性的)is:by将一种颜色与相反的颜色(在色轮上)混合,一个变灰。所以相反的颜色在轮子上也是相反的。所以我们有 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 度)。如果你写下所有情况,你会发现你最终可以简化计算[这通常在公共库中完成]

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

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

例外:然后有一些期望(你会看到你是否执行计算,例如,如果所有分量值都相等,则色调定义为零(它没有matter: full unsaturated colors do not have hue). 黑色的饱和度无法计算(零除以零),但它是不饱和色,所以我们设置为0.

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

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