4

これまでのところ、すべての行を読み取ってコンソールに出力できます。

void readFile(){

   string line;
   ifstream myfile("example1.pgm");

   if (myfile.is_open()){
       while (myfile.good()){
         getline (myfile,line);
         cout << line;
       }
   }

ただし、pgmファイルには、データの前の開始時に常に次のものが含まれているようです。

P2
# test.pgm
24 7
15

「P2」が存在することを確認し、コメント(#)を無視し、変数と後続のピクセルデータを保存するようにコードを調整するにはどうすればよいですか?

私は少し迷っていて、C ++に慣れていないので、どんな助けでもありがたいです。

ありがとう

4

2 に答える 2

9

ファイルを解析する方法はたくさんあります。このようなものについては、このサイトの回答を見ることができます。個人的には、getline()のループを使用して、すべての行(変数「line」に格納されている)をテスト/解析します。複数の値で使用する方が簡単なので、文字列ストリームを使用することもできます。

アイディア

最初の行: P2(ポータブルグレーマップ)が存在することをテストします。

if(line.compare("P2")) ...

2行目:何もしないで、次のgetline()に進むことができます

3行目:画像のサイズを保存します。stringstreamを使用すると、これを行うことができます

int w,h;
ss >> w >> h;

次の行:ファイルの最後に到達するまでピクセルデータを保存します

結果のコード

このコードを試して、ニーズに合わせることができます。

#include <iostream> // cout, cerr
#include <fstream> // ifstream
#include <sstream> // stringstream
using namespace std;

int main() {
  int row = 0, col = 0, numrows = 0, numcols = 0;
  ifstream infile("file.pgm");
  stringstream ss;
  string inputLine = "";

  // First line : version
  getline(infile,inputLine);
  if(inputLine.compare("P2") != 0) cerr << "Version error" << endl;
  else cout << "Version : " << inputLine << endl;

  // Second line : comment
  getline(infile,inputLine);
  cout << "Comment : " << inputLine << endl;

  // Continue with a stringstream
  ss << infile.rdbuf();
  // Third line : size
  ss >> numcols >> numrows;
  cout << numcols << " columns and " << numrows << " rows" << endl;

  int array[numrows][numcols];

  // Following lines : data
  for(row = 0; row < numrows; ++row)
    for (col = 0; col < numcols; ++col) ss >> array[row][col];

  // Now print the array to see the result
  for(row = 0; row < numrows; ++row) {
    for(col = 0; col < numcols; ++col) {
      cout << array[row][col] << " ";
    }
    cout << endl;
  }
  infile.close();
}

編集

これは、文字列ストリームの使用方法に関する優れたチュートリアルです。

于 2011-11-14T19:25:53.653 に答える
2

PNM (PBM / PGM / PPM)ヘッダー処理を簡素化する方法は、必要なすべてのデータをキャプチャするまで、ヘッダー文字列を1行ずつ作成することです。標準C++ライブラリのみを使用してこれを行うのにそれほど多くのコードは必要ありません...

#include <string>
#include <iostream>
#include <sstream>
#include <stdexcept>
...
std::string header, magic;
int width=0, height=0, maxsample=0, samples=0, bits=0, bytes=0;

do {
   try { getline(is,magic); } catch ( const std::ios_base::failure & ) {}
   if ( !magic.empty() && magic[0] != '#' ) header += magic+" ";
   if ( !( std::stringstream(header+" 1") >> magic >> width >> height >> maxsample ).eof() ) break;
   if ( ( (magic=="P1"||magic=="P4") && maxsample==1 ) || !is.good() ) break;
   } while ( true );

samples = magic=="P1"?1:magic=="P2"?1:magic=="P3"?3:magic=="P4"?1:magic=="P5"?1:magic=="P6"?3:0;
bits = (magic=="P1"||magic=="P4")?1:maxsample<256?8:maxsample<256*256?16:0, bytes = (width*samples*bits+7)>>3;
if ( width<=0 || height<=0 || maxsample<=0 || samples<=0 || bits<=0 ) throw std::runtime_error("invalid PNM header");

これは、コメント(存在する場合)およびPBMの特殊なケース(「maxsample」なし)を処理し、入力ストリームで例外が有効になっているかどうかに関係なく機能します。

フォーマットはシーケンシャルデータダンプ(「magic」値に応じてASCIIまたはバイナリのいずれか)として定義されているため、ヘッダーを読み取った後は、通常、画像データの読み取りは簡単です。16ビットのバイナリエンコードされたサンプルの場合、フォーマット仕様は「最上位バイトが最初」(ビッグエンディアン)であると示しているため、この場合、プラットフォーム固有の処理が必要になる場合があります。

書かれているように、これにはC++11が必要です-おそらく私がstringstream一時的に使用している方法が原因です。

getline注意点:病理学的なケースでは、呼び出しが本質的に制限されていないため、無効なヘッダーを読み取ろうとしているときに、これが多くの時間/RAMを浪費する可能性があります。比較的単純な解決策(より堅牢なものに置き換えるgetline)がありますが、もう少しコードが必要です。

本番品質のアプリケーションの場合は、libnetpbmの使用を検討してください。

于 2013-06-14T06:06:14.950 に答える