From RGB to HCL colors in R (and vice versa)

To convert colors from the RGB (red-green-blue) to the HCL (hue-chroma-lightness) system in R (or any other software), we need to go through XYZ and CIE-LAB color systems.

What is a RGB color?

A RGB color is composed of three to four values ranging from 0 to 255:

  • one value for the red
  • one value for the green
  • one value for the blue
  • one value for the transparency (facultative)

For example, let’s take the following values for red, green and blue, respectively:

RGB = c(237, 180, 232)
barplot(1, col = rgb(RGB[1]/255, RGB[2]/255, RGB[3]/255), axes = F)

What is a HCL color?

A HCL (or LCH) color is composed of three values:

  • one value for the hue (ranging from 0 to 360°)
  • one value for the chroma (ranging from 0 to 100%)
  • one value for the light / luminance / lightness / luminosity (ranging from 0 to 100%)

However, it is important to note that the hue is slightly different from the ones of HSL, HSV and HSI.

From RGB to HCL colors in R

To make the conversion between RGB and HCL color systems (and vice versa), we need to go through XYZ and CIE-LAB color systems. In the next sections, we will implement the formulas from the EasyRGB website.

from_rgb_to_hcl = function(RGB, color_model){
  R = RGB[1] / 255
  G = RGB[2] / 255
  B = RGB[3] / 255
  
  if (R > 0.04045){
    R = ((R + 0.055) / 1.055) ^ 2.4
    
  } else {
    R = R / 12.92
  }
  
  if (G > 0.04045){
    G = ((G + 0.055) / 1.055) ^ 2.4
    
  } else {
    G = G / 12.92
  }
  
  if (B > 0.04045){
    B = ((B + 0.055) / 1.055) ^ 2.4
      
  } else {
    B = B / 12.92
  }
  
  R = R * 100
  G = G * 100
  B = B * 100
  
  X = R * 0.4124 + G * 0.3576 + B * 0.1805
  Y = R * 0.2126 + G * 0.7152 + B * 0.0722
  Z = R * 0.0193 + G * 0.1192 + B * 0.9505
  
  XYZ = matrix(c(X, Y, Z))
  rownames(XYZ) = c("X", "Y", "Z")
  
  X = X / 95.047
  Y = Y / 100
  Z = Z / 108.883
  
  if (X > 0.008856){
    X = X ^ (1 / 3)
    
  } else {
    X = (7.787 * X) + (16 / 116)
  }
  
  if (Y > 0.008856){
    Y = Y ^ (1 / 3)
    
  } else {
    Y = (7.787 * Y) + (16 / 116)
  }
  
  if (Z > 0.008856){
    Z = Z ^ (1 / 3)
    
  } else {
    Z = (7.787 * Z) + (16 / 116)
  }
  
  L = (116 * Y) - 16
  A = 500 * (X - Y)
  B = 200 * (Y - Z)
  
  LAB = matrix(c(L, A, B))
  rownames(LAB) = c("L", "A", "B")
  
  H = atan2(B, A)
  
  if (H > 0){
    H = (H / pi) * 180
    
  } else {
    H = 360 - (abs(H) / pi) * 180
  }
  
  C = sqrt(A ^ 2 + B ^ 2)
  
  HCL = matrix(c(H, C, L))
  rownames(HCL) = c("H", "C", "L")
  
  if (color_model == "XYZ"){
    return(XYZ)
    
  } else if (color_model == "LAB"){
    return(LAB)
    
  } else if (color_model == "HCL"){
    return(HCL)
  }
}

HCL = from_rgb_to_hcl(RGB, "HCL")
> from_rgb_to_hcl(RGB, "XYZ")
      [,1]
X 65.81180
Y 56.47324
Z 83.77570

> from_rgb_to_hcl(RGB, "LAB")
       [,1]
L  79.88240
A  29.05609
B -17.95184

> from_rgb_to_hcl(RGB, "HCL")
       [,1]
H 328.29082
C  34.15443
L  79.88240

From HCL to RGB colors in R

from_hcl_to_rgb = function(HCL, color_model){
  H = HCL[1]
  C = HCL[2]
  L = HCL[3]
  
  A = cos((H * pi) / 180) * C
  B = sin((H * pi) / 180) * C
  
  LAB = matrix(c(L, A, B))
  rownames(LAB) = c("L", "A", "B")
  
  Y = (L + 16) / 116
  X = A / 500 + Y
  Z = Y - B / 200
  
  if (Y^3  > 0.008856){
    Y = Y^3
    
  } else {
    Y = (Y - 16 / 116) / 7.787
  }
  
  if (X^3  > 0.008856){
    X = X^3
    
  } else {
    X = (X - 16 / 116) / 7.787
  }
  
  if (Z^3  > 0.008856){
    Z = Z^3
    
  } else {
    Z = (Z - 16 / 116) / 7.787
  }
  
  X = X * 95.047
  Y = Y * 100
  Z = Z * 108.883
  
  XYZ = matrix(c(X, Y, Z))
  rownames(XYZ) = c("X", "Y", "Z")
  
  X = X / 100
  Y = Y / 100
  Z = Z / 100
  
  R = X *  3.2406 + Y * -1.5372 + Z * -0.4986
  G = X * -0.9689 + Y *  1.8758 + Z *  0.0415
  B = X *  0.0557 + Y * -0.2040 + Z *  1.0570
  
  if (R > 0.0031308){
    R = 1.055 * (R ^ (1 / 2.4)) - 0.055
    
  } else {
    R = 12.92 * R
  }
  
  if (G > 0.0031308){
    G = 1.055 * (G ^ (1 / 2.4)) - 0.055
    
  } else {
    G = 12.92 * G
  }
  
  if (B > 0.0031308){
    B = 1.055 * (B ^ (1 / 2.4)) - 0.055
    
  } else {
    B = 12.92 * B
  }
  
  RGB = matrix(c(R, G, B) * 255)
  mode(RGB) = "integer"
  rownames(RGB) = c("red", "green", "blue")
  
  if (color_model == "LAB"){
    return(LAB)
    
  } else if (color_model == "XYZ"){
    return(XYZ)
    
  } else if (color_model == "RGB"){
    return(RGB)
  }
}
> from_hcl_to_rgb(HCL, "LAB")
       [,1]
L  79.88240
A  29.05609
B -17.95184

> from_hcl_to_rgb(HCL, "XYZ")
      [,1]
X 65.81180
Y 56.47324
Z 83.77570

> from_hcl_to_rgb(HCL, "RGB")
      [,1]
red    237
green  180
blue   232

Conclusion

It was again a good exercise to implement the conversion between RGB and HCL color spaces in R. Is this article useful to you?

Related posts

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply