要約

あ…ありのまま 今 思った事を話すぜ!

「文字が文字で作れたら面白いよね?」

何を言っているのか わからねーと思うが、

おれも 何を言っているのか分からない。


  • 兎に角、下記の作例集を見れば何がしたいのかが分かる。まずは見てね

  • Colaboratoryで、前提一切不要&ブラウザだけですぐ動かせるよ

おれは 奴の前で文字を書いていたと思ったら

いつのまにか絵を書いていた。と思ったらやっぱり文字を書いていた。

頭がどうにかなりそうだった


作例集①


殺伐としたウニ

ebikani.png

これがホントの「エビカニ、クス(笑)」


殺伐としたスレに鳥取県が!!

satubatu_gunma.png

島根県 ( ※「矛盾塊」と呼ばれているらしい)


瀧「リューク、目の取引だ」

kiminona.png

アイドルの方の三葉が死ぬっ!


EVA

syogouki.png

こんなとき、どんな顔をしたらいいかわからないの


ごめんなさい。作例集を見ても

何がしたいのか」は分からなかったかもしれない。

「何が出来るようになるのか」は分かったと思う。

作例集②も最後にあるよ。


全体的な設計

逆に考えるんだ。

文字(エビ)で絵を書くためには、

文字(エビ)を書く座標が決まっていれば良い。

書く場所の座標 = 0と1で出来た二次元リスト。

二次元リスト = 白黒画像(グレースケール)

あとは、フレームとなる文字(カニ)を画像化して、

その白黒画像に入れれば完成。

まとめると、以下のような流れになる。

カニ ⇒ 画像化 ⇒ 白黒画像 ⇒ 01二次元リスト ⇒ エビで埋める

↑とても技術解説とは思えない説明文字列だ

◆さあ、以下の段取りで開発を進めよう!


  • 開発環境構築=不要(Colaboratory)

  • Step1 文字を画像にする技術

  • Step2 画像を白黒の01リストにする技術

  • Step3 白黒リストを文字で埋め尽くす技術

  • Step4 出来た関数のまとめ&最終的に画像に変換


開発環境構築=不要(Colaboratory)

今回は Colaboratory 上で、Python3 によって実装してみる。

ColaboratoryはGoogle様が用意してくれた

Jupyter&Pythonを簡単に実行出来る神環境

ブラウザでアクセスするだけですぐに本記事のコードが試せる。

お手元の環境を汚さない。エコ仕様。

全コード掲載&すぐにコピペ実行出来るようになっているので、

ぜひオリジナルの文字絵アート文字文字アートを作ってみてください!

(*´ω`)つ Colaboratory


Step1 文字を画像にする技術


準備:日本語フォントのインストール

Colaboratoryでは、最初に「!」をつけると

シェルコマンドの実行が出来る。

画像にしちゃう日本語フォントをインストールしてみよう。


Colaboratoryで日本語フォントのインストール

!apt-get -y install fonts-ipafont-gothic


インストールされたフォントのパスを確認してみよう。


TTFファイルのパスを確認する

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


出来た関数は以下のように使える


str2img関数のお試し実行

import matplotlib.pyplot as plt

img = str2img("勝利友情努力", 2, 3, 50)
plt.imshow(img)

出力結果:

勝利友情努力.PNG

「三本柱マン」が無事降臨!!

なお、以前に、

どこでもドアを作ってみた物語

においてもPillowで画像加工を実施したことがある。

文字だけでなく画像の合成等も可能だ。


Step2 画像を白黒の01リストにする技術

「文字」の画像の場合もともと白黒なのだが、

任意の画像を文字で表現することにも対応するため、

まず画像を「白黒化」し、各ピクセルを0~1の少数で表現する。

そして、閾値(その画像全体の平均値とする)と比較して

白い場合は「1」黒い場合は「0」にすれば、

あらゆる画像が「1」と「0」の2次元リストになるというわけ。


画像の白黒化&01リスト化

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


出来た関数は以下のように使える


白黒化&01リスト化

#与えられた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)


出力結果:

hannya_kakunin.PNG

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


出来た関数は以下のように使える


01リストを文字列で埋める

img = str2img("般若波羅蜜多", 6, 1, 20)

graylist = img2graylist(img)
wblist = graylist2wblist(graylist)
#print2Dcharlist(wblist)

# 今回は↑の外枠で「般若波羅蜜多」のフレーム(01)を作り、
# ↓の指定で、中身を「般若波羅密多」の文字列で埋める
wbcharlist = wblist2wbcharlist(wblist, "般若波羅蜜多"," ")
print2Dcharlist(wbcharlist)


出力結果:

hannya_kakunin2.PNG

この技術に狂気と恐怖を覚える


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")


出力結果:

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)


出力結果:

satubatu_gunma.png

グンマーは何をやっても面白いのでとてもお得


作例集②(オマケ)


はらみった

hannya.png

「写経」を自動化し、オートで功徳を積める仕組みを作ってみたのでございます。


しろくろ

simauma.png

じわじわくる


止まれ。

tomare.png

もう何十回も言ったのよ!?って言える必殺技


見よ、人がゴミのようだっ!

hitogomi.png

「バルス!!」「目がぁ~!目がぁ~!」


新時代アート

reiwa.png

【続】平成の次の元号を、AIだけで決めさせる物語(@テレビ取材)


その…下品なんですが…フフ…勃起…しちゃいましてね…

monakira.png

いいや!限界だ(いいねを)押すね!今だッ!

PythonでHello 世界(ザ・ワールド)止まった時の世界に入門してみる。ジョースターの末裔は必読


あとがき


大喜利

技術を使った大喜利として、ネタを考えるのも楽しいかもしれません。

面白い文字文字アートの案や、作例が出来たら、

ぜひコメント欄に張り付けて教えてください!


応用例/アイデアメモ

応用例はいろいろありそう。


  • 画像認識した部分を対応する文字に変える(車に認識された部分を「車」で表現など)

  • TwitterやSlackのツール/ボット作成、サービス化

  • 単純にアスキーアート生成技術として活用

  • 文字の色を変更してカラフル化

  • 濃淡に合わせて黒い文字/白い文字を使い分ける

  • セリフの無いマンガの作成

  • 薄い灰色で文字を印刷して、幼児/英単語などの書き取り練習帳に(書き終わると絵が浮かび上がる)

  • 究極的に「ざわざわっ...」「ゴゴゴゴゴ」している絵の作成(著作権的な意味で今回はパス)


いつもの名言

ちょっとした遊び & Colaboratoryの実践入門として

楽しんでいただけたら幸いです♪

ブラウザでColaboにアクセス、上から順にコピペしていくだけですぐ試せます。

文字文字アートで一緒に遊びましょう。


人類の進化は「遊び」からはじまる。

こんな「遊び」が出来るならば、というアイデアに触発される人がでて、

生活にも役に立つような「発明」が生まれるのだ。

          ~  Char Fuitter (1847~1912 オランダ) ~


長文おつきあいいただきありがとうございました。


出力結果画像は自由に転載していただいて構いません。

Char Fuitter (チャー・フイター)は架空の人物です。