10/15(火)-10/19(土) 岐阜県(南濃温泉「水晶の湯」)で自動運転車の実証実験を行います☆彡

14-7. k-meansで画像の階調を下げる

やること

k-meansというクラスタリング手法を用いて画像の階調を落としてみます。後半にパンケーキのお店当てクイズもついていますので、パンケーキ好きは挑戦してみてください。

参考にさせていただいたサイト

k-means法については説明が面倒 こちらの動画が分かりやすいです。

アルゴリズムがデータを分ける様子を可視化した【K-means】【クラスタリング】

こちらも同様に分かりやすい。

K-means 法を D3.js でビジュアライズしてみた
クラスタリングの定番アルゴリズム K-means 法(K平均法)の動作原理を理解するために、D3.js を使って可視化してみました。ステップ 最初からN (ノード数):K (クラスター数):新規作成図をクリックするか ボタンを押すと、1ステップずつ処理を行います ボタンを押すと、最初の状態に戻ります ボタンを押すと、...

こちらは sklearn.cluster.KMeans の使い方です。

scikit-learn でクラスタ分析 (K-means 法)
本ページでは、Python の機械学習ライブラリの scikit-learn を用いてクラスタ分析を行う手順を紹介します。 クラスタ分析とは クラスタ分析 (クラスタリング, Clustering) とは、ラベル付けがな …

実行環境

WinPython3.6をおすすめしています。

WinPython - Browse /WinPython_3.6/3.6.7.0 at SourceForge.net
Portable Scientific Python 2/3 32/64bit Distribution for Windows

Google Colaboratoryが利用可能です。

Google Colab

コード

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)

SNS等でお気軽にご連絡ください

※当ブログに関することは何でもご相談・ご依頼可能です(Servicesになくても)
※TwitterはFF外の場合はDMではなく返信orメンションでお願いしますm(_ _)m

情報発信しています

質問・コメントはSlackやDiscordでお気軽に

勉強会の告知はこちらで

画像処理
この記事を書いた人

博士(理学)。専門は免疫細胞、数理モデル、シミュレーション。米国、中国で研究に携わった。遺伝的アルゴリズム信者。物価上昇のため半額弁当とともに絶滅寸前。

この記事をシェアする
Vignette & Clarity(ビネット&クラリティ)
タイトルとURLをコピーしました