Jaleks
Jaleks

Reputation: 630

What range does skimage use in LAB color space for each channel?

When converting images from RGB to LAB with skimage.color.rgb2lab, I can not really find a documentation, which value range each of the three channels can have in skimage. My try with the code below proposes that it would be [0.0, 9341.57] for L channel, [-6952.27, 7924.33] for A channel and [-8700.71, 7621.43] for B channel.
But for my eye this does neither look like the typical LBA values ([0, 100], [-170, 100], [-100, 150]) one can find in descriptions, nor does the ratio of the numbers seem similar, and also these are generally quite 'odd' looking ranges which do not seem to be normalized to anything at all.

So what values can each channel of an LBA image have, if converted by skimage?

(And/or where's my error in below try to determine them?)

# WARN: can take a while to calculate
import numpy as np
from skimage.color import rgb2lab
import multiprocessing as mp

colors = [[r,g,b] for r in range(256) for g in range(256) for b in range(256)]

imgs = np.zeros((16777216,1,1,3))
for i, color in enumerate(colors):
    imgs[i,:,:] = color


labs = np.zeros((16777216,1,1,3))
pool = mp.Pool(mp.cpu_count()-1)
try:
    labs = pool.map(rgb2lab, imgs)
except KeyboardInterrupt:
    # without catching this here we will never be able to manually stop running in a sane way
    pool.terminate()
pool.close()
pool.join()

print(np.min(labs[:,:,:,0]), np.max(labs[:,:,:,0]), np.min(labs[:,:,:,1]), np.max(labs[:,:,:,1]), np.min(labs[:,:,:,2]), np.max(labs[:,:,:,2]))

# 0.0 9341.570221995466 -6952.27373084052 7924.333617630548 -8700.709143439595 7621.42813486568

Upvotes: 2

Views: 1570

Answers (1)

Juan
Juan

Reputation: 5738

Well, your first mistake is using pure Python loops instead of NumPy expressions, but that's off topic. =) See below for a more efficient version of what you're trying to achieve.

The second mistake is more subtle and possibly the most common mistake from scikit-image newcomers. As of version 0.16, scikit-image uses implicit data ranges for different data types, detailed in this page. np.zeros defaults to the float data type, so your input array, above, has floats ranging in 0-255, which is a much bigger range than the expected 0-1, so you end up with a similarly bigger range in Lab space.

You can see the range of Lab values using numpy.uint8 values instead of float by changing the imgs declaration to imgs = np.zeros((16777216, 1, 1, 3), dtype=np.uint8). However, complete code for "the NumPy way" below:

In [2]: import numpy as np
In [3]: colors = np.mgrid[0:256, 0:256, 0:256].astype(np.uint8)
In [4]: colors.shape
Out[4]: (3, 256, 256, 256)

In [6]: all_rgb = np.transpose(colors)
In [7]: from skimage import color
In [8]: all_lab = color.rgb2lab(all_rgb)
In [9]: np.max(all_lab, axis=(0, 1, 2))
Out[9]: array([100.        ,  98.23305386,  94.47812228])

In [10]: np.min(all_lab, axis=(0, 1, 2))
Out[10]: array([   0.        ,  -86.18302974, -107.85730021])

To illustrate the data range issue, you can see that using floating point input in 0-1 gives you the same result:

In [12]: all_lab2 = color.rgb2lab(all_rgb / 255)
In [13]: np.max(all_lab2, axis=(0, 1, 2))
Out[13]: array([100.        ,  98.23305386,  94.47812228])

Upvotes: 4

Related Questions