L*a*b* 色空間

L*a*b* 色空間は、ヒトの感覚に合わせて考案された色空間である。L* は明度で、0 ≤ L* ≤ 100 の値を取りうる。a* および b* は色味を表している。a* は緑色と赤色を表し、a* が正の大きな値になるほど赤みが強くなり、負の大きな値になるほど緑みが強くなり、また 0 であれば無彩色となる。また、b* は青色と黄色を表し、a* が正の大きな値になるほど黄色みが強くなり、負の大きな値になるほど青みが強くなり、また 0 であれば無彩色となる。a* および b* の最小値と最大値は、明度 L の値によって異なるので、明示的にその範囲を示されないことがほとんどである。

明度を 20、58、100 にしたときに、a* および b* の組み合わせによって、次のような色を表現することができる。なお、次の図は OpenCV を利用して視覚した画像で、L*、a*、および b* の取りうる値は、実際の L*a*b* 色空間の定義と少し異なる。

L*a*b* 色空間(L=20) L*a*b* 色空間(L=58) L*a*b* 色空間(L=100)

OpenCV

L*a*b* 色空間において、L* は 0 ≤ L* ≤ 100、a* および b* はマイナスからプラスまでの値を取りうる。OpenCV においては、0 ≤ L ≤ 100、-127 ≤ a ≤ 127 および -127 ≤ b ≤ 127 で定義されている。ただし、OpenCV の cv2.cvtColor メソッドを用いて変換された場合は、0 ≤ L ≤ 255、0 ≤ a ≤ 255 および 0 ≤ b ≤ 255 となる。OpenCV で L*a*b* 色空間を取り扱うときは、ここを注意する必要がある。

実際に、OpenCV で読み込んだ RGB 画像(sample.jpg)を L*a*b* 色空間に変換するときは次のようにする。

import cv2
import numpy as np

img = cv2.imread('sample.jpg')
img_Lab = cv2.cvtColor(img, cv2.COLOR_BGR2Lab)
img_L, img_a, img_b = cv2.split(img_Lab)

また、上で示した L*a*b* 色空間の図は、次の Python スクリプトで作図できる。L の値を書き換えることで、明度の異なる L*a*b* 色空間の画像を作ることができる。

import cv2
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt

L = 255.0


img_Lab = []
for a in np.arange(0, 255, 0.5):
    _r = []
    for b in np.arange(0, 255, 0.5):
        _p = [L, a, b]
        _r.append(_p)
    img_Lab.append(_r)

img_Lab = np.array(img_Lab, np.uint8)
img_BGR = cv2.cvtColor(img_Lab, cv2.COLOR_Lab2BGR)
img_RGB = cv2.cvtColor(img_Lab, cv2.COLOR_Lab2RGB)

img = Image.fromarray(img_RGB)
img = img.rotate(90)

fig = plt.figure(figsize=(25.5, 25.5), dpi=72)
ax = fig.add_subplot(111)

ax.imshow(np.asarray(img), origin='lower')

xy_labels = [0, 50, 100, 150, 200, 255]
xy_ticks = [_x * 2 for _x in xy_labels]

ax.set_xticks(xy_ticks)
ax.set_xticklabels(xy_labels, fontsize=60)
ax.set_yticks(xy_ticks)
ax.set_yticklabels(xy_labels, fontsize=60)

ax.set_xlabel('a*', fontsize=60)
ax.set_ylabel('b*', fontsize=60)
#fig.show()

fig.savefig('Lab_color_space.png')