🌝絵文字の月で繊細な絵を描くで🌚
表現力の幅の拡げるのは難しい。でもプログラムでおもろい絵や動画をつくるならどうしても必要やねんってことで、過去の流行リバイバル。
2018年ごろにバズった、月の絵文字をつかったモザイクアートを採り上げてみよう。そんで、これをちょこっと改良したろ。
🌑🌒🌓🌔🌕🌖🌗🌘 + 🌝🌚
これらで絵を描くことを月描(つきびょう)とここでは呼ぶことにするで。線や塗りをつかわず点だけで描く絵画技法を点描(てんびょう)と呼ぶのに合わせて。
作例
繊細に月描された地球。元ネタは地球の絵文字🌏。
地球は月だった…?
参考サイト
元ネタ
まっさきに参考にしたのはこちらの記事。プログラミング言語Pythonによって自動化された絵文字アート。
そしてこちらの改良案も参考に。
方針決定
今回は上記のアルゴリズムを改良する方針でいこう。じつは上のひとつ目の記事のコメント欄にこんな示唆が。
たしかに。そしてコメントに添付された作図例がよくできてるんよね。おそらくこちらのGitHubページ(mogamoga1024 / MoonEmojiArt)にそのアルゴリズムがあるのですが。ちょっと理解がむずかしかったので別方向で実現を目指そうというわけで。
アルゴリズム
方針
画像を4×4ピクセルのブロックに分割し、それぞれのブロックの情報をもとに月の絵文字に変換。これは「月で絵を描きたいだと?それならpythonに任せなさい🌝」記事にて示された方針を踏襲。
「月の満ち欠けの絵文字で文章を書く」記事では、月の絵文字に変換するにあたり4×4ピクセルのブロックの情報を1×4ピクセルの情報に落として計算量を軽減する工夫を加えてるんよね。これが素晴らしい改良で。
というのも、月の絵文字はどれも上下反転について対称やから。
🌑🌒🌓🌔🌕🌖🌗🌘
4×4の2次元ブロックを縦方向に平均をとって1×4の1次元配列にしちゃっても月に変換するなら問題ないと。上下対称やから。
ただ「月の満ち欠けの絵文字で文章を書く」記事の目的が「文章を書く」なので繊細さを求めないアルゴリズムになってるからさらに改良が必要やねんというのが今回の記事の眼目。
改良案
改良するにあたってまず考えたのは、あるブロック(4×4ピクセル)があればそのブロックだけをみて変換先の月の絵文字を決めたいなと。要するに、あるブロックの周りにある別のブロックを参照しないと絵文字が確定しないようなものは面倒やと。
そんで、2次元ブロックを縦方向に平均をとって1次元配列にしちゃうという方針は踏襲したい。
🌑🌒🌓🌔🌕🌖🌗🌘
そんな感じでこれらの絵文字をながめれば、まず「どれだけの明るさがあるのか」。そして「明るいのは右か左か」を判定すればいいってことに気付いた。
明るさは1次元配列の平均を取ろかと。左右の明るさの判定は1次元配列の差分の平均を取ろかと。「差分」というのがミソになるわけやね。
Pythonコード
本質的な部分だけ。PILモジュールをつかって画像を読み込み、グレースケール化してブロックごとに分ける処理は参考サイトのものがほぼ使えるはず。
def get_moon(block):
col_ave = np.average(block, axis=0)
block_ave = np.average(col_ave)
col_diff_ave = np.average(np.diff(col_ave))
right_side_is_brighter = col_diff_ave >= 0
threshold_ratios = [0.99, 0.7, 0.5, 0.3, 0.01]
brightness_ranges = [block_ave >= (255 * r) for r in threshold_ratios]
if brightness_ranges[0]:
return "🌕"
elif brightness_ranges[1]:
if right_side_is_brighter:
return "🌔"
else:
return "🌖"
elif brightness_ranges[2]:
if right_side_is_brighter:
return "🌓"
else:
return "🌗"
elif brightness_ranges[3]:
if right_side_is_brighter:
return "🌒"
else:
return "🌘"
elif brightness_ranges[4]:
return "🌑"
else:
return "🌚"
いやなんか月の種類が多いな…🌚
なんか可愛げのある顔つきの月絵文字2種🌝🌚。これもよく見れば明暗の違いとして使えそうやんってことで含めてみた。🌙こういうのは幅が一定じゃなくてうまいくいかず。
と思ったものの、🌝も明るさを指定するのがむずかしく使用断念。🌚は単純に一番暗い部分に当てればいいけど、🌝は考えるべきことが増えすぎてダメやと結論。
さらなる改良に向けて
上のコードでは明るさのしきい値を決め打ちしてるんやけど、変換元の画像全体の情報から自動で算出してもいいかも。とにかく、しきい値の設定アルゴリズムがミソやね。
もっとこだわるならグレースケールのアルゴリズムに注目すべきかも?「Python でグレースケール(grayscale)化」記事が参考になるけど、どうでしょう。
感想
Pythonをつかえば色んなモザイクアートを自動で作れるんよね。たとえば画像であったり、文字であったり、月以外も含む絵文字であったり。
でも月という単純でバリエーションの少ないものから、けっこう繊細な絵が再現できるっていうのはかなり面白いなと。
対称性をつかってアルゴリズムを単純にするっていうのもやりがいあるし。
題材もパブリックドメインで拾えるし。
お試しあれ。
この記事が気に入ったらサポートをしてみませんか?