RGB到HSL的转换 [英] RGB to HSL conversion

查看:167
本文介绍了RGB到HSL的转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个拾色器工具,对于HSL滑块,我需要能够将RGB转换为HSL.当我搜索SO进行转换的方法时,我发现此问题 HSL到RGB颜色转换.

I'm creating a Color Picker tool and for the HSL slider, I need to be able to convert RGB to HSL. When I searched SO for a way to do the conversion, I found this question HSL to RGB color conversion.

尽管它提供了将RGB转换为HSL的功能,但我看不到计算中真正发生什么的任何解释.为了更好地理解它,我已经阅读了Wikipedia上的 HSL和HSV .

While it provides a function to do conversion from RGB to HSL, I see no explanation to what's really going on in the calculation. To understand it better, I've read the HSL and HSV on Wikipedia.

稍后,我已使用"HSL和HSV"页面上的计算将功能从"HSL转换为RGB颜色转换".

Later, I've rewritten the function from the "HSL to RGB color conversion" using the calculations from the "HSL and HSV" page.

如果R为最大值,我将无法计算色相.请参阅"HSL和HSV"页面上的计算:

I'm stuck at the calculation of hue if the R is the max value. See the calculation from the "HSL and HSV" page:

这来自另一个维基页面,该页面位于荷兰语:

This is from another wiki page that's in Dutch:

这是从答案到"HSL到RGB颜色转换"的

and this is from the answers to "HSL to RGB color conversion":

case r: h = (g - b) / d + (g < b ? 6 : 0); break; // d = max-min = c

我用三个RGB值测试了所有这三个值,它们似乎会产生相似的(如果不准确的话)结果.我想知道的是他们在做同样的事情吗?对于某些特定的RGB值,我会得到不同的结果吗?我应该使用哪一个?

I've tested all three with a few RGB values and they seem to produce similar (if not exact) results. What I'm wondering is are they performing the same thing? Will get I different results for some specific RGB values? Which one should I be using?

hue = (g - b) / c;                   // dutch wiki
hue = ((g - b) / c) % 6;             // eng wiki
hue = (g - b) / c + (g < b ? 6 : 0); // SO answer

function rgb2hsl(r, g, b) {
    // see https://en.wikipedia.org/wiki/HSL_and_HSV#Formal_derivation
    // convert r,g,b [0,255] range to [0,1]
    r = r / 255,
    g = g / 255,
    b = b / 255;
    // get the min and max of r,g,b
    var max = Math.max(r, g, b);
    var min = Math.min(r, g, b);
    // lightness is the average of the largest and smallest color components
    var lum = (max + min) / 2;
    var hue;
    var sat;
    if (max == min) { // no saturation
        hue = 0;
        sat = 0;
    } else {
        var c = max - min; // chroma
        // saturation is simply the chroma scaled to fill
        // the interval [0, 1] for every combination of hue and lightness
        sat = c / (1 - Math.abs(2 * lum - 1));
        switch(max) {
            case r:
                // hue = (g - b) / c;
                // hue = ((g - b) / c) % 6;
                // hue = (g - b) / c + (g < b ? 6 : 0);
                break;
            case g:
                hue = (b - r) / c + 2;
                break;
            case b:
                hue = (r - g) / c + 4;
                break;
        }
    }
    hue = Math.round(hue * 60); // °
    sat = Math.round(sat * 100); // %
    lum = Math.round(lum * 100); // %
    return [hue, sat, lum];
}

推荐答案

我一直在阅读几个Wiki页面,并检查了不同的计算,并创建了将RGB立方体投影到六边形的可视化效果.我想发表我对这种转换的理解.由于我发现这种转换(使用几何形状的颜色模型表示)很有趣,因此,我将尽我所能.首先,让我们从RGB开始.

I've been reading several wiki pages and checking different calculations, and creating visualizations of RGB cube projection onto a hexagon. And I'd like to post my understanding of this conversion. Since I find this conversion (representations of color models using geometric shapes) interesting, I'll try to be as thorough as I can be. First, let's start with RGB.

嗯,这实际上并不需要太多解释.以其最简单的形式,您有3个值,R,G和B在[0,255]范围内.例如,51,153,204.我们可以使用条形图来表示它:

Well, this doesn't really need much explanation. In its simplest form, you have 3 values, R, G, and B in the range of [0,255]. For example, 51,153,204. We can represent it using a bar graph:

我们还可以在3D空间中表示一种颜色.我们有对应于XYZ的三个值RGB.所有这三个值都在[0,255]范围内,这将生成一个多维数据集.但是在创建RGB多维数据集之前,让我们先在2D空间上工作. R,G,B的两个组合给出了我们:RG,RB,GB.如果要在平面上绘制这些图形,则会得到以下结果:

We can also represent a color in a 3D space. We have three values R, G, B that corresponds to X, Y, and Z. All three values are in the [0,255] range, which results in a cube. But before creating the RGB cube, let's work on 2D space first. Two combinations of R,G,B gives us: RG, RB, GB. If we were to graph these on a plane, we'd get the following:

这些是RGB多维数据集的前三个面.如果我们将它们放置在3D空间上,则会得到一个半立方体:

These are the first three sides of the RGB cube. If we place them on a 3D space, it results in a half cube:

如果您查看上图,通过混合两种颜色,我们得到的新颜色为(255,255),分别是黄色,洋红色和青色.同样,这些的两种组合给出了我们:YM,YC和MC.这些是立方体的缺失面.添加它们后,我们将得到一个完整的多维数据集:

If you check the above graph, by mixing two colors, we get a new color at (255,255), and these are Yellow, Magenta, and Cyan. Again, two combinations of these gives us: YM, YC, and MC. These are the missing sides of the cube. Once we add them, we get a complete cube:

51,153,204在此多维数据集中的位置:

And the position of 51,153,204 in this cube:

现在我们有了RGB Cube,让我们将其投影到六边形上.首先,我们在x上将立方体倾斜45°,然后在y上倾斜35.264°.第二次倾斜后,黑角在底部,白角在顶部,它们都通过z轴.

Now that we have the RGB Cube, let's project it onto a hexagon. First, we tilt the cube by 45° on the x, and then 35.264° on the y. After the second tilt, black corner is at the bottom and the white corner is at the top, and they both pass through the z axis.

正如您所看到的,当我们从顶部看立方体时,我们得到了想要的六角形外观,具有正确的色相顺序.但是我们需要将其投影到真实的六边形上.我们要做的是绘制一个与立方体顶视图大小相同的六边形.六边形的所有角对应于立方体和颜色的角,白色的立方体的顶角投影到六边形的中心.黑色被省略.而且,如果我们将每种颜色映射到六边形上,我们都会看到正确的外观.

As you can see, we get the hexagon look we want with the correct hue order when we look at the cube from the top. But we need to project this onto a real hexagon. What we do is draw a hexagon that is in the same size with the cube top view. All the corners of the hexagon corresponds to the corners of the cube and the colors, and the top corner of the cube that is white, is projected onto the center of the hexagon. Black is omitted. And if we map every color onto the hexagon, we get the look at right.

51,153,204在六边形上的位置将是:

And the position of 51,153,204 on the hexagon would be:

在进行计算之前,让我们定义一下色调.

Before we make the calculation, let's define what hue is.

色相大约是矢量与投影中某个点的角度,红色为0°.

Hue is roughly the angle of the vector to a point in the projection, with red at 0°.

...色相是该点围绕该六角形边缘的距离.

... hue is how far around that hexagon’s edge the point lies.

这是 HSL和HSV Wiki页面的计算结果.我们将在此说明中使用它.

This is the calculation from the HSL and HSV wiki page. We'll be using it in this explanation.

检查六角形和51,153,204在其上的位置.

Examine the hexagon and the position of 51,153,204 on it.

首先,我们缩放R,G,B值以填充[0,1]间隔.

First, we scale the R, G, B values to fill the [0,1] interval.

R = R / 255    R =  51 / 255 = 0.2
G = G / 255    G = 153 / 255 = 0.6
B = B / 255    B = 204 / 255 = 0.8

接下来,找到R, G, B

M = max(R, G, B)    M = max(0.2, 0.6, 0.8) = 0.8
m = min(R, G, B)    m = min(0.2, 0.6, 0.8) = 0.2

然后,计算C(色度).色度定义为:

Then, calculate C (chroma). Chroma is defined as:

...色度大约是该点到原点的距离.

... chroma is roughly the distance of the point from the origin.

色度是六边形通过一个点的相对大小...

Chroma is the relative size of the hexagon passing through a point ...

C = OP / OP'
C = M - m
C = 0.8- 0.2 = 0.6

现在,我们有了RGBC值.如果我们检查条件,则if M = B对于51,153,204返回true.因此,我们将使用H'= (R - G) / C + 4.

Now, we have the R, G, B, and C values. If we check the conditions, if M = B returns true for 51,153,204. So, we'll be using H'= (R - G) / C + 4.

让我们再次检查六角形. (R - G) / C给出了BP段的长度.

Let's check the hexagon again. (R - G) / C gives us the length of BP segment.

segment = (R - G) / C = (0.2 - 0.6) / 0.6 = -0.6666666666666666

我们将这个线段放在内部六边形上.六角形的起点是0°处的R(红色).如果段长度为正,则应在RY上;如果为负,则应在RM上.在这种情况下,它是-0.6666666666666666的负数,并且在RM边缘.

We'll place this segment on the inner hexagon. Starting point of the hexagon is R (red) at 0°. If the segment length is positive, it should be on RY, if negative, it should be on RM. In this case, it is negative -0.6666666666666666, and is on the RM edge.

接下来,我们需要移动线段的位置,或者更确切地说P₁来警告B(因为M = B).蓝色位于240°.六角形有6个面.每侧对应于60°. 240 / 60 = 4.我们需要将P₁移位(递增)4(240°).移位后,P₁将位于P,我们将得到RYGCP的长度.

Next, we need to shift the position of the segment, or rather P₁ towars the B (because M = B). Blue is at 240°. Hexagon has 6 sides. Each side corresponds to 60°. 240 / 60 = 4. We need to shift (increment) the P₁ by 4 (which is 240°). After the shift, P₁ will be at P and we'll get the length of RYGCP.

segment = (R - G) / C = (0.2 - 0.6) / 0.6 = -0.6666666666666666
RYGCP   = segment + 4 = 3.3333333333333335

六边形的周长是6,对应于360°. 53,151,204的距离是3.3333333333333335.如果将3.3333333333333335乘以60,我们将获得其度数.

Circumference of the hexagon is 6 which corresponds to 360°. 53,151,204's distance to is 3.3333333333333335. If we multiply 3.3333333333333335 by 60, we'll get its position in degrees.

H' = 3.3333333333333335
H  = H' * 60 = 200°


对于if M = R,由于我们将线段的一端放置在R(0°)处,因此如果线段长度为正数,则无需将线段移至R. P₁的位置将为正.但是,如果线段长度为负,则需要将其偏移6,因为负值表示角度位置大于180°,并且需要进行完整旋转.


In the case of if M = R, since we place one end of the segment at R (0°), we don't need to shift the segment to R if the segment length is positive. The position of P₁ will be positive. But if the segment length is negative, we need to shift it by 6, because negative value means that the angular position is greater than 180° and we need to do a full rotation.

因此,荷兰语Wiki解决方案hue = (g - b) / c;和英语Wiki解决方案hue = ((g - b) / c) % 6;均不适用于负分段长度.只有SO答案hue = (g - b) / c + (g < b ? 6 : 0);既适用于正值,也适用于负值.

So, neither the Dutch wiki solution hue = (g - b) / c; nor the Eng wiki solution hue = ((g - b) / c) % 6; will work for negative segment length. Only the SO answer hue = (g - b) / c + (g < b ? 6 : 0); works for both negative and positive values.

JSFiddle:测试rgb(255,71,99)的所有三种方法

JSFiddle:在RGB立方体中找到颜色的位置并直观地看到六边形

工作色调计算:

console.log(rgb2hue(51,153,204));
console.log(rgb2hue(255,71,99));
console.log(rgb2hue(255,0,0));
console.log(rgb2hue(255,128,0));
console.log(rgb2hue(124,252,0));

function rgb2hue(r, g, b) {
  r /= 255;
  g /= 255;
  b /= 255;
  var max = Math.max(r, g, b);
  var min = Math.min(r, g, b);
  var c   = max - min;
  var hue;
  if (c == 0) {
    hue = 0;
  } else {
    switch(max) {
      case r:
        var segment = (g - b) / c;
        var shift   = 0 / 60;       // R° / (360° / hex sides)
        if (segment < 0) {          // hue > 180, full rotation
          shift = 360 / 60;         // R° / (360° / hex sides)
        }
        hue = segment + shift;
        break;
      case g:
        var segment = (b - r) / c;
        var shift   = 120 / 60;     // G° / (360° / hex sides)
        hue = segment + shift;
        break;
      case b:
        var segment = (r - g) / c;
        var shift   = 240 / 60;     // B° / (360° / hex sides)
        hue = segment + shift;
        break;
    }
  }
  return hue * 60; // hue is in [0,6], scale it up
}

这篇关于RGB到HSL的转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆