画像をアスキーアートに変換

画像処理に awk が使えたらと思うことはありませんか? 明暗の度合いや、コピーしたものから値を読み取ったり、CCD の出力画像を処理したりといったことに awk を使う簡単な方法としては一旦 ImageMagic の convert コマンドを用いて XPM フォーマットに変換するものがあります。 XPM フォーマットは画像フォーマットの中でも中身がテキストのフォーマットとしても有名で、インターネットの初期には Perl などでカウンターの文字を自動生成させたりする CGI もありました。

今回は、任意の画像をアスキーアートに変換してくれる『picascii』というページを見て、awk で同じようなことをやってみます。

やり方としては、ImageMagic の identify コマンドから元の画像の情報を取得し、convert コマンドでコンソールの解像力に合わせて出力させ、これを awk で処理します。 コードとしては長くなってしまったのですが、以下のようなものです。

#! /usr/bin/gawk -f
# img2txt.awk
#   画像を AA にして画面に表示する
#   usage: gawk -f img2txt.awk foo.jpg

BEGIN {
    # 色の AA への変換表
    num_color = split(" .-=+X$@", color, "");     # 8 文字 (3 ビットへ変換)
    aspect = 0.3;

    # コマンドの設定
    convert_cmd      = "/usr/bin/convert -depth 3 -type GrayScale";
    identify_cmd     = "/usr/bin/identify";
    get_terminal_cmd = "/bin/stty -a";

    # 現在のコンソールサイズを取得
    #   Ref: http://gauc.no-ip.org/awk-users-jp/blis.cgi/DoukakuAWK_056
    while (get_terminal_cmd | getline > 0) {
        if ($4 == "rows") {
            rows = $5;
            sub(/;/, "", rows);
        }
        if ($6 == "columns") {
            cols = $7;
            sub(/;/, "", cols);
        }
    }
    close(get_terminal_cmd);

    # 入力画像からサイズ情報を取得
    identify_inst = identify_cmd " " ARGV[1];
    identify_inst | getline image_info;
    close(identify_inst);
    split(image_info, image_info_arr);
    split(image_info_arr[3], image_info_pix, "x");

    image_pix_org_x = image_info_pix[1];    # X ピクセルサイズ
    image_pix_org_y = image_info_pix[2];    # Y ピクセルサイズ

    # 変換後の X を合わせるように Y を計算
    image_pix_x = cols;
    image_pix_y = int(image_pix_org_y * (cols / image_pix_org_x) * aspect);

    # 変換コマンドの生成と実行
    convert_cmd = convert_cmd " -resize " image_pix_x "x" image_pix_y "!";
    converted_image = ARGV[1] ".xpm";

    convert_inst = convert_cmd " " ARGV[1] " " converted_image;
    ##print convert_inst;
    system(convert_inst);
    close(convert_inst);

    while (getline < converted_image > 0) {
        # カラー設定を読み取る
        if (substr($0, 3, 3) == " c ") {
            color_org[++i] = substr($0, 2, 1);
        }

        # 実際の画像情報部の処理
        if (length($0) > image_pix_x + 0) {
            sub(/^"/, "", $0);
            sub(/",?$/, "", $0);

            # replace の識別用に "_" を使う
            for (i = 1; i <= length($0); i++) {
                str = str "_" substr($0, i, 1);
            }
            $0 = str;
            str = "";

            # 指定された色への変換
            for (i = 1; i <= num_color; i++) {
                ##print color_org[i], color[num_color - i + 1];
                gsub("_\\" color_org[i], color[num_color - i + 1], $0);
            }

            print $0;
        }
    }
    close(converted_image);

}

大体やるべきことは shell スクリプトでも十分できてしまうような内容ですが、最初の

num_color = split(" .-=+X$@", color, "");     # 8 文字 (3 ビットへ変換)

の部分の split() 関数の第 1 引数に白黒での濃淡の順の文字を記載しておきます。

aspect = 0.3;

という部分は、コンソールの文字が縦長なので、その比率調整用です。

イメージとしてはWikipedia の月の画像を使います。

$ gawk -f img2txt.awk Moon.jpg
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@$$$XXXXXXXXX$$$@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@$X+=---.............---==+$@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@$X=-------===-------......------=+$@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@$+=========----======-..---..-===....-+$@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@X+=+++++=====-=++++=+++=======------=--.-=$@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@$X+++X+++++======+++===+++++++======+==-....X@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@$X+XXXX+++++===-=++===-===++===------=-----..$@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@$XXXXX++++++===++====--.---..-----=------....+@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@XXXXX+++=====+++====---.--.......----...  ..X@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@$$XX++++===++=+==-----------.--...........=@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@$$XX+XX++++++===+==-------..-...........=$@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@$$XXXX+++++++++++=--..........-....-X@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@$$X++XX++++++==--..............=X@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@$$XXXXX+++==-----......---+X$@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@$$$$XXXXX+++++++XX$@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

さすがにこれでは解像度が悪いので、解像度を上げてみましょう。

DoukakuAWK_114.png

これは上げすぎでしょうか? (苦笑)

ここでは簡単な処理しか行っていませんが、XPM フォーマットのデータを一種の 2 次元配列のデータとして扱うことで、awk で扱うことができるということを知っておくと他の処理に使うこともできます。

xgawk で GD を扱うこともできますが、古典的な awk でも他のコマンドを使って様々なことができることを覚えておきましょう。 awk は awk 単独で処理するのではなく、他のコマンドと一緒に使って真価が発揮できます。

tag_nawk.pngtag_nawk.pngtag_nawk.pngtag_nawk.png