とらりもんHOME  Index  Search  Changes  Login

とらりもん - C言語による画像処理: 画像の切り出し Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

[[画像解析入門]]

!C言語による画像処理: 画像の切り出し

前章で, GIMPという画像処理ソフト(アプリケーション)を使って画像をいろいろいじりましたが, 自力でオリジナルの画像処理をするには, プログラミングが必要です。以下の実習では, 必ずしもオリジナルプログラムを作らなくてもアプリケーションで処理可能のことですが, それでも, 同様の処理を大量に繰り返すときなどは, やはりオリジナルプログラムを作ったほうが効率的であったりします。
----

前章の画像の左半分だけを切りだしてみましょう。プログラムは以下のようになります:

    /*
     * cutimage.c
     * cutout left part of an image
     * usage: $ ./cutimage < source_image > destin_image
     * compile: $ gcc cutimage.c -o cutimage
     * 2004/07/10 Kenlo Nishida
     */
    # include <stdio.h>
    # define XL 800
    # define YL 600
    # define BPP 3
    main()
    {short x, y;
     unsigned char data[BPP];
     for (y=0; y<YL; y++)
        for (x=0; x<XL; x++)
     {fread(data, BPP, 1, stdin);
     if (x<XL/2) fwrite(data, BPP, 1, stdout);
     }
    }

これをviなどのテキストエディタで入力し, cutimage.cというファイル名で保存し, コマンドラインで以下のようにコンパイルします:

    $ gcc cutimage.c -o cutimage

エラーが出なければ, コンパイルが成功してcutimageというファイルができているはずです。では以下のようにして走らせてみましょう:

    $ ./cutimage < lake.raw > lake_left.raw

この結果, lake_left.rawというファイルのサイズは, もともとのlake.rawの半分になっているはずです(確かめて下さい)。

では, この結果を表示してみましょう。GIMPで表示するには, まずrawバイナリーファイルにヘッダー情報を加えて, 何らかのフォーマットにしなければなりません。ここではPNMにしましょう。まずviなどのテキストエディタでlake_left.ppmという名のファイルを作り, 以下の内容(ヘッダー)を記述します:

    P6
    #
    400 600
    255

viなどで作業する場合, 最後の255のあとに改行しないようにしてください。

そして, このヘッダー情報のあとに, rawバイナリーファイルをドッキングさせます:

    $ cat lake_left.raw >> lake_left.ppm

この">>"は「リダイレクト」の一種で, 標準出力を, あるファイルに追加するかたちで出力します。

こうしてできたlake_left.ppmを表示してみてください:

    $ display lake_left.ppm

{{attach_view(lake_left.jpg)}}

↑こうなればOKです。

では上のプログラムを解説します:

    /*                                                    コメントのはじまり
     * cutimage.c                                         コメント:プログラム名
     * cutout left part of an image                       コメント:目的
     * usage: $ ./cutimage < source_image > destin_image  コメント:使用法
     * compile: $ gcc cutimage.c -o cutimage              コメント:コンパイルの方法
     * 2004/07/10 Kenlo Nishida                           コメント:著作権表示
    */                                                    コメントのおわり
    # include <stdio.h>         標準ライブラリを組みこめ!
    # define XL 800             画像の横の大きさ(800ピクセル)をXLという名前で定義。
    # define YL 600             画像の縱の大きさ(600ピクセル)をYLという名前で定義。
    # define BPP 3              画像の1ピクセルあたりのバイト数(3バイト)をBPPという名前で定義。
    main()
    {short x, y;                   画像の横と縱のインデックス。
     unsigned char data[BPP];      ピクセルのデータを格納するための配列を, 符号無し1バイト整数で宣言。
     for (y=0; y<YL; y++)
        for (x=0; x<XL; x++)
     {fread(data, BPP, 1, stdin);                画像データを標準入力(stdin)から読みこむ。
     if (x<XL/2) fwrite(data, BPP, 1, stdout);  画像の左半分のときのみ, データを標準出力(stdout)に出す。
     }
    }

この中で,

    if (x<XL/2) fwrite(data, BPP, 1, stdout);

という部分がポイントです。xは元画像の中のピクセルのx座標(左端がゼロ)ですが, それが画像の横サイズ(XL)の半分に満たない場合(つまり元画像の左半分)はデータを出力します。xが画像サイズの半分以上(元画像の右半分)になると, 出力をしません(freadで読み込まれたデータは, 何もされずに捨てられます)。このようにして, 左半分だけを抜き出しているのです。

一般に, 画像ファイルは, 画像の左上のピクセルの情報を先頭として, その右隣りのピクセルの情報がその次,...というふうに, 左上から右下への順番で, 各ピクセルの情報を順々に並べて格納しています。
----

課題1: 画像lake.rawの, 右半分を切り出してみよ。

課題2: 画像lake.rawの, 下半分を切り出してみよ。

課題3: 画像lake.rawを, 縦50%, 横50%に縮小せよ。ヒント: ヘッダーの画像サイズ記述が400 300になる。for文はそのまま。freadもそのまま。fwriteのタイミングをちょっとだけ調整すればよい。