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

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

问题描述

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

这是来自另一个

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

RGB 立方体

我们还可以在 3D 空间中表示一种颜色.我们有三个值RGB分别对应XY, 和 Z.所有三个值都在 [0,255] 范围内,这会产生一个立方体.但在创建 RGB 立方体之前,让我们先处理 2D 空间.R、G、B 的两种组合为我们提供:RG、RB、GB.如果我们在平面上绘制这些图形,我们会得到以下结果:

这些是 RGB 立方体的前三个边.如果我们将它们放置在 3D 空间中,则会产生一个半立方体:

如果您查看上图,通过混合两种颜色,我们会在 (255,255) 处获得一种新颜色,它们是黄色、洋红色和青色.同样,这些的两个组合给了我们:YM、YC 和 MC.这些是立方体的缺失面.一旦我们添加它们,我们就得到了一个完整的立方体:

以及51,153,204在这个立方体中的位置:

RGB Cube 投影到六边形上

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

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

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

计算色调

在进行计算之前,让我们先定义什么是色调.

<块引用>

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

<块引用>

... 色调是点所在的六边形边缘周围的距离.

这是来自

检查六边形和 51,153,204 在它上面的位置.

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

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

接下来,找到R、G、B

maxmin

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

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

<块引用>

... chroma 大概是点到原点的距离.

<块引用>

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

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

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

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

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

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

接下来,我们需要移动段的位置,或者说P₁B(因为M = B).蓝色位于 240°.六边形有6个边.每边对应60°.240/60 = 4.我们需要将 P₁ 移动(增加)4(即 240°).移位后,P₁ 将在 P 处,我们将得到 RYGCP 的长度.

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

六边形的周长为6,对应360°.53,151,204 的距离是 3.3333333333333335.如果我们将 3.333333333333335 乘以 60,我们将得到它的位置(以度为单位).

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

<小时>

if M = R的情况下,由于我们将线段的一端放置在R(0°)处,如果线段长度为积极的.P₁ 的位置将为正.但是如果段长为负,我们需要将其移动6,因为负值意味着角位置大于180°,我们需要做一个完整的旋转.

因此,无论是荷兰维基解决方案hue = (g - b)/c; 还是英维基解决方案hue = ((g - b)/c) % 6; 将适用于负段长度.只有 SO 答案 hue = (g - b)/c + (g < b ? 6 : 0); 适用于负值和正值.

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

<小时>

JSFiddle:在 RGB Cube 和色相六边形中直观地找到颜色的位置

工作色调计算:

console.log(rgb2hue(51,153,204));控制台日志(rgb2hue(255,71,99));控制台日志(rgb2hue(255,0,0));控制台日志(rgb2hue(255,128,0));控制台日志(rgb2hue(124,252,0));函数 rgb2hue(r, g, b) {r/= 255;克/= 255;b/= 255;var max = Math.max(r, g, b);var min = Math.min(r, g, b);var c = 最大值 - 最小值;var 色调;如果(c == 0){色调 = 0;} 别的 {开关(最大){案例 r:var 段 = (g - b)/c;无功移位= 0/60;//R°/(360°/六角边)if (segment <0) {//色调 >180,全旋转移位 = 360/60;//R°/(360°/六角边)}色调 = 段 + 移位;休息;案例g:var 段 = (b - r)/c;无功移位 = 120/60;//G°/(360°/六角边)色调 = 段 + 移位;休息;案例b:var 段 = (r - g)/c;无功移位 = 240/60;//B°/(360°/六角边)色调 = 段 + 移位;休息;}}返回色调 * 60;//色调在 [0,6] 中,按比例放大}

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.

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.

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

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:

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

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

解决方案

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.

RGB

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:

RGB Cube

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:

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

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:

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

Projection of RGB Cube onto a hexagon

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.

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

Calculating the Hue

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

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.

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

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

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

Next, find the max and min values of 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

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

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.

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

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.

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

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°


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.

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: Test all three methods for rgb(255,71,99)


JSFiddle: Find a color's position in RGB Cube and hue hexagon visually

Working hue calculation:

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天全站免登陆