pgm形式の画像ファイルは、非圧縮型の画像ファイルである。pgm形式の画像ファイルは、ヘッダ部とボディ部がある。今回の演習で使用するファイルの場合、ヘッダ部のフォーマットはラベル行「P5」、コメント行、縦と横のサイズを表す行、そして、輝度(明るさ)の上限を表す行となっている。その次の行以降がボディ部である。ボディ部分は、1ピクセルごとの輝度値をバイナリで列挙している。画像の左上が原点であり、右方向と下方向に座標がすすむ。以下に例を示す。画像サイズが 170 x 240、輝度値の上限が 255 である。
P5 # CREATOR - - - 170 240 255
pgm形式の画像ファイルのロードとセーブを行うライブラリは、pgmimage.c および pgmimage.h というソースコードで用意している(リンク先を参照)。画像は2次元配列に格納するので、array2dint.c および array2dint.h を使用する。
上記のリンク先のファイルをよく読むと、array2dint.h のインクルードが2回行なわれるため、typedef などが同名で2重宣言されてしまうというエラーが生じる。2重のインクルードを防止するために、C言語のヘッダファイルには、以下のおまじないを挿入する。
/* array2dint.h */ #ifndef __ARRAY2DINT_H__ #define __ARRAY2DINT_H__ - - - ヘッダファイルの本体 - - - #endif (ファイルの終了)
pgmimage の使用例を list0301.c に示す。Makefile を自分で作成し、list0301.c をコンパイルせよ。そして、動作を確認せよ。list0301.c のコンパイル後の実行ファイルを list0301 とする。また、実行すると tmp.pgm ファイルが出力される。以下にコンパイルの方法と実行の方法を示す。
gcc -Wall -o list0301 list0301.c pgmimage.o array2dint.o ./list0301 PGM/22_Takuma_Sato.pgm
なお、画像ファイルは、pgm 形式に変換したファイルを使用する。ここの 圧縮ファイルをダウンロードして使用せよ。圧縮ファイルの展開は「tar -zxf PGM.tgz」で行なう。ここの画像は、Yahoo F1 より引用した。
2次元配列のライブラリ array2dint に次の機能を追加せよ。
以下のプログラムを実行すると、2つの画像を横並びに結合することができるので、動作確認に使おう。
/* list0302.c */
#include "array2dint.h"
#include "pgmimage.h"
#include <stdio.h>
#include <stdlib.h>
Array2dInt *load_pgmfile( char *fname )
{
Array2dInt *img;
FILE *fp;
int sx, sy;
fp = fopen( fname, "r" );
if( fp == NULL ){
fprintf(stderr,"No file: %s\n", fname);
exit(1);
}
pgmimage_get_header( fp, &sx, &sy );
img = array2dint_open( sx, sy );
pgmimage_get_body( fp, img );
fclose(fp);
return img;
}
void save_pgmfile( char *fname, Array2dInt *img )
{
FILE *fp;
fp = fopen( fname, "w" );
pgmimage_put_header( fp, img );
pgmimage_put_body( fp, img );
fclose( fp );
}
|
int main()
{
Array2dInt *p1, *p2, *cmb, *buf1, *buf2;
// バトン選手の顔部分を buf1 に入れる
p1 = load_pgmfile("PGM/07_Jenson_Button.pgm");
buf1 = array2dint_copy( p1, 40, 0, 130, 120 );
array2dint_close( p1 );
// バリチェロ選手の顔部分を buf2 に入れる
p2 = load_pgmfile("PGM/08_Rubens_Barrichello.pgm");
buf2 = array2dint_copy( p2, 44, 0, 140, 120 );
array2dint_close( p2 );
// 2人の顔を並べる
cmb = array2dint_open( (130 - 40) + (140 - 44), 120 );
array2dint_paste( cmb, 0, 0, buf1 );
array2dint_paste( cmb, 90, 0, buf2 );
array2dint_close( buf1 );
array2dint_close( buf2 );
// ファイルに出力する
save_pgmfile("HondaPilots.pgm", cmb);
array2dint_close( cmb );
return 0;
}
|
小レポートとして、下記について説明せよ。
次回の演習開始時に集めます。