アスキーアートを自動生成する
画像をテキストで置き換えるいわゆるアスキーアートを自動生成します。変換したい画像と使用する文字列を与えると、画像の濃いところは画数の多い字で薄いところは画数の少ない字で置き換えることで濃淡を表現します。ただし画数情報はわからないので、文字列の字を一文字ずつ画像に変換して濃さ(輝度)を測定して画数の代わりに使用しています。
環境
- windows10 home
- Anaconda 3/ jupyter notebook 5.6.0
- Python 3.7.0
- Pillow 5.2.0
準備
画像ファイルはフリー写真素材ぱくたそからダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリに保存しました(使用した画像サイズは800x1195)。
置き換える文字列は小学校1年生で習う漢字を用いました。また空白の描画のため全角スペースをそれに追加しています。
コード
from PIL import Image, ImageDraw, ImageFont # x × y ピクセルのr値の合計を求める関数 def r_sum_calc(im,x_f,y_f): r_sum_f = 0 for i in range(x_f): for j in range(y_f): r,g,b=im.getpixel((i,j)) r_sum_f = r_sum_f+r return r_sum_f # 画像を置き換える文字を探す関数 def choose_letter(r_ave_norm_list_f,test_r_f): near_check = 256 near_index_f = 0 for i in r_ave_norm_list: diff = abs(test_r_f-i) if diff<near_check: near_check = diff near_index_f = r_ave_norm_list_f.index(i) return near_index_f x = 16 y = 16 r_ave_list = [] r_ave_norm_list = [] font = ImageFont.truetype('C:\Windows\Fonts\msmincho.ttc',x) #フォントの設定(等幅のMS明朝を選ぶ) # 描画に使う文字列 スペースと小学校1年生の漢字 kanjis = ' 一右雨円王音下火花貝学気九休玉金空月犬見五口校左三山子四糸字耳七車手十出女小上森人水正生青夕石赤千川先早草足村大男竹中虫町天田土二日入年白八百文木本名目立力林六' # 文字列kanjisのそれぞれの文字の白ピクセル値を求める counter = 0 for kanji,counter in zip(kanjis,range(len(kanjis))): im = Image.new('RGB',(x,y),(0,0,0)) # 下地となるイメージオブジェクトの生成 draw = ImageDraw.Draw(im) # drawオブジェクトを生成 draw.multiline_text((0,0),kanjis[counter], fill=(255,255,255), font=font) # 1行分の文字列を画像に描画 r_ave = 0 r_sum = r_sum_calc(im,x,y) for i in range(x): for j in range(y): r,g,b=im.getpixel((i,j)) r_sum = r_sum+r r_ave = r_sum/(x*y) r_ave_list.append(r_ave) offset = min(r_ave_list) r_range =max(r_ave_list)-offset mag = 255/r_range # 0~255に規格化する for i in r_ave_list: i = (i-offset)*mag r_ave_norm_list.append(int(i)) im_draw = Image.open('model.jpg') # アスキーアートに変換する画像の読み出し im_draw_gray = im_draw.convert('L') # グレースケール画像に変換 x_im_draw_gray,y_im_draw_gray = im_draw_gray.size # グレースケール画像サイズ取得 # 画像を1/x,1/yに縮小 x_resize = x_im_draw_gray//x y_resize = y_im_draw_gray//y im_draw_gray_resize = im_draw_gray.resize((x_resize,y_resize)) # 縮小画像の各ピクセルの輝度を取得し割り当てる文字を探して表示 for y_check in range(y_resize): text_row ='' for x_check in range(x_resize): brightness=255-im_draw_gray_resize.getpixel((x_check,y_check)) near_index = choose_letter(r_ave_norm_list,brightness) text_row =text_row+kanjis[near_index] print(text_row)
実行結果
アスキーアートが生成されます。
縮小するとよりそれっぽく見えます。