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; } |
小レポートとして、下記について説明せよ。
次回の演習開始時に集めます。