-
-
Save manojpandey/f5ece715132c572c80421febebaf66ae to your computer and use it in GitHub Desktop.
# RGB to Lab conversion | |
# Step 1: RGB to XYZ | |
# http://www.easyrgb.com/index.php?X=MATH&H=02#text2 | |
# Step 2: XYZ to Lab | |
# http://www.easyrgb.com/index.php?X=MATH&H=07#text7 | |
def rgb2lab(inputColor): | |
num = 0 | |
RGB = [0, 0, 0] | |
for value in inputColor: | |
value = float(value) / 255 | |
if value > 0.04045: | |
value = ((value + 0.055) / 1.055) ** 2.4 | |
else: | |
value = value / 12.92 | |
RGB[num] = value * 100 | |
num = num + 1 | |
XYZ = [0, 0, 0, ] | |
X = RGB[0] * 0.4124 + RGB[1] * 0.3576 + RGB[2] * 0.1805 | |
Y = RGB[0] * 0.2126 + RGB[1] * 0.7152 + RGB[2] * 0.0722 | |
Z = RGB[0] * 0.0193 + RGB[1] * 0.1192 + RGB[2] * 0.9505 | |
XYZ[0] = round(X, 4) | |
XYZ[1] = round(Y, 4) | |
XYZ[2] = round(Z, 4) | |
# Observer= 2°, Illuminant= D65 | |
XYZ[0] = float(XYZ[0]) / 95.047 # ref_X = 95.047 | |
XYZ[1] = float(XYZ[1]) / 100.0 # ref_Y = 100.000 | |
XYZ[2] = float(XYZ[2]) / 108.883 # ref_Z = 108.883 | |
num = 0 | |
for value in XYZ: | |
if value > 0.008856: | |
value = value ** (0.3333333333333333) | |
else: | |
value = (7.787 * value) + (16 / 116) | |
XYZ[num] = value | |
num = num + 1 | |
Lab = [0, 0, 0] | |
L = (116 * XYZ[1]) - 16 | |
a = 500 * (XYZ[0] - XYZ[1]) | |
b = 200 * (XYZ[1] - XYZ[2]) | |
Lab[0] = round(L, 4) | |
Lab[1] = round(a, 4) | |
Lab[2] = round(b, 4) | |
return Lab |
I think that this line:
value = (7.787 * value) + (16 / 116)
Is buggy. If you're using float
elsewhere to make the divisions produce float results (i.e. for Python 2 support) then I'd expect you to have to write 16.0 / 116.0
(technically only one would have to be a float literal).
$ python2
>>> 16/116
0
$ python3
>>> 16/116
0.13793103448275862
Hi! I used your RGB>LAB code as confirmation mine was working. I then used it in SLIC superpixel segmentation.
Great. Any feedback @i-make-robots? :)
Your work is appreciated and I thank you. :)
Super helpful stuff! Just used the alg and values (hard to find in a digestible way) in c#
im gonna convert it to javascript for a module im making
@JayRizuri feel free to :D Thanks!
Thanks for that! In case this helps someone, I ported to JS as follow:
function rgb2lab_normalizeRgbChannel(channel) {
channel /= 255;
return 100 * (channel > 0.04045
? Math.pow((channel + 0.055) / 1.055, 2.4)
: channel / 12.92
);
}
function rgb2lab_normalizeXyzChannel(channel) {
return (channel > 0.008856)
? Math.pow(channel, 1/3)
: (7.787 * channel) + (16 / 116);
}
function rgb2lab([r, g, b]) {
r = rgb2lab_normalizeRgbChannel(r);
g = rgb2lab_normalizeRgbChannel(g);
b = rgb2lab_normalizeRgbChannel(b);
let X = r * 0.4124 + g * 0.3576 + b * 0.1805;
let Y = r * 0.2126 + g * 0.7152 + b * 0.0722;
let Z = r * 0.0193 + g * 0.1192 + b * 0.9505;
// Observer= 2°, Illuminant= D65
X = rgb2lab_normalizeXyzChannel(X / 95.0470);
Y = rgb2lab_normalizeXyzChannel(Y / 100.0);
Z = rgb2lab_normalizeXyzChannel(Z / 108.883);
return [
(116 * Y) - 16, // L
500 * (X - Y), // a
200 * (Y - Z), // b
];
}
This is the code written in R.
I added a tiny extension, making the maximum of the RGB color value range variable instead of hard-coding it.
https://gist.github.com/TellAnAx/06ace666a92d0849d6b774de1790cc7a
rgb2lab <- function(inputColor, maxColorValue = 255){
num <- 1
RGB <- c(0, 0, 0)
for(value in inputColor){
value <- value / maxColorValue
if(value > 0.04045){
value <- ((value + 0.055) / 1.055)^2.4
} else{
value <- value / 12.92
}
RGB[num] <- value * 100
num <- num + 1
}
XYZ <- c(0, 0, 0)
X = RGB[1] * 0.4124 + RGB[2] * 0.3576 + RGB[3] * 0.1805
Y = RGB[1] * 0.2126 + RGB[2] * 0.7152 + RGB[3] * 0.0722
Z = RGB[1] * 0.0193 + RGB[2] * 0.1192 + RGB[3] * 0.9505
XYZ[1] = round(X, 4)
XYZ[2] = round(Y, 4)
XYZ[3] = round(Z, 4)
# Observer= 2°, Illuminant= D65
XYZ[1] = XYZ[1] / 95.047 # ref_X = 95.047
XYZ[2] = XYZ[2] / 100.0 # ref_Y = 100.000
XYZ[3] = XYZ[3] / 108.883 # ref_Z = 108.883
num = 1
for(value in XYZ){
if(value > 0.008856){
value = value ** (0.3333333333333333)
} else{
value = (7.787 * value) + (16 / 116)
}
XYZ[num] <- value
num <- num + 1
}
Lab <- c(0, 0, 0)
L = (116 * XYZ[2]) - 16
a = 500 * (XYZ[1] - XYZ[2])
b = 200 * (XYZ[2] - XYZ[3])
Lab[1] = round(L, 4)
Lab[2] = round(a, 4)
Lab[3] = round(b, 4)
return(Lab)
}
someome start a page on http://rosettacode.org/wiki/Rosetta_Code
Anyone have the numpy conversion for this code.. this takes too much time
This is really useful, thanks!
Hey, I used your gist in mine, I hope that's ok: https://gist.github.com/SinBirb/f71ab664d6f6bd3bbea7992bb264f2cf