第3回ライブラリの利用(4月27日)

■ 今日のポイント

■ 画像入出力のライブラリ

画像ファイルのフォーマット

pgm形式の画像ファイルは、非圧縮型の画像ファイルである。pgm形式の画像ファイルは、ヘッダ部とボディ部がある。今回の演習で使用するファイルの場合、ヘッダ部のフォーマットはラベル行「P5」、コメント行、縦と横のサイズを表す行、そして、輝度(明るさ)の上限を表す行となっている。その次の行以降がボディ部である。ボディ部分は、1ピクセルごとの輝度値をバイナリで列挙している。画像の左上が原点であり、右方向と下方向に座標がすすむ。以下に例を示す。画像サイズが 170 x 240、輝度値の上限が 255 である。

P5
# CREATOR - - -
170 240
255

画像のライブラリ

pgm形式の画像ファイルのロードとセーブを行うライブラリは、pgmimage.c および pgmimage.h というソースコードで用意している(リンク先を参照)。画像は2次元配列に格納するので、array2dint.c および array2dint.h を使用する。

2重インクルードの防止

上記のリンク先のファイルをよく読むと、array2dint.h のインクルードが2回行なわれるため、typedef などが同名で2重宣言されてしまうというエラーが生じる。2重のインクルードを防止するために、C言語のヘッダファイルには、以下のおまじないを挿入する。

/* array2dint.h */

#ifndef __ARRAY2DINT_H__
#define __ARRAY2DINT_H__

 - - - ヘッダファイルの本体 - - -

#endif
(ファイルの終了)

■ 練習1

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

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;
}

□ 宿題

小レポートとして、下記について説明せよ。

  1. pgmimage.h をプリントアウトして、4つの関数の引数の意味を説明せよ(手書きによるコメント)。
  2. array2dint.c のうち少なくとも array2dint_copy 関数と array2dint_paste 関数の部分をプリントアウトして、プログラムの説明をせよ。
  3. Makefile を作成し、説明せよ。
  4. 実行結果をプリントアウトせよ。

次回の演習開始時に集めます。


(c) Masato TOKUHISA (2007, April, 15.)