Pylette
Pylette copied to clipboard
CIELAB color space
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.
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!