アニメとポスターの色, あるいはK-means法
はじめに
この記事はProlab Advent Calendar 2017 - Adventarの第7日目として執筆されています。またこの記事はフィクションであり、登場する団体・人物などの名称はすべて架空のものです。同様に時間に非常にだらしなく変にバランス主義者で友達の友達の格言である「日常生活の問題が解けずしてどうしてアルゴリズムといえようか」を受け売りにしている高専6年生の柏木ひのきさんも架空の人物であることを了承ください。
ポスターの色ってどうやって決めればいいんだっけ?
事の発端
突如ポスターを作る必要がでてきたひのき(@KashiwagiHinoki)はどのようにして色を決めるかという非常に悩ましい問題に直面した。三日三晩悩んだ末(三日三晩って初めて書いた気がするんですけど、日と晩の疾走感すごいですね)、休憩中にARIAを読み少女終末旅行を観終えたところで突然(実現可能の是非は置いといて)3つの妙想を得たのであった。
いんすぴれーしょn
彼は以下の3つの妙想を得た(ARIAと少女終末旅行のおかげだと思います)。そしてまず比較的難易度が低そうなものから列挙していったのであった。
- 今から自分の遺伝子を強い画家の遺伝子に変える
- 好きな画像の色を参考にする
- 今から色の勉強をする
また、彼のノートにはこのような内容のメモが記されていた。
今から自分の遺伝子を強い画家の遺伝子に変える
植物になるよりも強い画家になる方が簡単だと思われます。
好きな画像の色を参考にする
これも上のアイデアの次に並ぶくらい有効であると思われます。ただし、僕は色の調和などがほとんどわからないので、何色か代表の色の組み合わせを作ることができるとより実現性が増すと思われます。
今から色の勉強をする
これも有効な手法であると思います。ただし、これには少し時間がかかりすぎるという欠点もあるので、選択はしづらいと思われます。
選択した手法
彼は最終的に2つ目の好きな画像の色を参考にすることを選んだ。柏木ひのきという人物は変なところで頑ななところがあり、なるべくバランスを取ろうという癖があった。そのため、彼は1でも3でもなく2を選んだのである。しかし、2を選択すると1つの問題が生じる。色の調和がうまくわからない彼は適当な色の組み合わせを出力してくれる装置がどうしても必要となるのだ。 そして、もちろん彼のポリシーによりアルゴリズムで殴って解決することを念頭に置いて考えるのであった。
クラスタリング?
去年、ひのきはたいちゃんさんとぺるきらさんにクラスタリングなる単語を教えてもらっていたのである。いわく、クラスタリングとはデータの集まりをうまい具合に分割する手法のことで、一つのデータ解析手法であるらしい。彼はとりあえずグーグル先生に"クラスタリング 簡単"と検索をして一番最初に出てきたものを実装しようと考えたのであった。そしてk-平均法(k-means clustering)に出会う。
k-means clustering
k-means clusteringとは以下のようなものである。
おそらくこれを使えばいい感じな色の組み合わせができるだろうと彼は得も言われぬ確信をしたのであった。
実装
import numpy as np
import cv2
import random
def k_means(vec_list, k):
(nums, dims) = np.shape(vec_list)
cluster = [random.randint(0, k - 1) for i in range(nums)]
centered = np.zeros((k, dims))
for loop in range(100):
_centered = np.zeros((k, dims))
cluster_num_list = [0] * k
for (c, v) in zip(cluster, vec_list):
_centered[c] += v
cluster_num_list[c] += 1
for i in range(k):
if(cluster_num_list[i] != 0):
_centered[i] /= cluster_num_list[i]
for i in range(nums):
for j in range(k):
if(np.linalg.norm(vec_list[i] - _centered[cluster[i]]) > np.linalg.norm(vec_list[i] - _centered[j])):
cluster[i] = j
eps = sum([np.linalg.norm(centered[i] - _centered[i]) for i in range(k)])
if(eps < 0.001):
return _centered
centered = _centered
print(centered.astype('int32'))
image_file = 'gazou.jpg'
image = cv2.imread(image_file, cv2.IMREAD_COLOR)
k = 3
color = np.reshape(image, (-1 , 3))
_color = np.zeros((2000, 3))
for i in range(2000):
_color[i] = color[random.randint(0, len(color - 1))]
color_scheme = k_means(_color ,k)
print(color_scheme)
このコードは柏木ひのきの最大限の努力によって作られたものである。確かに指摘は欲しいが、なるべく優しい口調で伝えてくれるとなおうれしくなるだろう、彼はそういう生き物である。
実験
この記事を最初からもしくは最後から見てもわかるように、オタクでありそして今期の推しは間違いなく少女終末旅行である。
結果
縦1列が一つの色の組み合わせで左からk = 3、k = 4、k = 5、k = 6(kは重心の数)となんともうまくいっているようである。彼はその後三日三晩(日と晩の疾走感)、小躍りをしたらしい。
まとめ
1月ごろにそのポスターがタイで柏木ひのきが使っていると思うので、そのときちょうどタイにいて興味があるよーって人は頑張って探してみるとよいと思う。また、タイにいない人でも今から-30 ~ -40日後に日本からタイに泳ぎ始めれば彼がちょうどポスターを使っている時期につくと思うので、体力に自身ニキorネキはぜひ頑張ってほしい。
次回予告
やめて!学校の課題をこれ以上積まれたら、闇のゲームで単位とつながっている柏木の精神まで燃え尽きちゃう!
お願い、死なないで柏木!あんたがここで倒れたら、親との約束はどうなっちゃうの?時間はまだ残ってる。ここを耐えれば、テストに勝てるんだから!
次回、「柏木死す」デュエルスタンバイ!