Open Leterax opened 2 years ago
Here is some code to convert RGB to LAB:
func Rgb2lab(color RGB) LAB {
return xyz2lab(rgb2xyz(color))
}
// rgb2xyz converts from the RGB to the XYZ colorspace
func rgb2xyz(color RGB) XYZ {
r := float32(color.R) / 255.
g := float32(color.G) / 255.
b := float32(color.B) / 255.
if r > 0.04045 {
r = math32.Pow((r+0.055)/1.055, 2.4)
} else {
r = r / 12.92
}
if g > 0.04045 {
g = math32.Pow((g+0.055)/1.055, 2.4)
} else {
g = g / 12.92
}
if b > 0.04045 {
b = math32.Pow((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
return XYZ{X, Y, Z}
}
// xyz2lab converts from the XYZ to the LAB colorspace
func xyz2lab(color XYZ) LAB {
x := color.X / 94.811
y := color.Y / 100.000
z := color.Z / 107.304
if x > 0.00885 {
x = math32.Pow(x, 1./3.)
} else {
x = (7.787 * x) + (16. / 116.)
}
if y > 0.00885 {
y = math32.Pow(y, 1./3.)
} else {
y = (7.787 * y) + (16. / 116.)
}
if z > 0.00885 {
z = math32.Pow(z, 1./3.)
} else {
z = (7.787 * z) + (16. / 116.)
}
L := (116. * y) - 16.
a := 500. * (x - y)
b := 200. * (y - z)
return LAB{L, a, b}
}
And two different distance functions:
// DeltaE76 calculates the simpler DeltaE76 between two LAB colors
func DeltaE76(colorA, colorB LAB) float32 {
return math32.Sqrt(math32.Pow(colorB.L-colorA.L, 2.) + math32.Pow(colorB.A-colorA.A, 2.) + math32.Pow(colorB.B-colorA.B, 2.))
}
// DeltaE calculates the DeltaE between two LAB colors
func DeltaE(colorA LAB, colorB LAB) float32 {
xC1 := math32.Sqrt(math32.Pow(colorA.A, 2) + math32.Pow(colorA.B, 2))
xC2 := math32.Sqrt(math32.Pow(colorB.A, 2) + math32.Pow(colorB.B, 2))
xDL := colorB.L - colorA.L
xDC := xC2 - xC1
xDE := math32.Sqrt(((colorA.L - colorB.L) * (colorA.L - colorB.L)) + ((colorA.A - colorB.A) * (colorA.A - colorB.A)) + ((colorA.B - colorB.B) * (colorA.B - colorB.B)))
xDH := (xDE * xDE) - (xDL * xDL) - (xDC * xDC)
if xDH > 0 {
xDH = math32.Sqrt(xDH)
} else {
xDH = 0
}
xSC := 1 + (0.045 * xC1)
xSH := 1 + (0.015 * xC1)
xDC /= xSC
xDH /= xSH
dE := math32.Sqrt(math32.Pow(xDL, 2) + math32.Pow(xDC, 2) + math32.Pow(xDH, 2))
return dE
}
Hello @Leterax !
Thanks a lot for chiming in! I'll look at this. The CIELAB color space is new to me!
Have you thought of using the CIELAB color space instead of HSV/RGB? I have had pretty good success using this, but have only implemented it in golang, not python. The LAB colorspace has the advantage of being perceptually uniform.