回答編集履歴
1
追記
test
CHANGED
@@ -1,16 +1,4 @@
|
|
1
|
-
```
|
2
|
-
|
3
|
-
cv2.cvtColor(image_bgr, cv2.COLOR_BGR2LAB)
|
4
|
-
|
5
|
-
|
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
|
-
|
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
|
-

|
164
|
+
|
165
|
+

|
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
|
+

|