とらりもんHOME  Index  Search  Changes  Login

C言語による画像処理: 画像の左右反転・上下反転

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
lake_s.jpg

↑lake.ppm

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
Last modified:2018/10/22 13:51:45
Keyword(s):
References:[画像解析入門]