要約
あ…ありのまま 今 思った事を話すぜ!
「文字が文字で作れたら面白いよね?」
何を言っているのか わからねーと思うが、
おれも 何を言っているのか分からない。
- 兎に角、下記の作例集を見れば何がしたいのかが分かる。まずは見てね
- Colaboratoryで、前提一切不要&ブラウザだけですぐ動かせるよ
おれは 奴の前で文字を書いていたと思ったら
いつのまにか絵を書いていた。と思ったらやっぱり文字を書いていた。
頭がどうにかなりそうだった
作例集①
殺伐としたウニ
これがホントの「エビカニ、クス(笑)」
殺伐としたスレに鳥取県が!!
島根県 ( ※「矛盾塊」と呼ばれているらしい)
瀧「リューク、目の取引だ」
アイドルの方の三葉が死ぬっ!
EVA
こんなとき、どんな顔をしたらいいかわからないの
ごめんなさい。作例集を見ても
「何がしたいのか」は分からなかったかもしれない。
「何が出来るようになるのか」は分かったと思う。
作例集②も最後にあるよ。
全体的な設計
逆に考えるんだ。
文字(エビ)で絵を書くためには、
文字(エビ)を書く座標が決まっていれば良い。
書く場所の座標 = 0と1で出来た二次元リスト。
二次元リスト = 白黒画像(グレースケール)
あとは、フレームとなる文字(カニ)を画像化して、
その白黒画像に入れれば完成。
まとめると、以下のような流れになる。
カニ ⇒ 画像化 ⇒ 白黒画像 ⇒ 01二次元リスト ⇒ エビで埋める
↑とても技術解説とは思えない説明文字列だ
◆さあ、以下の段取りで開発を進めよう!
- 開発環境構築=不要(Colaboratory)
- Step1 文字を画像にする技術
- Step2 画像を白黒の01リストにする技術
- Step3 白黒リストを文字で埋め尽くす技術
- Step4 出来た関数のまとめ&最終的に画像に変換
開発環境構築=不要(Colaboratory)
今回は Colaboratory 上で、Python3 によって実装してみる。
ColaboratoryはGoogle様が用意してくれた
Jupyter&Pythonを簡単に実行出来る神環境。
ブラウザでアクセスするだけですぐに本記事のコードが試せる。
お手元の環境を汚さない。エコ仕様。
全コード掲載&すぐにコピペ実行出来るようになっているので、
ぜひオリジナルの文字絵アート&文字文字アートを作ってみてください!
(*´ω`)つ Colaboratory
Step1 文字を画像にする技術
準備:日本語フォントのインストール
Colaboratoryでは、最初に「!」をつけると
シェルコマンドの実行が出来る。
画像にしちゃう日本語フォントをインストールしてみよう。
!apt-get -y install fonts-ipafont-gothic
インストールされたフォントのパスを確認してみよう。
import matplotlib.font_manager as fm
fonts = fm.findSystemFonts()
for font in fonts:
print(str(font), " ",fm.FontProperties(fname=font).get_name())
# 出力は省略。こんなパスの場所を確認出来る
# /usr/share/fonts/truetype/fonts-japanese-gothic.ttf
文字列を画像にする関数
Pythonの画像処理ライブラリ(Pillow)で
白色背景画像に文字を書き込み、
全体を画像として保存する。
これで、好きな「文字」を「画像」に出来る。
from PIL import Image, ImageDraw, ImageFont
## 与えられた文字列を、画像にする関数
## 1文字あたりのサイズ&縦横の文字数も引数で指定
def str2img(input_str, yoko_mojisuu, tate_mojisuu, moji_size):
# 真っ白な背景画像を生成する
# 横(縦)幅 = 文字サイズ× 横(縦)文字数
img = Image.new('RGBA', (moji_size * yoko_mojisuu , moji_size * tate_mojisuu), 'white')
# 背景画像上に描画を行う
draw = ImageDraw.Draw(img)
# フォントの読み込みを行う。(環境によって異なる)
myfont = ImageFont.truetype("fonts-japanese-gothic.ttf /usr/share/fonts/truetype/fonts-japanese-gothic.ttf", moji_size)
# 文字を書く。基本は以下で済むが、今回は1文字ずつ記入
# draw.text((0, 0), input_str , fill=(0, 0, 0), font = myfont)
# ※備考:1文字ずつ記入の場合、半角と全角を区別しないといけなくなる
# (今回は全角前提とする)
# fillは、文字の色をRBG形式で指定するもの。今回は黒なので0,0,0固定
# 縦横のサイズに合せて1文字ずつ描画
yoko_count = 0
tate_count = 0
for char in input_str:
#縦の文字数の許容量を途中でオーバーしてしまった場合は終了
if tate_count >= tate_mojisuu:
break
#所定の位置に1文字ずつ描画
draw.text( ( yoko_count * moji_size, tate_count * moji_size ), char, fill=(0, 0, 0), font = myfont)
yoko_count +=1
if yoko_count >= yoko_mojisuu:
yoko_count = 0
tate_count += 1
return img
出来た関数は以下のように使える
import matplotlib.pyplot as plt
img = str2img("勝利友情努力", 2, 3, 50)
plt.imshow(img)
「三本柱マン」が無事降臨!!
なお、以前に、
どこでもドアを作ってみた物語
においてもPillowで画像加工を実施したことがある。
文字だけでなく画像の合成等も可能だ。
Step2 画像を白黒の01リストにする技術
「文字」の画像の場合もともと白黒なのだが、
任意の画像を文字で表現することにも対応するため、
まず画像を「白黒化」し、各ピクセルを0~1の少数で表現する。
そして、閾値(その画像全体の平均値とする)と比較して
白い場合は「1」黒い場合は「0」にすれば、
あらゆる画像が「1」と「0」の2次元リストになるというわけ。
from PIL import Image, ImageDraw, ImageFont
# 与えた画像を、グレースケールのリストに変換する関数(白=1、灰=0.5、黒=0)
# 元がカラー画像でも対応出来るようにしている
def img2graylist(input_img):
#幅と高さを取得する
img_width, img_height = input_img.size
print('幅 : ', img_width)
print('高さ: ', img_height)
#最終的に出力する二次元リスト
result_graylist = []
for y in range(0, img_height, 1):
# 1行ごとのテンポラリリスト
tmp_graylist=[]
for x in range(0, img_width, 1):
# 1ピクセルのデータ(RGB値)を取得
#(20, 16, 17, 255)のように4つのデータが取れる⇒3つに絞って使う
r,g,b, = input_img.getpixel((x,y))[0:3]
#RGB値の平均=グレースケールを求める
g = (r + g + b)/3
tmp_graylist.append(g)
#1行終わるごとにテンポラリリストを最終出力に追加
result_graylist.append(tmp_graylist)
return result_graylist
# 与えたグレイリストを、白=1、黒=0のリストに変換する関数
# 黒が多い画像⇒全て黒、や、色の薄い画像⇒全て白、にならないように、
# 閾値として、平均値を取得した後で、その閾値との大小で判定する
# よって、薄い画像が全部白に、濃い画像が全部黒に、などはならない
import numpy as np
def graylist2wblist(input_graylist):
#与えられた二次元配列の値の平均値を求める(npを使っても良いが)
gray_sum_list = []
for tmp_graylist in input_graylist:
gray_sum_list.append( sum(tmp_graylist)/len(tmp_graylist) )
gray_ave = sum(gray_sum_list)/len(gray_sum_list)
print("灰色平均値: ", gray_ave)
# 最終的に出力する二次元の白黒リスト
result_wblist = []
for tmp_graylist in input_graylist:
tmp_wblist = []
for tmp_gray_val in tmp_graylist:
#閾値と比べて大きいか小さいかによって1か0を追加
if tmp_gray_val >= gray_ave:
tmp_wblist.append(1)
else:
tmp_wblist.append(0)
result_wblist.append(tmp_wblist)
return result_wblist
出来た関数は以下のように使える
#与えられた2次元文字列リストをプリントする関数(pprint的なもの)
#(※最終出力時には使わないが、途中経過を見る用途)
def print2Dcharlist(charlist):
for tmp_charlist in charlist:
for char in tmp_charlist:
#改行無しで出力
print(char, end="")
#1行終わるごとに改行
print()
img = str2img("般若波羅蜜多", 6, 1, 20)
graylist = img2graylist(img)
wblist = graylist2wblist(graylist)
print2Dcharlist(wblist)
出力結果:
01デジタル化された般若心経
Step3 白黒リストを文字で埋め尽くす技術
作った白黒リストの「0」の部分だけを(または「1」の部分を)
「文字」で置き換えれば、ほとんど完成に近い。
エビエビエビエビエビ・・・と繰り返して文字を取得/出力するため、
Pythonの「ジェネレータ」を使って実装してみる。
yield は return のようなものなので、
return に読み替えると分かりやすいかもしれない(説明雑)
# 文字列を一文字ずつ取り出すジェネレータ。半無限ループにより繰り返し
def infinity_gen_str(str):
for a in range(1000000000):
for s in str:
yield s
# 以下のように使う
# 定義:gen_str = infinity_gen_str("表示したい文字列")
# 使用:next(gen_str)
# これで、使用するたびに1文字ずつ出力される
# 白黒リストの、白黒の部分を文字列で埋め尽くした二次元リストを返す
# 白=soto_strで埋める。黒=nakami_strで埋める。
def wblist2wbcharlist(input_wblist, nakami_str, soto_str):
# 1文字ずつ出力できるジェネレータの生成
gen_nakami_str = infinity_gen_str(nakami_str)
gen_soto_str = infinity_gen_str(soto_str)
# 最終的に出力する二次元の白黒リスト
result_wbcharlist = []
for tmp_wblist in input_wblist:
tmp_wbcharlist = []
for tmp_wb_val in tmp_wblist:
# 値が1か0かによって、文字列を入れていく
# ※空白と等幅になる文字&フォントでやることが望ましい
if tmp_wb_val == 1:
# 1が白
# 空白固定ならコレでも同じ ⇒ tmp_wbcharlist.append( " " )
tmp_wbcharlist.append( next(gen_soto_str))
else:
# 0が黒
tmp_wbcharlist.append( next(gen_nakami_str) )
result_wbcharlist.append(tmp_wbcharlist)
return result_wbcharlist
出来た関数は以下のように使える
img = str2img("般若波羅蜜多", 6, 1, 20)
graylist = img2graylist(img)
wblist = graylist2wblist(graylist)
#print2Dcharlist(wblist)
# 今回は↑の外枠で「般若波羅蜜多」のフレーム(01)を作り、
# ↓の指定で、中身を「般若波羅密多」の文字列で埋める
wbcharlist = wblist2wbcharlist(wblist, "般若波羅蜜多"," ")
print2Dcharlist(wbcharlist)
この技術に狂気と恐怖を覚える
Step4 出来た関数のまとめ&最終的に画像に変換
ここまでで、以下の流れの全てが実装できた。
カニ ⇒ 画像化 ⇒ 白黒画像 ⇒ 01二次元リスト ⇒ エビで埋める
最後に、これらの処理のまとめと、
出来たエビのリストを画像にして保存するようにしよう。
最後の画像変換では、最初の「文字を画像化する関数(カニ⇒画像化)」を
再利用することが出来る!
def moji2mojiImg(flame_str, nakami_str, soto_str, yoko_len, tate_len, moji_size, final_moji_size):
# 引数サンプル
# flame_str = "般若"
# nakami_str = "般若波羅蜜多"
# yoko_len = 2
# tate_len = 1
# moji_size = 30
# 最後に表示する際のフォントサイズ
# final_moji_size = 12
img = str2img(flame_str, yoko_len, tate_len, moji_size)
graylist = img2graylist(img)
wblist = graylist2wblist(graylist)
wbcharlist = wblist2wbcharlist(wblist, nakami_str, soto_str)
# print2Dcharlist(wbcharlist)
# 作った配列を、str2imgで画像化する
# 作ったリストを全てつなげて単純文字列にする
# (※最初に作成したstr2imgに入れるための変換)
all_str = ""
for tmp_list in wbcharlist:
for char in tmp_list:
all_str += char
#今回のファイルのサイズは縦横は、moji_size倍されている点に注意
img = str2img(all_str, yoko_len*moji_size, tate_len*moji_size, final_moji_size)
return img
出来た関数は以下のように使える
img = moji2mojiImg("カニ","エビ"," ",2,1,20,15)
#正しく表示&ダウンロード出来るように、一度セーブする
img.save("ebikani.png")
#colaboratoryで表示
import IPython
IPython.display.Image("ebikani.png")
出力結果:
エビもカニも甲殻類
出来た画像をColaboratoryからダウンロードするには以下
from google.colab import files
files.download("ebikani.png")
(オマケ)画像を文字列で描画する技術
「文字」に文字を埋め込んで画像化することが出来た。
一方で、「画像」に文字を埋め込んで画像化することは、
実はより簡単に出来てしまう。
カニ ⇒ 画像化 ⇒ 白黒画像 ⇒ 01二次元リスト ⇒ エビで埋める
この、最初ステップのカニの画像化がなくなって、
直接画像の白黒化から始められるというだけ。
「アスキーアート」生成ツールの亜種的なものになる。
最後のStep4のまとめ関数をちょっと書き換えて実行してみる。
普段使うには 使わないけど こちらのほうが使いやすいかもしれない
def img2mojiImg(input_img, nakami_str, soto_str, final_moji_size):
img_width, img_height = input_img.size
#print('幅 : ', img_width)
#print('高さ: ', img_height)
#文字から画像を作る必要なく、input画像を使う
#img = str2img(flame_str, yoko_len, tate_len, moji_size)
graylist = img2graylist(input_img)
wblist = graylist2wblist(graylist)
wbcharlist = wblist2wbcharlist(wblist, nakami_str, soto_str)
#print2Dcharlist(wbcharlist)
#作った配列を、str2imgで画像化する
#作ったリストを全てつなげて単純文字列にする
#(※作成したstr2imgに入れるため)
all_str = ""
for tmp_list in wbcharlist:
for char in tmp_list:
all_str += char
#今回のファイルのサイズは縦横は、moji_size倍されている点に注意
img = str2img(all_str, img_width, img_height, final_moji_size)
return img
出来た関数は以下のように使える
「グンマー」の画像は別途用意して
Colaboratoryにアップロードしておく。
(※左上の「>」から「ファイル」を選ぶと、アップロード出来る)
img = Image.open("Gunma.png")
#幅と高さを取得する
img_width, img_height = img.size
print('幅 : ', img_width)
print('高さ: ', img_height)
#リサイズする場合は以下のような感じ
#元画像は幅640、高さ640
img = img.resize((40, 40))
result_img = img2mojiImg(img, " ", "栃木県", 14)
output_file_name = "satubatu_gunma.png"
result_img.save(output_file_name)
#colaboratoryで表示
import IPython
IPython.display.Image(output_file_name)
グンマーは何をやっても面白いのでとてもお得
作例集②(オマケ)
はらみった
つ「写経」を自動化し、オートで功徳を積める仕組みを作ってみたのでございます。
しろくろ
じわじわくる
止まれ。
もう何十回も言ったのよ!?って言える必殺技
見よ、人がゴミのようだっ!
「バルス!!」「目がぁ~!目がぁ~!」
新時代アート
つ 【続】平成の次の元号を、AIだけで決めさせる物語(@テレビ取材)
その…下品なんですが…フフ…勃起…しちゃいましてね…
いいや!限界だ(いいねを)押すね!今だッ!
つ PythonでHello 世界(ザ・ワールド)止まった時の世界に入門してみる。ジョースターの末裔は必読
あとがき
大喜利
技術を使った大喜利として、ネタを考えるのも楽しいかもしれません。
面白い文字文字アートの案や、作例が出来たら、
ぜひコメント欄に張り付けて教えてください!
応用例/アイデアメモ
応用例はいろいろありそう。
- 画像認識した部分を対応する文字に変える(車に認識された部分を「車」で表現など)
- TwitterやSlackのツール/ボット作成、サービス化
- 単純にアスキーアート生成技術として活用
- 文字の色を変更してカラフル化
- 濃淡に合わせて黒い文字/白い文字を使い分ける
- セリフの無いマンガの作成
- 薄い灰色で文字を印刷して、幼児/英単語などの書き取り練習帳に(書き終わると絵が浮かび上がる)
- 究極的に「ざわざわっ...」「ゴゴゴゴゴ」している絵の作成(著作権的な意味で今回はパス)
いつもの名言
ちょっとした遊び & Colaboratoryの実践入門として
楽しんでいただけたら幸いです♪
ブラウザでColaboにアクセス、上から順にコピペしていくだけですぐ試せます。
文字文字アートで一緒に遊びましょう。
人類の進化は「遊び」からはじまる。
こんな「遊び」が出来るならば、というアイデアに触発される人がでて、
生活にも役に立つような「発明」が生まれるのだ。
~ Char Fuitter (1847~1912 オランダ) ~
長文おつきあいいただきありがとうございました。
出力結果画像は自由に転載していただいて構いません。
Char Fuitter (チャー・フイター)は架空の人物です。