RPGツクールと数学のブログ

RPGツクールと数学についてのブログです。

k-means法で減色

過去ブログの転載です。

k-means法とはクラスタリングの手法の一つです。数あるクラスタリングの中でもとても実装が簡単で、割と速く収束して結果が得られるという利点があります。k個の平均値を使って、その平均値に近いグループにデータを割り当ててやろうという考えです。

f:id:fermiumbay13:20190802013357p:plain

たとえばこんなふうに、2次元平面上にまばらな点があります。これを3個の分類してみましょう。k=3とします。

f:id:fermiumbay13:20190802013407p:plain

k-means法を行うには、初期値を決める必要があります。結果が初期値に大きく依存してしまうのが欠点です。このてきとうに与えた3点を初めの平均値としましょう。

f:id:fermiumbay13:20190802013416p:plain

次に、各データがはたしてどの平均値に近いかをそれぞれ求めます。赤に近い点は赤になります。この場合は赤が多いですね。実は目で見て何となくでやっているので、嘘が混ざっているかもしれません。

これでデータが3つに分かれました。でも分かれた感じがしないですよね。

f:id:fermiumbay13:20190802013516p:plain

そこで、新しく決まったこれらのデータの平均を計算しなおします。すると、平均を意味する×印の位置はちょっと変わります。

f:id:fermiumbay13:20190802013532p:plain

あとはその繰り返しです。再び×印に近いものを色分けします。例がよろしくなかったですね。この場合は1つの点が赤から緑に変わっただけです。そしてまた平均を求めて×印の位置を変えて……というのを、変化がなくなるまで繰り返せばOKです。

f:id:fermiumbay13:20190802013542p:plain

最終的にこんな感じになりました。どうしても初期値に依存するので初め思っていたのとちょっと違うのですが、まあ、ちゃんとそれっぽく3つに分けてくれたので良いでしょう。

この方法を使って、減色をやってみます。

f:id:fermiumbay13:20190802013553p:plain

Windows10の時代になったこのご時世で、未だに私はXPのペイントを使っているのですが、jpg形式で保存するとずいぶんひどい画質になってしまっています。

ペイントでかいた画像なので、単純な色に戻したいわけです。

色をいくつかあらかじめ指定しておいて、それに近い色を選ばせてやればそれで実現できるのですが、色の指定がめんどくさいので、k-means法を用いて色の数kだけ与えて勝手に振り分けてもらいましょう。

f:id:fermiumbay13:20190802013603p:plain

色に対してk-means法を適用するイメージです。色は3原色の光量で一意に決まりますので、このような3次元空間上の点と考えることができます。

近い色の距離同士は近いので、この距離を用いてk-means法を適用すれば、勝手に色を分けてくれるようになるという仕組みです。

16色に分けてみて、初期値となる色は彩度、明度が最大で、色相だけ異なるようにしました。各画素をデータと考えて、k-means法を適用します。

f:id:fermiumbay13:20190802013616p:plain

29回目で収束しました。結構はっきり分かれてくれましたね。残念ながら、ざらざらした点がいくつか含まれてしまっているので結果は微妙ですが、少なくとももとのjpg画像と比べれば色が単純化したのが確認できます。

ベイ助とベイ太の体の色(体毛なのだ)はちゃんと単色になってますね。ベイ助の服のBの字がおかしいですけど……

実用させるには、ぼかし等と併用したほうが良いかもしれません。

f:id:fermiumbay13:20190802013627p:plain

今度はベイ助単体。jpgで保存したので、もやもやが出来てしまっています。これを適用してみます。10色でやってみました。

f:id:fermiumbay13:20190802013639p:plain

今度は10回で収束しました。

若干赤が濃かったり、細かい色が省かれていたりしますが、だいたい抽出できてますね。大丈夫そうです。

f:id:fermiumbay13:20190802013649p:plain

次はチーター君。jpg保存じゃないのですが、保存の都合でずいぶんぼけてます。こちらもとりあえず16色でやってみました。

f:id:fermiumbay13:20190802013658p:plain

66回で収束しました。遅いですね……しかも輪郭の部分のぼけたところが全部別の色になってしまい、うまく分離されていないことが分かります。色数を多くした弊害でしょう。

f:id:fermiumbay13:20190802013709p:plain

16色じゃなくて、6色に落としてみると、こうなりました。やっぱり輪郭部分に持っていかれてますね……初期値をうまいこと設定してやれば何とかなるのかもしれません。

f:id:fermiumbay13:20190802013721p:plain

次は写真です。これは稚内のノシャップ岬であります。

実際、k-means法を使うなら、このように具体的な色を指定せずに特定の色数に減色することに適用するのが良いでしょう。今の時代、画像の減色なんてほとんどされないのかもしれませんが……

16色で適用してみます。

f:id:fermiumbay13:20190802013731p:plain

18回目ぐらいでほぼ変化しなくなったので途中で切りました。いいですね。とても16色しか使用されていないなんて思えません。

まあこんな遊びができるわけでございます。