とらりもんHOME  Index  Search  Changes  Login

とらりもん - C言語による画像処理: 画像の左右反転・上下反転 Diff

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

![[C言語による画像処理]]: 画像の反転

!!画像の左右反転

前章の画像を, 左右反転してみましょう。
これまではrawバイナリーの入出力でしたが, ヘッダーの入出力もプログラムに組み込み, PPM型式の入出力にしてみましょう。プログラムは以下のようになります:

    /* reverse_LR.c
     * reverse left-right of an image
     * usage: $ ./reverse_LR < source_image.ppm > destin_image.ppm
     * compile: $ gcc reverse_LR.c -o reverse_LR
     * 2006/07/14 Kenlo Nishida
     */
    # include <stdio.h>
    # define XL 800
    # define YL 600
    # define BPP 3
    short linescan(FILE *fp, char *buff)
    {int in=0, i=0;
     while((in=fgetc(fp))!='\n' && feof(fp)==0)
         {buff[i]=in;
          i++;}
     buff[i]=0;
     return(feof(fp));
    }
    main()
    {short x, y;
     char head[255];
     unsigned char data[BPP*XL];
     linescan(stdin, head);
     printf("%s\n", head);
     linescan(stdin, head);
     printf("%s\n", head);
     linescan(stdin, head);
     printf("%s\n", head);
     linescan(stdin, head);
     printf("%s\n", head);
     for (y=0; y<YL; y++)
           {fread(data, BPP, XL, stdin);
            for (x=0; x<XL; x++)
       fwrite(&data[BPP*(XL-x-1)], BPP, 1, stdout);
           }
    }

これを, 以下のようにコンパイルして実行してみて下さい:

    $ gcc reverse_LR.c -o reverse_LR
    $ ./reverse_LR < lake.ppm > lake_reverse_LR.ppm
    $ display lake_reverse_LR.ppm

{{attach_view(lake_s.jpg)}}

↑lake.ppm

{{attach_view(lake_reverse_LRs.jpg)}}

↑lake_reverse_LR.ppm

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

    short linescan(FILE *fp, char *buff)
    {int in=0, i=0;
     while((in=fgetc(fp))!='\n' && feof(fp)==0)
         {buff[i]=in;
          i++;}
     buff[i]=0;
     return(feof(fp));
    }

↑この部分は, main()から使われる関数(数学的な関数ではなく, プログラムの下請をする小さなプログラムのこと)を作っています。一般に, C言語では, ほとんどの機能は「関数」という形で実装されます。例えば, 皆さんがこれまで使った, freadやscanfやprintfなども, すべて関数です。それらは, C言語に標準的に実装されている関数ですが, それ以外にも, ユーザーが独自に関数を作ることができます。ここでは, linescanという名前の関数を独自に作っているのです(linescanという名前は, 私がテキトーにつけました)。

この関数は, 引数(関数に与える変数)としてファイルポインタという型の変数*fpと, 文字列変数*buffをとります。linescanの前のshortというのは, この関数が返す出力値の型です。実際は何も返さないのですが, とりあえずここを定めておかないと, コンパイラに怒られるので(警告が出る), テキトーにshortと定めています。このlinescanという関数は, 改行コードに出会うまで, ファイルから文字列を読みつづけて, 読みこんだ文字列を*buffという変数に入れます。

ではその次の部分を読んでみましょう:

    main()
    {short x, y;
     char head[255];               ヘッダーファイルを読みこむための文字列の配列変数。
      unsigned char data[BPP*XL];  画像データを読みこむための, 符号無し整数の配列変数。
      linescan(stdin, head);        ヘッダーファイルを1行読みこむ。
     printf("%s\n", head);         読みこんだ行をそのまま出力。

ここでlinescanとprintfのカタマリが4回くり返されているのは, この画像のヘッダー情報が4行ぶんあるからです。

ではその次の部分を読んでみましょう:

    for (y=0; y<YL; y++)
           {fread(data, BPP, XL, stdin);
            for (x=0; x<XL; x++)
       fwrite(&data[BPP*(XL-x-1)], BPP, 1, stdout);
           }

これまではyのループのすぐ内側にxのループがあったのに, ここでは, xのループの前に, fread文が入っています。じつはここで, 画像の横1ラインぶんのデータをがっさりと読みこんでいます。従来はxのループの中で1ピクセルごとに読んでいたのですが, このプログラムではxのループの外で1ラインを一気に読みこんでいます。これは, 画像の左右を反転させるためです。画像データは左から右に順に格納されるので, 左右をひっくりかえすには, まず1ラインをぜんぶ読みこんで, それを反転させて書き出す必要があるわけです。それをやっているのが, fwrite(&data[BPP*(XL-x-1)]の部分です。(XL-x-1)とすることで, インデックスxの増加にともなって座標をへらしていくことができ, それが右から左の順でデータを指定することになるわけです。


!!画像の上下反転

画像の上下を反転するには, 上のプログラムの赤色の部分を以下のように変えればよろしい:

     unsigned char data[BPP*XL*YL];
     fread(data, BPP, XL*YL, stdin);
     for (y=0; y<YL; y++)
            fwrite(&data[BPP*XL*(YL-y-1)], BPP, XL, stdout);

このプログラムをreverse_UD.cという名で保存し, 次のようにコンパイル・実行してみて下さい:

    $ gcc reverse_UD.c -o reverse_UD
    $ ./reverse_UD < lake.ppm > lake_reverse_UD.ppm
    $ display lake_reverse_UD.ppm