回答編集履歴

1

追記

2018/09/20 10:49

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -1,16 +1,4 @@
1
- ```
2
-
3
- cv2.cvtColor(image_bgr, cv2.COLOR_BGR2LAB)
4
-
5
- を使うと、クラスタリグで色を取得したあとになぜかRGBAに変換されてしまうで、
1
+ ## 各チャネル可視化
6
-
7
- ```
8
-
9
-
10
-
11
- BGR 色空間から LAB 色空間に変換するには、上記でよいはずですが、「クラスタリングで色を取得したあとになぜかRGBAに変換されてしまう」とはどういう処理のことを言っていますか?
12
-
13
-
14
2
 
15
3
 
16
4
 
@@ -64,16 +52,6 @@
64
52
 
65
53
  draw_each_channel(ch_imgs, labels)
66
54
 
67
-
68
-
69
- # リサイズした LAB 画像をチャンネルごとに表示する。
70
-
71
- ch_imgs = cv2.split(resized)
72
-
73
- labels = ['L', 'a', 'b']
74
-
75
- draw_each_channel(ch_imgs, labels)
76
-
77
55
  ```
78
56
 
79
57
 
@@ -90,6 +68,166 @@
90
68
 
91
69
 
92
70
 
71
+ ## 質問の内容 Lab 色空間の値の範囲について
72
+
73
+
74
+
75
+ ```
76
+
77
+ クラスタリングで色を取得したあとになぜかRGBAに変換されてしまうので、
78
+
79
+ ```
80
+
81
+ クラスタリングは関係ありません。
82
+
83
+ オリジナルの Lab 色空間の各チャンネルの値の範囲は以下ですが、
84
+
85
+
86
+
93
- リサイズした LAB 画像
87
+ L: [0, 100]
88
+
94
-
89
+ a: [-127, 127]
90
+
91
+ b: [-127, 127]
92
+
93
+
94
+
95
+ `cv2.cvtColor()` で変換した際は、値の範囲はすべて [0, 255] になるように補正されます。[OpenCV リファレンス](https://docs.opencv.org/3.3.0/de/d25/imgproc_color_conversions.html) を参考にしてください。
96
+
97
+ 補正する理由は、OpenCV の多くの関数は画像の型は uint8 を期待するため、int 型であると不便だからだと思います。
98
+
99
+ 元の範囲で得たい場合は、補正と逆の変換を行えばよいです。算出の式は [OpenCV リファレンス](https://docs.opencv.org/3.3.0/de/d25/imgproc_color_conversions.html) にのっています。
100
+
101
+
102
+
103
+ ```python
104
+
105
+ def draw_each_channel_hist(ch_imgs, labels, bins_list):
106
+
107
+ fig, axes_list = plt.subplots(1, 3, figsize=(10, 3))
108
+
109
+ for axes, ch_img, label, bins in zip(axes_list, ch_imgs, labels, bins_list):
110
+
111
+ axes.set_title(label)
112
+
113
+ axes.hist(ch_img.flatten(), bins=bins, density=True)
114
+
115
+ plt.show()
116
+
117
+
118
+
119
+ # cv2.COLOR_Lab2BGR 直後の Lab 画像
120
+
121
+ ch_imgs = cv2.split(lab_img)
122
+
123
+ bins_list = [np.arange(256), np.arange(256), np.arange(256)]
124
+
125
+ draw_each_channel_hist(ch_imgs, ['L', 'a', 'b'], bins_list)
126
+
127
+
128
+
129
+ # cv2.COLOR_Lab2BGR で最後に [0, 255] に範囲が補正されるので元に戻す、
130
+
131
+ # L_d := L * 255 / 100 <-> L = L_d * 100 / 255
132
+
133
+ # a_d := a + 128 <-> a = a_d - 128
134
+
135
+ # b_d := b + 128 <-> b = b_d - 128
136
+
137
+
138
+
139
+ lab_img2 = lab_img.astype(np.float)
140
+
141
+ lab_img2[:, :, 0] *= 100 / 255 # L の範囲を [0, 100] に戻す。
142
+
143
+ lab_img2[:, :, 1] -= 128 # L の範囲を [-127, 127] に戻す。
144
+
145
+ lab_img2[:, :, 2] -= 128 # L の範囲を [-127, 127] に戻す。
146
+
147
+ lab_img2 = lab_img2.astype(np.int)
148
+
149
+
150
+
151
+ # cv2.COLOR_Lab2BGR 直後の Lab 画像
152
+
153
+ ch_imgs = cv2.split(lab_img2)
154
+
155
+ bins_list = [np.arange(101), np.arange(-127, 128), np.arange(-127, 128)]
156
+
157
+ draw_each_channel_hist(ch_imgs, ['L', 'a', 'b'], bins_list)
158
+
159
+ ```
160
+
161
+
162
+
95
- ![イメージ説明](37a14ef2e14699832e9eeba7aba39e09.png)
163
+ ![イメージ説明](ed36867d25140aa8b7993a5ff6be2e3f.png)
164
+
165
+ ![イメージ説明](ce3603e89127499621e8341b48c11376.png)
166
+
167
+
168
+
169
+
170
+
171
+ ## ラベル画像作成
172
+
173
+
174
+
175
+ PIL や matplotlib など多くのライブラリでも、色は [0, 255] の範囲であることを前提としているので、[]0, 255] に補正したままのほうがよさそうです。
176
+
177
+
178
+
179
+ ```
180
+
181
+ # k-平均クラスタリングを行う。
182
+
183
+ kmeans = KMeans(n_clusters=3)
184
+
185
+ kmeans.fit(lab_img.reshape(-1, 3))
186
+
187
+
188
+
189
+ # ラベル一覧及び各ラベルの個数を取得する。
190
+
191
+ unique, counts = np.unique(kmeans.labels_, return_counts=True)
192
+
193
+ rates = counts / counts.sum() # 各ラベルの割合
194
+
195
+
196
+
197
+ # 画像を作成する。
198
+
199
+ height, width = 50, 300 # 画像の大きさ
200
+
201
+ bar_img = np.empty((height, 0, 3), dtype=np.uint8)
202
+
203
+ for color, rate in zip(clt.cluster_centers_, rates):
204
+
205
+ bar_width = int(rate * width)
206
+
207
+ bar = np.full((height, bar_width, 3), color, dtype=np.uint8)
208
+
209
+ bar_img = np.hstack([bar_img, bar])
210
+
211
+
212
+
213
+ print('color: {}, rate: {:.2f}'.format(color, rate))
214
+
215
+ # color: [168.23241035 106.80193675 180.55651384], rate: 0.37
216
+
217
+ # color: [ 89.67927036 110.89743899 153.16863977], rate: 0.32
218
+
219
+ # color: [208.73413897 112.50177328 172.6562459 ], rate: 0.31
220
+
221
+
222
+
223
+ plt.imshow(bar_img)
224
+
225
+ plt.axis('off')
226
+
227
+ plt.show()
228
+
229
+ ```
230
+
231
+
232
+
233
+ ![イメージ説明](17bde1156d45d617d693a5a864222ced.png)