ボリュームデータの読み込み
ここではバイナリ形式で表現されたボリュームデータの読み込みについて、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);
この操作は書き込みもほとんど同じで、fwrite
と ofstream::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
にボリュームデータを読み取る関数を実装してみよう。