Programming for Beginners Programming for everyone!

ボリュームデータの読み込み

ここではバイナリ形式で表現されたボリュームデータの読み込みについて、C++を用いた方法について見ていく。

ファイルを開く

C言語では stdio.h にある FILE 型を用いてバイナリファイルを読み書きを行うが、C++では ifstream で読み込み、ofstream で書き込みを行う。いずれも、第1引数の const char* 型のファイル名文字列を取り、第2引数にファイルを開く際のオプションを取る。

テキスト形式 (ASCII形式ともいう)のテキストデータを読み書きするときは、以下のようにしてファイルを開く。

読み込み

std::ifstream reader(filename, std::ios::in);

書き込み

std::ofstream writer(filename, std::ios::out);

また、先に宣言だけを行っておいて、ファイルを後から開くこともできる。

std::ifstream reader;
reader.open(filename, std::ios::in);

ファイルを開いたときに、例えばファイルが見つからないなどのエラーが生じると fail() メソッドの戻り値が true になる。ファイルを開く操作は比較的失敗しやすい操作なので、エラー処理は必ず入れておくこと。

if (reader.fail()) {
    fprintf(stderr, "Failed to open file: %s\n", filename);
    std::exit(1);
}

ここまではテキスト形式のデータを見てきたが、バイナリ形式のデータを読み書きするときには第2引数に std::ios::binary を追加する。

std::ifstream reader(filename, std::ios::in | std::ios::binary);

ファイルへの操作が終わったら close() メソッドを呼んでファイルを閉じる。ただし、C++の場合には ifstream, ofstream を値型で宣言している場合には、それらが破棄されるときに自動的にファイルも閉じられる。

reader.close();

データの読み書き (テキスト形式)

C言語においては、ファイルからのデータの読み取りは fprintf のようなIO関数を用いていた。見て分かる通り、これは標準入出力を担当する printf のファイル版といって良い。一方C++では標準入出力を cout ならびに cin を用いて行う。例えば、以下のような形だ。

標準入力

int x;
std::cin >> x;

標準出力

std::cout << "Hello, world!" << std::endl;

C++ではこの文法と似た形式でテキスト形式のデータの読み書きが可能である (バイナリはできない!!!)。

読み込み

int x;
reader >> x;

書き込み

writer << "Hello, world!" << std::endl;

データの読み書き (バイナリ形式)

C言語においては、バイナリ形式の読み込みに fread、書き込みに fwrite を用いた。一方でC++の場合には ifstreamならびにofstream クラスのメソッドを用いて読み書きができる。fread と比較をしながら見ていこう。

int x[10];
fread((void*)x, sizeof(int), 10, fp);

このようにC言語では読み取るデータの一つ分の大きさを第2引数に、読み取る数を第3引数に指定していたが、C++ではこれらをまとめて以下のように書く。

int x[10];
reader.read((char*)x, sizeof(int) * 10);

この操作は書き込みもほとんど同じで、fwriteofstream::write を比較すると以下のようになる。

int x[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
fwrite((void*)x, sizeof(int), 10, fp);
int x[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
writer.write((char*)x, sizeof(int) * 10);

ボリュームデータの読み込み

今回わたすボリュームデータはX線CTで撮影された巻き貝のデータで、ImageJを用いて16bit符号なし整数のデータとして出力したものである。

このデータには、大きさのデータが含まれず、ファイルの先頭から各ボクセルにCT値が格納されている。ファイル名は shell_512_512_271.raw のようになっており、このデータには縦、横、奥行きに、それぞれ512, 512, 271ボクセルのデータが並んでいる。

サンプルプログラムの volume.h にある Volume::load にボリュームデータを読み取る関数を実装してみよう。

comments powered by Disqus