In this tutorial, we will see how to convert colors from the RGB (red-green-blue) to the HSL (hue-saturation-lightness), HSV (hue-saturation-value) or HSI (hue-saturation-intensity) systems in R (and vice versa).
If you are interested, I have already written a blog post about how to convert colors between RGB and HEX in R.
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(127.5, 127.5, 255)
barplot(1, col = rgb(RGB[1]/255, RGB[2]/255, RGB[3]/255), axes = F)
What is a HSL, HSV or HSI color?
Before digging into this subject, I invite you to browse this very complete page about HSL, HSV and HSI from Wikipedia. After that, we will use the fact that the three color systems are composed of three values. The two first ones are:
- the hue (ranging from 0 to 360°) which is identical in the three cases
- the saturation (ranging from 0 to 100 %) which is different in the three cases
Then, the third one is:
- the light / luminance / lightness / luminosity (ranging from 0 to 100 %) for HSL
- the value / brightness (ranging from 0 to 100 %) for HSV
- the intensity (ranging from 0 to 100 %) for HSI
Consequently, we will implement the HSL, HSV and HSI formulas from Wikipedia in R.
From RGB to HSL, HSV or HSI colors in R
from_rgb_to_hsl = function(RGB, color_model){
R = RGB[1] / 255
G = RGB[2] / 255
B = RGB[3] / 255
M = max(c(R, G, B))
m = min(c(R, G, B))
C = M - m
if (C == 0){
H = 0
} else {
if (M == R){
H = ((G - B) / C) %% 6
} else if (M == G){
H = ((B - R) / C) + 2
} else if (M == B){
H = ((R - G) / C) + 4
}
}
if (color_model == "HSI"){
I = (R + G + B) / 3
S = ifelse(I == 0, 0, 1 - (m / I))
params = c(H * 60, S * 100, I * 100)
} else if (color_model == "HSV" | color_model == "HSB"){
V = M
S = ifelse(V == 0, 0, C / V)
params = c(H * 60, S * 100, V * 100)
} else if (color_model == "HSL"){
L = (M + m) / 2
S = ifelse(L == 0 | L == 1, 0, C / (1 - abs(2 * L - 1)))
params = c(H * 60, S * 100, L * 100)
}
params = matrix(params)
rownames(params) = unlist(strsplit(color_model, ""))
return(params)
}
HSI = from_rgb_to_hsl(RGB, "HSI")
HSV = from_rgb_to_hsl(RGB, "HSV")
HSL = from_rgb_to_hsl(RGB, "HSL")
> from_rgb_to_hsl(RGB, "HSI")
[,1]
H 240.00000
S 25.00000
I 66.66667
> from_rgb_to_hsl(RGB, "HSV")
[,1]
H 240
S 50
V 100
> from_rgb_to_hsl(RGB, "HSL")
[,1]
H 240
S 100
L 75
From HSL, HSV or HSI to RGB colors in R
from_hsl_to_rgb = function(params, color_model){
H = params[1] / 60
S = params[2] / 100
if (color_model == "HSI"){
I = params[3] / 100
Z = 1 - abs(H %% 2 - 1)
C = (3 * I * S) / (1 + Z)
X = C * Z
} else if (color_model == "HSV"){
V = params[3] / 100
C = V * S
X = C * (1 - abs(H %% 2 - 1))
} else if (color_model == "HSL"){
L = params[3] / 100
C = (1 - abs(2 * L -1)) * S
X = C * (1 - abs(H %% 2 - 1))
}
if (H >= 0 & H < 1){
R = C
G = X
B = 0
} else if (H >= 1 & H < 2){
R = X
G = C
B = 0
} else if (H >= 2 & H < 3){
R = 0
G = C
B = X
} else if (H >= 3 & H < 4){
R = 0
G = X
B = C
} else if (H >= 4 & H < 5){
R = X
G = 0
B = C
} else if (H >= 5 & H < 6){
R = C
G = 0
B = X
}
if (color_model == "HSI"){
m = I * (1 - S)
} else if (color_model == "HSV"){
m = V - C
} else if (color_model == "HSL"){
m = L - C / 2
}
RGB = matrix((c(R, G, B) + m) * 255)
rownames(RGB) = c("red", "green", "blue")
return(RGB)
}
> from_hsl_to_rgb(HSI, "HSI")
[,1]
red 127.5
green 127.5
blue 255.0
> from_hsl_to_rgb(HSV, "HSV")
[,1]
red 127.5
green 127.5
blue 255.0
> from_hsl_to_rgb(HSL, "HSL")
[,1]
red 127.5
green 127.5
blue 255.0
Conclusion
In conclusion, it was a good exercise to implement the HSL, HSV and HSI formulas in R. How would you improve this function?