やること
k-meansというクラスタリング手法を用いて画像の階調を落としてみます。後半にパンケーキのお店当てクイズもついていますので、パンケーキ好きは挑戦してみてください。
参考にさせていただいたサイト
k-means法については説明が面倒 こちらの動画が分かりやすいです。
こちらも同様に分かりやすい。
こちらは sklearn.cluster.KMeans の使い方です。
実行環境
WinPython3.6をおすすめしています。
Google Colaboratoryが利用可能です。
コード
sklearn.cluster.KMeans のおかげでクラスタリングは数行で終わります。丁寧にコメントを入れてもこの程度です。
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
#============================
# パラメータ
#============================
#画像
file = 'hoge.jpg'
#何色に落とすか
n_clusters = 5
#============================
# 前処理
#============================
#画像読み込み
img = Image.open(file).convert('RGB'); img.close
#画像をたて200pxにリサイズする
w, h = int(img.size[0] * 200 / img.size[1]), 200
img_resize = img.resize((w, h), Image.BICUBIC)
#表示
print('img_resize')
plt.imshow(img_resize)
plt.show()
#(-1, 3)次元の配列に変形、-1は適当に判断してくれる
img_array = np.array(img_resize).reshape(-1, 3)
print('img_array.shape\n{}'.format(img_array.shape))
#============================
# k-means
#============================
#k-meansのオブジェクト
km = KMeans(n_clusters=n_clusters)
#計算を実行
km.fit(img_array)
#各クラスタの重心
km_centers = km.cluster_centers_
print('km_centers\n{}'.format(km_centers))
#計算結果に応じてクラスタリング(クラスタ番号の配列が返ってくる)
km_predict = km.predict(img_array)
print('km_predict.shape\n{}'.format(km_predict.shape))
#============================
# 後処理
#============================
#クラスタ番号を2次元に戻す
img_predict = km_predict.reshape(h, w)
print('img_predict.shape\n{}'.format(img_predict.shape))
#表示
print('img_predict')
plt.imshow(img_predict)
plt.show()
#クラスタ番号をクラスタ重心に置き換える、(h, w, 3)次元になる
img_final = np.empty((h, w, 3), dtype=int)
for i in range(n_clusters):
img_final[img_predict==i] = km_centers[i]
print('img_final.shape\n{}'.format(img_final.shape))
#表示
print('img_final')
plt.imshow(img_final)
plt.show()
5階調のときの出力です。
img_resize
img_array.shape
(59800, 3)
km_centers
[[ 30.12513446 41.97968208 19.47579778]
[219.39103917 214.34248182 198.82237861]
[173.46803045 66.32949572 10.8 ]
[204.4928753 167.28275437 77.73619348]
[ 99.0330566 106.72875472 47.45916981]]
km_predict.shape
(59800,)
img_predict.shape
(200, 299)
img_predict
img_final.shape
(200, 299, 3)
img_final
画像をリサイズして、(たて, よこ, RGB) という3次元情報だったものを (一列, RGB) すなわち img_array.shape=(59800, 3) に伸ばします。これを k-means にかけます。km_predict はクラスタ番号が並んだ配列です。km_centers は各クラスタの重心で、これがRBGの色になります。km_predict を (たて, よこ) の2次元に戻してやって、各要素に重心RGBを入れてやると、(たて, よこ, RGB) の出力画像となります。
こちらの写真を入力しました。どこのお店で撮ったものでしょうか?(難易度★★★☆☆)
20階調。ペイント感があっていいですね。
10階調。まだいけます。
5階調。このあたりがギリギリでしょうか。
ちなみにこちらはPowerPointのアート効果>カットアウト(影の数=3)です。5~10階調くらいに相当しそうです。
他の例
私がこれまでに撮ったパンケーキコレクションの一部です。左が元画像、右が10階調です。
FLIPPER’S(全国)
38mitsubachi(仙台)
花きゃべつ(自由が丘)
Clinton St. Baking Company(Newyork)