teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

追記

2018/09/20 10:49

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -1,11 +1,5 @@
1
- ```
2
- cv2.cvtColor(image_bgr, cv2.COLOR_BGR2LAB)
3
- を使うと、クラスタリグで色を取得したあとになぜかRGBAに変換されてしまうで、
1
+ ## 各チャネル可視化
4
- ```
5
2
 
6
- BGR 色空間から LAB 色空間に変換するには、上記でよいはずですが、「クラスタリングで色を取得したあとになぜかRGBAに変換されてしまう」とはどういう処理のことを言っていますか?
7
-
8
-
9
3
  ```python
10
4
  import cv2
11
5
  import matplotlib.pyplot as plt
@@ -31,11 +25,6 @@
31
25
  ch_imgs = cv2.split(lab_img)
32
26
  labels = ['L', 'a', 'b']
33
27
  draw_each_channel(ch_imgs, labels)
34
-
35
- # リサイズした LAB 画像をチャンネルごとに表示する。
36
- ch_imgs = cv2.split(resized)
37
- labels = ['L', 'a', 'b']
38
- draw_each_channel(ch_imgs, labels)
39
28
  ```
40
29
 
41
30
  BGR 画像
@@ -44,5 +33,85 @@
44
33
  LAB 画像
45
34
  ![イメージ説明](c59d63d2aa2cb1a005a583e4800a1392.png)
46
35
 
36
+ ## 質問の内容 Lab 色空間の値の範囲について
37
+
38
+ ```
39
+ クラスタリングで色を取得したあとになぜかRGBAに変換されてしまうので、
40
+ ```
41
+ クラスタリングは関係ありません。
42
+ オリジナルの Lab 色空間の各チャンネルの値の範囲は以下ですが、
43
+
47
- リサイズした LAB 画像
44
+ L: [0, 100]
45
+ a: [-127, 127]
46
+ b: [-127, 127]
47
+
48
+ `cv2.cvtColor()` で変換した際は、値の範囲はすべて [0, 255] になるように補正されます。[OpenCV リファレンス](https://docs.opencv.org/3.3.0/de/d25/imgproc_color_conversions.html) を参考にしてください。
49
+ 補正する理由は、OpenCV の多くの関数は画像の型は uint8 を期待するため、int 型であると不便だからだと思います。
50
+ 元の範囲で得たい場合は、補正と逆の変換を行えばよいです。算出の式は [OpenCV リファレンス](https://docs.opencv.org/3.3.0/de/d25/imgproc_color_conversions.html) にのっています。
51
+
52
+ ```python
53
+ def draw_each_channel_hist(ch_imgs, labels, bins_list):
54
+ fig, axes_list = plt.subplots(1, 3, figsize=(10, 3))
55
+ for axes, ch_img, label, bins in zip(axes_list, ch_imgs, labels, bins_list):
56
+ axes.set_title(label)
57
+ axes.hist(ch_img.flatten(), bins=bins, density=True)
58
+ plt.show()
59
+
60
+ # cv2.COLOR_Lab2BGR 直後の Lab 画像
61
+ ch_imgs = cv2.split(lab_img)
62
+ bins_list = [np.arange(256), np.arange(256), np.arange(256)]
63
+ draw_each_channel_hist(ch_imgs, ['L', 'a', 'b'], bins_list)
64
+
65
+ # cv2.COLOR_Lab2BGR で最後に [0, 255] に範囲が補正されるので元に戻す、
66
+ # L_d := L * 255 / 100 <-> L = L_d * 100 / 255
67
+ # a_d := a + 128 <-> a = a_d - 128
68
+ # b_d := b + 128 <-> b = b_d - 128
69
+
70
+ lab_img2 = lab_img.astype(np.float)
71
+ lab_img2[:, :, 0] *= 100 / 255 # L の範囲を [0, 100] に戻す。
72
+ lab_img2[:, :, 1] -= 128 # L の範囲を [-127, 127] に戻す。
73
+ lab_img2[:, :, 2] -= 128 # L の範囲を [-127, 127] に戻す。
74
+ lab_img2 = lab_img2.astype(np.int)
75
+
76
+ # cv2.COLOR_Lab2BGR 直後の Lab 画像
77
+ ch_imgs = cv2.split(lab_img2)
78
+ bins_list = [np.arange(101), np.arange(-127, 128), np.arange(-127, 128)]
79
+ draw_each_channel_hist(ch_imgs, ['L', 'a', 'b'], bins_list)
80
+ ```
81
+
48
- ![イメージ説明](37a14ef2e14699832e9eeba7aba39e09.png)
82
+ ![イメージ説明](ed36867d25140aa8b7993a5ff6be2e3f.png)
83
+ ![イメージ説明](ce3603e89127499621e8341b48c11376.png)
84
+
85
+
86
+ ## ラベル画像作成
87
+
88
+ PIL や matplotlib など多くのライブラリでも、色は [0, 255] の範囲であることを前提としているので、[]0, 255] に補正したままのほうがよさそうです。
89
+
90
+ ```
91
+ # k-平均クラスタリングを行う。
92
+ kmeans = KMeans(n_clusters=3)
93
+ kmeans.fit(lab_img.reshape(-1, 3))
94
+
95
+ # ラベル一覧及び各ラベルの個数を取得する。
96
+ unique, counts = np.unique(kmeans.labels_, return_counts=True)
97
+ rates = counts / counts.sum() # 各ラベルの割合
98
+
99
+ # 画像を作成する。
100
+ height, width = 50, 300 # 画像の大きさ
101
+ bar_img = np.empty((height, 0, 3), dtype=np.uint8)
102
+ for color, rate in zip(clt.cluster_centers_, rates):
103
+ bar_width = int(rate * width)
104
+ bar = np.full((height, bar_width, 3), color, dtype=np.uint8)
105
+ bar_img = np.hstack([bar_img, bar])
106
+
107
+ print('color: {}, rate: {:.2f}'.format(color, rate))
108
+ # color: [168.23241035 106.80193675 180.55651384], rate: 0.37
109
+ # color: [ 89.67927036 110.89743899 153.16863977], rate: 0.32
110
+ # color: [208.73413897 112.50177328 172.6562459 ], rate: 0.31
111
+
112
+ plt.imshow(bar_img)
113
+ plt.axis('off')
114
+ plt.show()
115
+ ```
116
+
117
+ ![イメージ説明](17bde1156d45d617d693a5a864222ced.png)