Reputation: 17388
The following creates a red image using the RGB color 255,0,0
import numpy as np
import matplotlib.pyplot as plt
import cv2
width = 5
height = 2
array = np.zeros([height, width, 3], dtype=np.uint8)
array[:,:] = [255, 0, 0] # make it red
print(array)
plt.imshow(array)
plt.show()
Outputs:
[[[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]]
[[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]]]
If I transform the array into the LAB space:
array = cv2.cvtColor(array, cv2.COLOR_BGR2LAB)
print(array)
The results look like this:
[[[ 82 207 20]
[ 82 207 20]
[ 82 207 20]
[ 82 207 20]
[ 82 207 20]]
[[ 82 207 20]
[ 82 207 20]
[ 82 207 20]
[ 82 207 20]
[ 82 207 20]]]
According to http://colorizer.org/ the value of red should be:
lab(53.23, 80.11, 67.22)
Why is opencv producing different values? Am I missing something? Is there a site where I can lookup, for example, red in Lab color numbers for opebcv? Thanks.
PS:
One issue is that I used COLOR_BGR2LAB instead of COLOR_RGB2LAB (thanks Mark Setchell) but it still does not result in the expected vector of 53.23, 80.11, 67.22 it produces: 54.4 83.2 78. which is not close but not the same ...
import numpy as np
import matplotlib.pyplot as plt
import cv2
width = 5
height = 2
array = np.zeros([height, width, 3], dtype=np.uint8)
array[:,:] = [255, 0, 0] # make it red
print(array)
array = cv2.cvtColor(array, cv2.COLOR_RGB2LAB)
array = array / 2.5
print(array)
Upvotes: 1
Views: 2480
Reputation: 51
Actually you have to divide by 255. This way you have the same results as SKimage and Matlab...
cv2.cvtColor(array.astype('float32')/255., cv2.COLOR_RGB2Lab)
otherwise it gives wrong ranges. you can change the value of the array and check:
width = 5
height = 1
array = np.zeros([height, width, 3], dtype=np.uint8)
array[:,:] = [150, 20, 255] # make it red
print(array)
array2=rgb2lab(array )
print(array2.max(), array2.min())
array3 = cv2.cvtColor(array, cv2.COLOR_RGB2Lab)
print(array3 .max(), array3 .min())
array4 = cv2.cvtColor(array.astype('float32'), cv2.COLOR_RGB2Lab)
print(array4 .max(), array4 .min())
array5 = cv2.cvtColor(array.astype('float32')/255., cv2.COLOR_RGB2Lab)
print(array5 .max(), array5 .min())
Upvotes: 0
Reputation: 207465
You created the image in RGB order, so this
array = cv2.cvtColor(array, cv2.COLOR_BGR2LAB)
should be:
array = cv2.cvtColor(array, cv2.COLOR_RGB2LAB)
If you display it using OpenCV cv2.imshow(array)
and cv2.waitKey()
you will see OpenCV considers it blue.
As regards the discrepancy you see between the online converter and OpenCV, I can only assume this has something to do with rounding errors arising from using uint8
for the RGB values. If you convert to float
type, the issue goes away:
Lab = cv2.cvtColor(array.astype(np.float32), cv2.COLOR_RGB2LAB)
# Result
array([[[53.240967, 80.09375 , 67.203125],
[53.240967, 80.09375 , 67.203125],
[53.240967, 80.09375 , 67.203125],
[53.240967, 80.09375 , 67.203125],
[53.240967, 80.09375 , 67.203125]],
[[53.240967, 80.09375 , 67.203125],
[53.240967, 80.09375 , 67.203125],
[53.240967, 80.09375 , 67.203125],
[53.240967, 80.09375 , 67.203125],
[53.240967, 80.09375 , 67.203125]]], dtype=float32)
As an aside, I note that scikit-image
chooses to automatically return you a float
when you pass it uint8
:
from skimage import color
import numpy as np
# Make a rather small red image
array = np.full((1, 1, 3), [255,0,0], dtype=np.uint8)
# Convert to Lab with scikit-image
Lab = color.rgb2lab(array)
# Result
array([[[53.24058794, 80.09230823, 67.20275104]]])
Just for fun, while we are at it, check what ImageMagick makes it:
magick xc:red -colorspace lab txt:
# ImageMagick pixel enumeration: 1,1,65535,cielab
0,0: (34891.4,53351.7,17270.9) #884BD068C376 cielab(53.2408,80.0943,67.202)
Upvotes: 2