画像のグレースケール化

画像のグレイスケール化 - みずぴー日記 にインスパイヤされて画像をグレースケールに変換してみます。 awk 単独の機能として実装するのは危険なので、ここでは ImageMagick の convert コマンドを用いますが、convert コマンドを用いるのであれば、以下のようにして一発でできますが、ここでは向学のため採用しません。

$ convert -colorspace GRAY foo_1.png foo_2.png

さて、AWK Users JP :: 画像をアスキーアートに変換 にて既に説明してあるように、convert コマンドを用いて XPM 形式に変換することで awk でも容易に扱えるようになります。

また、グレースケール化にあたっては、XPM の カラー指定部分の RGB のうち、最大のものを RGB に割り当て直すことでグレースケール化しています。

#! /usr/local/bin/nawk -f
# color2gray.awk
# カラー画像をグレー画像に変換します。
# usage: nawk -f color2gray.awk foo.png

BEGIN {
    org_image  = ARGV[1];
    tmp_image  = ENVIRON["TMP"] "/color2gray.xpm";
    gray_image = org_image ".xpm";

    convert_cmd = "/usr/bin/convert";
    convert_opt = "";
    convert_exe = convert_cmd " " convert_opt " " org_image " " tmp_image;

    system(convert_exe);

    while (getline < tmp_image > 0) {
        split($0, arr, / c /);
        if ($0 ~ /^"/ && \
            $0 ~ / c #[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]",/ && \
            arr[2] ~ /^#[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]",$/) {
            red   = substr(arr[2], 2, 2);
            green = substr(arr[2], 4, 2);
            blue  = substr(arr[2], 6, 2);
            gray  = max3(hex2dec(red), hex2dec(green), hex2dec(blue));
            $0 = arr[1] " c " "#" conv_base_num(gray, 16) \
                                  conv_base_num(gray, 16) \
                                  conv_base_num(gray, 16) "\",";

            print $0 > gray_image;

        } else {
            print $0 > gray_image;
        }
    }
    close(tmp_image);
}

# max3():   3 つの数値の最大値を返す
#   in:     数値 a, b, c
#   out:    数値 a, b, c の最大値
function max3(a, b, c,    max) {
    max = a;
    if (b > max) {
        max = b;
    }
    if (c > max) {
        max = c;
    }

    return max;
}

# hex2dec():    16 進数を 10 進数に変換する
#   in:     16 進数 str
#   out:    16 進数 str の 10 進数変換値
# Ref.: http://gauc.no-ip.org/awk-users-jp/blis.cgi/DoukakuAWK_156
function hex2dec(str,   hex, i, x) {
    hex[0] = 0;     hex[1] = 1;     hex[2] = 2;     hex[3] = 3;
    hex[4] = 4;     hex[5] = 5;     hex[6] = 6;     hex[7] = 7;
    hex[8] = 8;     hex[9] = 9;     hex["A"] = 10;  hex["B"] = 11;
    hex["C"] = 12;  hex["D"] = 13;  hex["E"] = 14;  hex["F"] = 15;

    for (i = 1; i <= length(str); i++) {
        x = x * 16 + hex[substr(str, i, 1)];
    }

    return x;
}

# conv_base_num():  10 進数を N 進数変換する
#   in:     10 進数 num
#   out:    10 進数 num の base 進数変換値
# Ref.: http://gauc.no-ip.org/awk-users-jp/blis.cgi/DoukakuAWK_055
function conv_base_num(num, base,    rem, str, base_str, arr_base_str) {

    base_str = "1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z";
    split(base_str, arr_base_str);

    while (num > 0) {
        rem = int(num % base);

        if (rem == 0) {
            str = "0" str;
        } else {
            str = arr_base_str[rem] str;
        }
        num = int(num / base);
    }

    return str;
}

さて、サンプル画像としては我が家のコガネメキシコインコの写真を使います。 画像が sample_in.png であるとします。

$ nawk -f color2gray.awk sample.png

引数は convert コマンドが扱えるものであれば何でも構いません。 カレントディレクトリに sample.png.xpm というファイルができていると思います。(一時ファイルとして環境変数 TMP で指定されているディレクトリに color2gray.xpm という名前のファイルもできます)

以下に変換前後の画像を掲載しますが、どうも一部で変換がおかしい部分があるようですが、概ねグレースケールに変換できているようです。

doukaku_254_1.png

doukaku_254_2.png

tag_nawk.png tag_nawk.png tag_nawk.png tag_nawk.png