各チャンネルの可視化
python
1import cv2
2import matplotlib.pyplot as plt
3
4bgr_img = cv2.imread('harinezumi.jpg')
5lab_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2RGB)
6resized = cv2.resize(lab_img, (150, 150))
7
8def draw_each_channel(ch_imgs, labels):
9 fig, axes_list = plt.subplots(1, 3, figsize=(8, 5))
10 for axes, ch_img, label in zip(axes_list, ch_imgs, labels):
11 axes.set_axis_off()
12 axes.set_title(label)
13 axes.imshow(ch_img, cmap='gray')
14 plt.show()
15
16# BGR 画像をチャンネルごとに表示する。
17ch_imgs = cv2.split(bgr_img)
18labels = ['Blue', 'Green', 'Red']
19draw_each_channel(ch_imgs, labels)
20
21# LAB 画像をチャンネルごとに表示する。
22ch_imgs = cv2.split(lab_img)
23labels = ['L', 'a', 'b']
24draw_each_channel(ch_imgs, labels)
BGR 画像

LAB 画像

質問の内容 Lab 色空間の値の範囲について
クラスタリングで色を取得したあとになぜかRGBAに変換されてしまうので、
クラスタリングは関係ありません。
オリジナルの Lab 色空間の各チャンネルの値の範囲は以下ですが、
L: [0, 100]
a: [-127, 127]
b: [-127, 127]
cv2.cvtColor()
で変換した際は、値の範囲はすべて [0, 255] になるように補正されます。OpenCV リファレンス を参考にしてください。
補正する理由は、OpenCV の多くの関数は画像の型は uint8 を期待するため、int 型であると不便だからだと思います。
元の範囲で得たい場合は、補正と逆の変換を行えばよいです。算出の式は OpenCV リファレンス にのっています。
python
1def draw_each_channel_hist(ch_imgs, labels, bins_list):
2 fig, axes_list = plt.subplots(1, 3, figsize=(10, 3))
3 for axes, ch_img, label, bins in zip(axes_list, ch_imgs, labels, bins_list):
4 axes.set_title(label)
5 axes.hist(ch_img.flatten(), bins=bins, density=True)
6 plt.show()
7
8# cv2.COLOR_Lab2BGR 直後の Lab 画像
9ch_imgs = cv2.split(lab_img)
10bins_list = [np.arange(256), np.arange(256), np.arange(256)]
11draw_each_channel_hist(ch_imgs, ['L', 'a', 'b'], bins_list)
12
13# cv2.COLOR_Lab2BGR で最後に [0, 255] に範囲が補正されるので元に戻す、
14# L_d := L * 255 / 100 <-> L = L_d * 100 / 255
15# a_d := a + 128 <-> a = a_d - 128
16# b_d := b + 128 <-> b = b_d - 128
17
18lab_img2 = lab_img.astype(np.float)
19lab_img2[:, :, 0] *= 100 / 255 # L の範囲を [0, 100] に戻す。
20lab_img2[:, :, 1] -= 128 # L の範囲を [-127, 127] に戻す。
21lab_img2[:, :, 2] -= 128 # L の範囲を [-127, 127] に戻す。
22lab_img2 = lab_img2.astype(np.int)
23
24# cv2.COLOR_Lab2BGR 直後の Lab 画像
25ch_imgs = cv2.split(lab_img2)
26bins_list = [np.arange(101), np.arange(-127, 128), np.arange(-127, 128)]
27draw_each_channel_hist(ch_imgs, ['L', 'a', 'b'], bins_list)


ラベル画像作成
PIL や matplotlib など多くのライブラリでも、色は [0, 255] の範囲であることを前提としているので、[]0, 255] に補正したままのほうがよさそうです。
# k-平均クラスタリングを行う。
kmeans = KMeans(n_clusters=3)
kmeans.fit(lab_img.reshape(-1, 3))
# ラベル一覧及び各ラベルの個数を取得する。
unique, counts = np.unique(kmeans.labels_, return_counts=True)
rates = counts / counts.sum() # 各ラベルの割合
# 画像を作成する。
height, width = 50, 300 # 画像の大きさ
bar_img = np.empty((height, 0, 3), dtype=np.uint8)
for color, rate in zip(clt.cluster_centers_, rates):
bar_width = int(rate * width)
bar = np.full((height, bar_width, 3), color, dtype=np.uint8)
bar_img = np.hstack([bar_img, bar])
print('color: {}, rate: {:.2f}'.format(color, rate))
# color: [168.23241035 106.80193675 180.55651384], rate: 0.37
# color: [ 89.67927036 110.89743899 153.16863977], rate: 0.32
# color: [208.73413897 112.50177328 172.6562459 ], rate: 0.31
plt.imshow(bar_img)
plt.axis('off')
plt.show()

バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/09/20 08:34
2018/09/20 10:52
2018/09/20 11:20