【機械学習】scikit learnでの画像減色プログラム

こんにちは。
林@[アイエンター](http://www.i-enter.co.jp)です。

前回の[ブログ](http://qiita.com/m-hayashi/items/bbd90806328af66906e8)では、[Pandas](http://pandas.pydata.org)やデータ可視化用の[Seaborn](https://stanford.edu/~mwaskom/software/seaborn/)を導入し、米国自動車株の解析を行いました。

今回は再び[scikit-learn](http://scikit-learn.org/stable/)にフォーカスして、機械学習のクラスタリングで用いられる「[k平均法（k-means）](https://ja.wikipedia.org/wiki/K%E5%B9%B3%E5%9D%87%E6%B3%95)」で画像の減色処理を行ってみます。
また、今回は画像の扱いには「[OpenCV](https://ja.wikipedia.org/wiki/OpenCV)」も使ってみることにします。
# k平均法での画像減色
k平均法とは[Wiki](https://ja.wikipedia.org/wiki/K%E5%B9%B3%E5%9D%87%E6%B3%95)に詳細が記載されておりますが、空間上の点群データをk個のグループに分類するアルゴリズムです。

アルゴリズムから、各点がどこのグループに所属するかと、その各グループの重心の座標が算出できます。

今回は画像データから画素ごとのRGBを取得して、3次元空間の点群として考えます。

例えば画像を8色に減色する場合は、点群を8グループに分類します。
その後に各グループに含まれる点（RGB）の値を、重心の座標（RGB）で
置き換えることで、画像の8色化を実現します。

# OpenCVでの画像の読み込み
今回はこの猫の画像を8色に減色してみます。
![cat.jpg](https://qiita-image-store.s3.amazonaws.com/0/134453/140159e8-ea93-0ec3-1c62-550f68c8b41f.jpeg)


まずは、jupyter notebookで解析をしていく際の、基本ライブラリをインポートします。![shot1.png](https://qiita-image-store.s3.amazonaws.com/0/134453/4510212e-30f0-59cc-7ba5-dfde0aa859ca.png)

また、今回はOpenCVを用いるのでcv2ライブラリのインポートと、
scikit-learnのclusterライブラリから、k平均法のKMeansを用いることにします。
![shot2.png](https://qiita-image-store.s3.amazonaws.com/0/134453/7e688686-2613-dc24-50d2-296d0298fd64.png)

画像の読み込みは、cv2のimread関数で簡単に読み込みができます。
![shot3.png](https://qiita-image-store.s3.amazonaws.com/0/134453/0ff1dcca-9e66-d396-791d-0584b80cc49f.png)

読み込まれたイメージデータの中身を確認してみます。
![shot4.png](https://qiita-image-store.s3.amazonaws.com/0/134453/2dbc4599-2f0a-aad7-2e99-f5003373c864.png)

arrayになっているようです。shapeでarrayの構造を確認してみます。
![shot5.png](https://qiita-image-store.s3.amazonaws.com/0/134453/bf932f99-2e18-28ab-aa80-7106557d4977.png)

縦幅640、横幅480でRGB要素が含まれた配列ということが見て取れます。

ただ、ここで注意が必要なのは、OpenCVで読み込まれたデータは、
色データはBGRの順番で格納されています。

試しにイメージをそのまま表示してみると、こんな見え方をします。
![shot6.png](https://qiita-image-store.s3.amazonaws.com/0/134453/7dc8cf9b-9be1-83d0-5e0a-8d97c630b8f1.png)

RGBの順番に変更するためには、cv2.cvtColorで変換を行います。
![shot7.png](https://qiita-image-store.s3.amazonaws.com/0/134453/210647d5-a34c-9280-97df-2db9339a4c82.png)

再度、表示してみると正しい色合いで表示されることが確認できるかと思います。
![shot8.png](https://qiita-image-store.s3.amazonaws.com/0/134453/2ec258d9-f420-3350-3c75-e19fbba57039.png)

# 機械学習モデル KMeansでの色変換処理
KMeansのモデルデータを作成して、OpenCVで読み込んだデータを加工していきます。
![shot9.png](https://qiita-image-store.s3.amazonaws.com/0/134453/439778d4-16b4-8078-11f6-d12f167f32d8.png)

イメージデータを機械学習のトレーニングデータとして扱うため、RGBデータが並んだフラットな配列に変換します。
![shot10.png](https://qiita-image-store.s3.amazonaws.com/0/134453/b1b8de5c-0c9e-b4e1-8c43-50507fe7fc28.png)

トレーニングデータをKMeansモデルに適用します。
![shot11.png](https://qiita-image-store.s3.amazonaws.com/0/134453/cc2c7354-b3c6-3f9a-d32e-a1c4e8ce1355.png)

これによって、8グループの重心データ配列が取得できます。
モデルデータのcluster_centers_に格納されています。
![shot12.png](https://qiita-image-store.s3.amazonaws.com/0/134453/ac84bd57-d298-fd8e-128a-d5926c91ea6f.png)

次にトレーニングデータ自体を用いて、モデルデータで予測処理を行ってみます。
![shot21.png](https://qiita-image-store.s3.amazonaws.com/0/134453/fc833aa5-f0c8-9fda-8e17-3d6f22092ee2.png)

ワーニングが出ていますが以降の処理に影響しないので、そのまま進めていきます。
予測処理を行った結果のYの中身を確認してみます。
![shot14-2.png](https://qiita-image-store.s3.amazonaws.com/0/134453/9728f78d-7a90-8d8a-2493-ed2555dd07a6.png)

この配列は、各点群がどこのグループに所属されているかの配列データになっています。

OpenCVで扱うRGBデータは整数値なので、重心データの色配列の要素を整数化します。
![shot15.png](https://qiita-image-store.s3.amazonaws.com/0/134453/e990f361-6e58-3e0e-6af6-460304adf313.png)

変換後のイメージを生成します。
空の配列を用意して、各点について重心のRGBに変換したデータを追加して行きます。
![shot16.png](https://qiita-image-store.s3.amazonaws.com/0/134453/76d6c9a9-1011-2163-1a9d-b794fef2f548.png)

上記で生成された配列は、OpenCVのイメージ配列の次元になっていません。
reshapeして（640×480×3）の配列に変換します。

![shot17.png](https://qiita-image-store.s3.amazonaws.com/0/134453/5f55be07-1c63-af77-618d-3b4b3f5282da.png)

生成されたイメージを表示してみます。
![shot18.png](https://qiita-image-store.s3.amazonaws.com/0/134453/79aa87bb-9383-c3a7-88fa-2dc83cd6ee24.png)

それっぽく減色されているように見えます。
最後にOpenCVで画像ファイルに出力します。

OpenCVでは色の並びはBGRでしたので、変換したイメージも同じように色の並びを変えてやります。
![shot19.png](https://qiita-image-store.s3.amazonaws.com/0/134453/617d20e8-d7e9-f356-9e82-ef77fd3ec690.png)

画像ファイルをcv2.imwriteで出力します。
![shot22.png](https://qiita-image-store.s3.amazonaws.com/0/134453/640843a8-25fd-1ef6-8c02-c3d3d5ac8569.png)

以下が出力されたファイルになります。
![img_cnv.jpg](https://qiita-image-store.s3.amazonaws.com/0/134453/aa752d7c-0573-3b87-d25b-e54f0228193d.jpeg)

scikit learnのKMeansモデルとOpenCVライブラリを用いることで
比較的簡単に画像の減色を行うことが出来ます。

今回のお話はここまで！