17

I am trying to convert a given Mat representing an RGB image with 8-bit depth to Lab using the function provided in the documentation:

cvtColor(source, destination, <conversion code>);

I have tried the following conversion codes:

CV_RGB2Lab
CV_BGR2Lab
CV_LBGR2Lab

I have received bizarre results each time around, with an "L" value of greater than 100 for some samples, literally <107, 125, 130>.

I am also using Photoshop to check the results - but given that 107 is beyond the accepted range of 0 ≤ L ≤ 100, I can not comprehend what my error is.

Update: I'll post my overall results here: Given an image (Mat) represented by 8-bit BGR, the image can be converted by the following:

cvtColor(source, destination, CV_BGR2Lab);

The pixel values can then be accessed in the following manner:

int step = destination.step;
int channels = destination.channels();
for (int i = 0; i < destination.rows(); i++) {
    for (int j = 0; j < destination.cols(); j++) {
        Point3_<uchar> pixelData;
        //L*: 0-255 (elsewhere is represented by 0 to 100)
        pixelData.x = destination.data[step*i + channels*j + 0];
        //a*: 0-255 (elsewhere is represented by -127 to 127)
        pixelData.y = destination.data[step*i + channels*j + 1];
        //b*: 0-255 (elsewhere is represented by -127 to 127)
        pixelData.z = destination.data[step*i + channels*j + 2];
    }
}
JT Cho
  • 263
  • 1
  • 4
  • 11
  • Also, you cannot do a RGB to Lab conversion with a reliable result without knowing the color profile. RGB is not an independent color space, Lab is. – TimZaman Feb 04 '15 at 08:56

4 Answers4

15

If anyone is interested in the range of the other variables a and b I made a small program to test their range. If you convert all the colors that are represented with RGB to the CieLab used in OpenCV the ranges are:

0  <=L<= 255
42 <=a<= 226
20 <=b<= 223

And if you're using RGB values in the float mode instead of uint8 the ranges will be:

0.0      <=L<= 100.0
-86.1813 <=a<= 98.2352
-107.862 <=b<= 94.4758

P.S. If you want to see how distinguishable (regarding human perception) is a LAB value from another LAB value, you should use the floating point. The scale used to keep the lab values in the uint8 ranges messes up with their euclidean distance.

This is the code I used (python):

L=[0]*256**3
a=[0]*256**3
b=[0]*256**3
i=0
for r in xrange(256):
    for g in xrange(256):
        for bb in xrange(256):
            im = np.array((bb,g,r),np.uint8).reshape(1,1,3)
            cv2.cvtColor(im,cv2.COLOR_BGR2LAB,im) #tranform it to LAB 
            L[i] = im[0,0,0]
            a[i] = im[0,0,1]
            b[i] = im[0,0,2]
            i+=1

print min(L), '<=L<=', max(L)
print min(a), '<=a<=', max(a)
print min(b), '<=b<=', max(b)
João Abrantes
  • 4,772
  • 4
  • 35
  • 71
  • Why do you say the scale for LAB values in uint8 type "messes" with their Euclidean distance? – simplename Oct 05 '17 at 15:06
  • @simplename the idea of LAB is that the Euclidean distance of two colors is related with how easily the human eye is able to distinguish those two colors. Using uint8 the L amplitude is now 255 instead of 100, while a and b still have similar ranges - two different colors have different euclidean distances when uint8 is used or when float is used. – João Abrantes Oct 05 '17 at 20:08
  • I cannot seem to convert to original image -> float32 -> bgr2lab -> make changes -> lab2bgr -> uint8 -> new image without issues. do you have code of converting back and forth? – 2c2c Oct 21 '17 at 06:42
14

That's because L value is in range [0..255] in OpenCV. You can simply scale this value to needed interval ([0..100] in your case).

ArtemStorozhuk
  • 8,715
  • 4
  • 35
  • 53
4

I am not sure about João Abrantes's range on A and B.

The opencv documentation has clearly mentioned the CIE L*a*b*range.

General Range

  • 8 bit images

    Range of 8_bit images

Thus leading to a range of

0 <= L <= 255
0 <= a <= 255
0 <= b <= 255
Shan
  • 511
  • 5
  • 13
0

In case anyone runs into the same issue:

Please note that in OpenCV (2.4.13), you can not convert CV_32FC3 BGR images into the Lab color space. That is to say:

//this->xImage is CV_8UC3
this->xImage.convertTo(FloatPrecisionImage, CV_32FC3);
Mat result;
cvtColor(FloatPrecisionImage, result, COLOR_BGR2Lab);
this->xImage = result;

will not work while

Mat result;
cvtColor(this->xImage, result, COLOR_BGR2Lab);
result.convertTo(this->xImage, CV_32FC3);

works like a charm. I did not track down the reason for said behavior; however it seems off to me, because this in effect puts limits on the image's quality.

zeroByte
  • 21
  • 1
  • 4