とらりもん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
int 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));
}
int main()
{int 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);
       }
}

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

$ 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

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

int 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という変数に入れます。

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

int main()
{int 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]; を unsigned char data[BPP*XL*YL]; に。
  • for (y=0; y<YL; y++) の行の前に fread(data, BPP, XL*YL, stdin); を入れる。
  • for (y=0; y<YL; y++) の中のループは fwrite(&data[BPP*XL*(YL-y-1)], BPP, XL, stdout); とする(1行のみ)。

課題2: このプログラムを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:2022/08/13 23:14:47
Keyword(s):
References:[画像解析入門]