- 
      
 - 
        
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