Dots

ブログとか

文字によるセルフィー

🎨 AA(アスキーアート)を生成する

自分はアスキーアートに詳しいわけじゃないけど、アスキーアート自体は結構好きだ。

AA職人の手による芸術的なアスキーアートというのもあるのだと思うが、 これはもっと単純なやつ。

実際の画像をアスキーアートに変換するのは、超具体的に言うと以下のような仕組み。

  1. まず、使用する文字をリストアップして、「視覚的ピクセル密度」順にソートする。
    • 視覚的ピクセル密度というのは、今テキトーに考えた言葉だけど、半角1文字空間に文字がレンダリングされたときのピクセルの数というか、例えば、黒背景に白い文字だった場合、遠くからみて白に近いもの # とか $ とかは密度が高い。 逆に ,. は密度が低い、というようなもの。
    • 厳密にいうと、フォントによってかなり変わるので、ある程度は想定フォントを決める必要はある。
    • 文字をこの密度が薄い -> 濃い の順で並べておく。
  2. その文字の濃淡が何段階か数える。
      # たとえばこれは 0-13 の14段階
      [' ', '.', ':', ';', '+', '-', '=', 'c', 'o', 'w', 'O', '$', '8', '@']
    
  3. 画像を加工する
    • 最初に、グレースケールに変換する。
    • そしてできれば、境界線がわかりやすいように、いい感じにコントラストのカーブを調整する。
    • 最後にそれを、先程の「視覚的ピクセル密度」順に並べた文字数分の階調に変換する。
    • プログラムで画像のピクセルを読み込んで計算しても良いし、ffmpegコマンドでもできる。
      #!/bin/bash
      set -e
      # convert video to grayscale with specified number of tones and resolution
      # usage: to_gray.sh input.mp4 output.mp4 [N] [WIDTH] [HEIGHT]
      
      INPUT="$1"         # 入力ファイル
      OUTPUT="$2"        # 出力ファイル
      N="${3:-24}"       # 階調数(省略時 24)
      WIDTH="${4:-320}"  # 出力横幅(省略時 320)
      HEIGHT="${5:-240}" # 出力縦幅(省略時 240)
      
      # 256 ÷ N(グレースケールの間隔)を計算
      STEP=$(awk "BEGIN { printf \"%.6f\", 256 / $N }")
      # 実行
      ffmpeg -i "$INPUT" \
      -vf "format=gray,lut=y='floor(val/$STEP)*$STEP',scale=${WIDTH}:${HEIGHT}:force_original_aspect_ratio=disable" \
      -y "$OUTPUT"
      
  4. グレースケール画像を文字に変換する
    • 1ピクセルずつ読みこんで、対応する文字に変換する。
    • 画像の右端まで来たら改行する。
  5. 等幅フォント( fixed width )で書く
    • プロポーショナルフォントで書くと、1文字あたりの幅が違うので、当然、ぐっちゃぐちゃになる。
    • HTMLだと、<pre>...</pre> タグを使うのが良いと思う。
    • ただ、スタイルに変な設定が入っていてうまくいかなかったり、文字サイズとか細かく指定したい場合は、直接スタイル指定する。
      <!-- こんなふうにするとか -->
      <pre style="font-size: 0.6rem; letter-spacing: 0.01em; line-height: 1.01em;">
       .:;+-=cowO$8@
       .:;+-=cowO$8@
       .:;+-=cowO$8@
      </pre>
      

作成したセルフポートレート

88888$$$$$$$$$$OOOOOOOOOwc-      :=owooooooooooooooooo=;++++=c=c
88888$$$$$$$$$$$OOOOOOw=.          -=owooooooooooooooo=;++++=ccc
888888$$$$$$$$$$$OOOOw-              +oooooooooooooooo=;++++=ccc
8888888$$$$$$$$$$$$OO;                =woooooooooooooo=;+++==ccc
8888888$$$$$$$$$$$$$c                 -ooooooooooooooo=;+++==ccc
888888888$$$$$$$$$$w.                  cwwoooooooooooo=;++===ccc
8888888888$$$$$$$$$+                   -wwoooooooooooo=;++===ccc
8888888888$$$$$$$$O:                    owwooooooooooo=;++===ccc
88888888888$$$$$$$w.                    cwwwoooooooooo=;++===ccc
888888888888$$$$$$o:                    =wwwoooooooooo=;=+===ccc
8888888888888$$$$$o      :.             =wwwwwoooooooo=;=+==cccc
@888888888888$$$$$o    .-;;:.           cwwwwwoooooooo=;====cccc
@@888888888888$$$$w.  .==+;:  :..       owwwwwwooooooo=;====ccco
@@888888888888$$$$O:  =wc=-:  ::.    . :wwwwwwwwoooooo=;====ccco
@@@888888888888$$$O-:-owo=;:.:;;... ...=wwwwwwwwoooooo=;===cccco
@@@888888888888$$$O+;+owc+-:-;c=:...::;owwwwwwwwwooooo=+==ccccco
@@@@88888888888$$$$o-+wo=+;--;o=:..:::cwwwwwwwwwwooooo=+==ccccco
@@@8888888888888$$$O+cwoc++-:-+;:..::-cwwwwwwwwwwooooo=+==ccccco
@@@8888888888888$$$$wwwoc=+-:-:.. .::;owwwwwwwwwoooooo=+==ccccoo
@@@8888888888888$$$$$wooc=+-;;;-....:;owwwwwwwwooooooo=+==cccooo
@@88888888888888$$$$$Owoc=;+;+;:....:+wwwwwwwwwooooooo=+==ccccoo
@@@8888888888888$$$$$$Owc=+-::.   ..:=wwwwwwwwwooooooo=+==cccooo
@@@8888888888888$$$$$$Owc=+::-:.  ..-owwwwwwwwoooooooo=+c=cccooo
@888888888888888$$$$$$OOo=+;-::....:.cowwwwwwooooooooo=+==ccccoo
888888888888888$$$$$$$O$Oc=+;;-.....    =coooooooooooo=+c=ccccoo
888888888888888$$$$$$$$O+cc+;-::....    ;;+ccooooooooo=+==ccccoo
888888888888888$$88888O- +o=;-:::...   :-;;++==ccooooo=+=cccccoo
88888888888888$$8@@@@$:  =oc;-:::...  .-;;;+++++==cooc=+=cccccoo
8888888888888$$$8@@@@O.  woc+--:::.  :-;;;+++++++++=oc=+=cccccoo
8888888888888$$$@@@@@O+ :ooo=;-:::..-;;;++++++++++++=c=+=cccccoo
888888888888$$$8@@888$w+-=oo=;--:::-;;+++++++++++++++=++=cccccoo
88888888888$$$8@@888$$Owc=cc=+;:-;-;++++++++++++++++++++=cccccco
8888888888$$$$888$$$$$$wwowwoc=cc=;+++++++++++;+++++++++=cccccco
888888888$$$$$$$$$OOOOOOOowwwocc=++=ccccc=++++;++++++++++=ccccco
8888888$$$$$$$OwwOOOOOOOOwooc=====coooooOo===+;==++++++;+=ccccco
888888$$$$$$$$OoowwOwO$OOwwwocoooowoowoOOocwo++c==+=++;;++===cco
888$$$$$$$$$$$$ooowO$$$$OOOOwwwowowoowwOOccOo;=ooc+=+;;;;++==cco
88$$$$$$$$$$$$$OoowO88$$OOwOOwwwwwwooww$w=oOc;cwwc+++;;;;;;+=cco
$$$$$$$$$$$$$$$$Ooow88$$OOOOOOwwwwwowwOOo=wO=;oOo=;+;;;+;;;;+ccc
$$$$$$$$$$$$$$$$$OO$@8$$OOOwOOwwwwwowO$Oo=wO++Owc+;;;;++;;;++=cc
$$$$$$$$$$$$$$$OOOO8@8$$OOOwOOOwOwwowO$Oc=ww;=Oo=++;;;;;;;+==+=c
$$$$$$$$$$$$$$OOOOO88$$$OOOwOOOwwwwowO$w==wo-owcc=+;;;+;;;+=c=+c
$$$$$$$$$$$$OOOOOOO$8$$OOOOOwOOwwwwwO$Oo==wo-o=oc=;;;;+;;++co=;+
$$$$$$$$$$OOOOOOOOOO88$$OOOOwOOOwOwwO$Oo++wo-=;oc+;-;;+;;++co=;;
$$$$$$$$OOOOOOOOOOOO$8$OOOOOwOOOwOwwO$Oc++oo-;:wo+;-;;;;;+=ow=;;
$$$$$$OOOOOOOOOOwwwwO8$OOOOOOOOOOOOw$Owc++oo-:.oo+;-;;;;+=owo+;-
$$$$$OOOOOOOOwwwwwwww$$OOOO$$OOwOOOwOOw=;;co-. co+;-;;;;=cwwc;-;
$$$$OOOOOOOwwwwoccowwwwOO$$$$OOOOOwOOwo+;;=o;. oo+;-;;;+cowwc;;;