I’m not really sure how to get this to work properly and I’m not sure there is a point in continuing. The code below shows how to get XYZ and Lab* from a given RGB value in two ways: cvtColor and the documentation I’ve linked before about how cvtColor is intended to work.
My code gives the exact same values for XYZ as cvtColor. However, these values are significantly different from expected values. The Y value is 93 if I don’t divide by 255 first and 0.36 if I do. The expected value should be about 0.12. (In all honesty, i’m used to XYZ values being about 100 times these ones but that is just scaling I think.)
Calculating Lab* from the XYZ values (which is not a option using cvtColor) yields an L value of about 67 when 41 is expected.
My conclusion is that the matrix in the documentation is the one to determine XYZ but it isn’t the one used as an intermediate to calculate Lab*. Alternatively, there is an additional processing step I missed.
import cv2 #This is importing OpenCV
import numpy as np #This is importing numpy which I do automatically but allows matrix like manipulation of data
StartingRGB = np.zeros((1,1,3),np.uint8)
StartingRGB[0,0,0] = 50
StartingRGB[0,0,1] = 100
StartingRGB[0,0,2] = 150
StartingRGB = np.multiply(StartingRGB.astype(np.float32),1/255.0)
opencvXYZ = cv2.cvtColor(StartingRGB, cv2.COLOR_RGB2XYZ)
opencvLAB = cv2.cvtColor(StartingRGB, cv2.COLOR_RGB2LAB)
XYZRGBConverter = [[0.412453,0.357580,0.180423],[0.212671,0.715160,0.072169],[0.019334,0.119193,0.950227]]
calculatedXYZ = np.reshape(np.transpose(np.dot(XYZRGBConverter,np.transpose(np.reshape(StartingRGB,(-1,3))))),(-1,1,3))
calculatedLAB = np.zeros_like(opencvXYZ)
calculatedLAB[:,0,0] = [116*np.cbrt(t)-16 if t>0.008856 else 903.3*t for t in opencvXYZ[:,0,1]]
temp = np.zeros_like(opencvXYZ)
temp[:,0,0] = [np.cbrt(t) if t>0.008856 else 7.787*t+16.0/116.0 for t in opencvXYZ[:,0,0]/0.950456]
temp[:,0,1] = [np.cbrt(t) if t>0.008856 else 7.787*t+16.0/116.0 for t in opencvXYZ[:,0,1]]
temp[:,0,2] = [np.cbrt(t) if t>0.008856 else 7.787*t+16.0/116.0 for t in opencvXYZ[:,0,2]/1.088754]
calculatedLAB[:,0,1] = 500*(temp[:,0,0]-temp[:,0,1])
calculatedLAB[:,0,2] = 200*(temp[:,0,1]-temp[:,0,2])
expectedXYZ = np.zeros_like(opencvXYZ)
expectedXYZ[0,0,0] = 0.11377584875271197
expectedXYZ[0,0,1] = 0.1199446097547431
expectedXYZ[0,0,2] = 0.30569660696966523
recalculatedLAB = np.zeros_like(expectedXYZ)
recalculatedLAB[:,0,0] = [116*np.cbrt(t)-16 if t>0.008856 else 903.3*t for t in expectedXYZ[:,0,1]]
tempy = np.zeros_like(expectedXYZ)
tempy[:,0,0] = [np.cbrt(t) if t>0.008856 else 7.787*t+16.0/116.0 for t in expectedXYZ[:,0,0]/0.950456]
tempy[:,0,1] = [np.cbrt(t) if t>0.008856 else 7.787*t+16.0/116.0 for t in expectedXYZ[:,0,1]]
tempy[:,0,2] = [np.cbrt(t) if t>0.008856 else 7.787*t+16.0/116.0 for t in expectedXYZ[:,0,2]/1.088754]
recalculatedLAB[:,0,1] = 500*(tempy[:,0,0]-tempy[:,0,1])
recalculatedLAB[:,0,2] = 200*(tempy[:,0,1]-tempy[:,0,2])
print("RGB value to start with (normallized to 0 to 1 range): ")
print(StartingRGB)
print("\nXYZ calculated with cvtColor: ")
print(opencvXYZ)
print("\nL*a*b* calculated with cvtColor: ")
print(opencvLAB)
print("\nXYZ calculated from instructions: ")
print(calculatedXYZ)
print("\nL*a*b* calculated from instructions: ")
print(calculatedLAB)
print("\nXYZ value expected from other sources: ")
print(expectedXYZ)
print("\nL*a*b* calculated from instructions and expected value: ")
print(recalculatedLAB)
RGB value to start with (normalized to 0 to 1 range):
[[[0.19607845 0.3921569 0.5882353 ]]]
XYZ calculated with cvtColor:
[[[0.3272318 0.36460748 0.60949045]]]
Lab* calculated with cvtColor:
[[[ 41.082764 0.046875 -32.46875 ]]]
XYZ calculated from instructions:
[[[0.32723179 0.36460748 0.60949042]]]
Lab* calculated from instructions:
[[[ 66.870476 -6.762356 -21.952188]]]
XYZ value expected from other sources:
[[[0.11377585 0.11994461 0.3056966 ]]]
Lab* calculated from instructions and expected value:
[[[ 41.207314 -0.16321242 -32.330204 ]]]