画像をドット絵風の低画質に変換するTwitter Bot「低画質」を作った

※追記①

パラメーターいじりながらweb上でドット絵風低画質画像を作れるようにしたのでこちらのエントリもよろしく。

※追記②

雑だけどPythonコマンドライン版も置いとく。



概要

画像をドット絵風の低画質に変換するTwitter Botを作った。

jpg/png/gifの静止画を@teigashitsuに対してリプを飛ばすと、ドット絵風の低画質画像が返ってくる。

例えばいらすとやのこの画像が、

f:id:razokulover:20170212144706p:plain

ドット絵風低画質になるとこう。

f:id:razokulover:20170212144749p:plain

サーバルちゃんのこの画像*1が、

f:id:razokulover:20170212144852p:plain

こう。

f:id:razokulover:20170212144913p:plain

このように味わいある画像に変換してリプライを返す。

きっかけ

iPhoneをはじめ世間は日々解像度を上げつづけている。

Deeplearningの発展はめざましく低画質な画像を高画質に補正する技術はすでに実用段階にある。

そんな中、低画質画像の存在はまさに絶滅の危機に瀕していると言っても過言ではない。

しかし、低画質画像が世の中から消えてしまっても良いのだろうか。

低画質画像があるからこそ高画質が輝くのではないか。

必要を超えた人間の傲慢さがいくつもの生物を絶滅の道へと追いやってきたことを忘れたのだろうか。

低画質画像を絶滅させてはいけない。

そんな警鐘を人類へ送るために我々は立ち上がったのだ…

みたいなテンションで最近覚えたてのPythonでごにょごにょ弄ってたら良い感じの画風に変換する手法ができたので作ってみた。

技術的なこと

実は今回のドット絵風の低画質画像のアルゴリズムには先行実装がある。

アルゴリズムについてはこのエントリに詳しく書いてあるが、何も別に難しいことはない。

  • 1) 画像を1x1ピクセルより大きいサイズで分割する
  • 2) 分割した各領域の色の平均値を算出する
  • 3) 算出した色をkmeans法でクラスタリングし、色数を減らす
  • 4) 各分割した領域をクラスタリングされた色で塗りつぶす

これだけ。

要は色数の少ない低画質画像だ(なのでドット絵に変換Botとはドッター諸氏にキレられそうで書けなかった)。

先行実装の方ではJavascriptCanvasでやっているのでクラスタリングの実装も素で書く必要があり少々難しいと思うが、PythonにはNumpyとSklearnがあるので画像のフィルターやクラスタリングの処理は手軽にできる。

ただ、少し悩んだのが画像を2x2や3x3のフィルタで分割処理していくところ。

こんな感じでFor文を使いながら書いたのだけどまだPythonをはじめて日が浅いのでNumpyっぽい感じがしない。もっと良い書き方がある気がする。

以下その擬似コード

# 4x4のフィルタで画像を上から下まで全体をモザイク上に処理していく
from PIL import Image
img = np.array([Image.open('./sample.jpg')])
height, width = img.shape[:2]
dh = round(height / 4)
dw = round(width / 4)
row_step = 0
col_step = 0
# 問題の箇所
for i in range(dh):
    for j in range(dw):
        cell = img[row_step:row_step+4, col_step:col_step+4]
        mean_rgb = cell.mean(axis=(0, 1))
        img[row_step:row_step+4, col_step:col_step+4] = mean_rgb # 4x4の領域の平均色でその領域を塗りつぶす
        col_step += 4
    col_step = 0
    row_step += 4

Numpyはピクセルを全てなめていくような処理は良くないと聞くしいいやり方あったら知りたい。

あとはBot化については、

  • TwitterのStreaming apiでリプライを監視してリプライが来たらsqliteにデータを突っ込むワーカー
  • sqliteからデータを取り出して変換してリプライを返すワーカー

の2つを作成してEC2で動かしてる。

Pythonを使ってサーバー上にアプリを構築するのははじめてでよくわからなかったが、とりあえずPython3.5.1で動かしてる。

今回は画像のリサイズとIOはPillow、クラスタリングはscikit-learn、Twitter系の操作はTweepy、あとは標準のライブラリを使っている。

数値計算機械学習系のライブラリが揃ってるPythonの便利さがわかって良い学びとなった。

まとめ

最初はただの低画質画像生成スクリプトを書いて遊んでいたのだが、パラメータを色々いじって画像を食わせてるうちに味わいある画像がうまれることがわかりBotにすることにした(大きい画像の方が低画質感がでるのでオススメ)。

見る専だがドット絵が好きでよくみるので(正確には全然ドット絵では無いが)こうやって自分でもそれっぽいものを生成させられるのは気分が良い。

TwitterAPI制限で大量のリプライには耐えられないし、耐えるような措置も取るつもりはないけど低画質画像の味わいを感じたい人はぜひ使ってみてください。