简体   繁体   English

如何在C ++中从pgm文件中读取数据

[英]How to read in data from a pgm file in C++

So far I can read every line and print it out to the console: 到目前为止,我可以阅读每一行并将其打印到控制台:

void readFile(){

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

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

However a pgm file apparently will always have the following at the start before the data: 但是,pgm文件显然在数据开始时始终具有以下内容:

P2
# test.pgm
24 7
15

How can i adapt my code so that it checks that "P2" is present, ignores any comments (#), and stores the variables and subsequent pixel data? 我该如何修改我的代码,以便它检查是否存在“ P2”,忽略任何注释(#),并存储变量和后续的像素数据?

I'm a bit lost and new to c++ so any help is appreicated. 我有点迷茫,对C ++还是陌生的,因此不胜感激。

Thanks 谢谢

There are a lot of different ways to parse a file. 解析文件有很多不同的方法。 For something like this, you could look at the answers on this site . 对于这种情况,您可以在此网站上查看答案。 Personally, I would go with a loop of getline() and test/parse every line (stored in the variable "line"), you can also use a stringstream since it is easier to use with multiple values : 就个人而言,我将使用getline()循环并测试/解析每行(存储在变量“ line”中),您还可以使用stringstream,因为它更易于与多个值一起使用:

Idea 理念

First line : test that P2 (Portable graymap) is present, maybe with something like 第一行:测试是否存在P2(便携式灰度图)

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

Second line : do nothing, you can go on with the next getline() 第二行:什么也不做,您可以继续下一个getline()

Third line : store the size of the image; 第三行:存储图像的大小; with a stringstream you could do this 用stringstream,你可以做到这一点

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

Following lines : store the pixel data until you reach the end of the file 以下几行:存储像素数据,直到到达文件末尾

Resulting code 结果代码

You can try this code and adapt it to your needs : 您可以尝试以下代码,并使其适应您的需求:

#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();
}

EDIT 编辑

Here is a good tutorial on how to use stringstreams . 这是有关如何使用stringstreams很好的教程

A way of simplifying PNM (PBM/PGM/PPM) header processing is to build up a header string line-by-line until you have captured all of the requisite data. 简化PNM (PBM / PGM / PPM)标头处理的一种方法是逐行建立标头字符串,直到捕获了所有必需的数据为止。 It doesn't take too much code to do this using only the standard C++ libraries... 仅使用标准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");

This handles comments (if present) and the special-case of PBM (no 'maxsample') -- and it works regardless of whether or not exceptions are enabled on the input stream. 它处理注释(如果存在)和PBM的特殊情况(不存在“ maxsample”),并且不管是否在输入流上启用了异常,它都可以工作。

Once you've read the header, reading the image data is usually a simple matter since the format is defined to just be a sequential data dump (which may be either ASCII or binary depending on the 'magic' value). 读取标头后,读取图像数据通常很简单,因为格式被定义为仅是顺序数据转储(取决于“ magic”值,可以是ASCII或二进制)。 In the case of 16-bit binary-encoded samples, the format specification indicates that "The most significant byte is first" (big endian), so this case may require some platform-specific handling. 对于16位二进制编码的样本,格式规范指示“最高有效字节在前”(大字节序),因此这种情况可能需要特定于平台的处理。

As written, this requires C++11 -- probably due to the way I'm using stringstream as a temporary. 如所写,这需要C ++ 11-可能是由于我将stringstream用作临时方式。

One caveat: In a pathological case, it is possible for this to waste a lot of time/RAM while attempting to read an invalid header -- since the getline call isn't inherently bounded. 一个警告:在病理情况下,这样做可能会浪费大量时间/ RAM,同时尝试读取无效的标头-因为getline调用不是固有的限制。 There's a relatively simple solution ( replace getline with something more robust ), but it requires a bit more code. 有一个相对简单的解决方案( 用更强大的功能替换getline ),但是它需要更多的代码。

For production-quality applications, consider using libnetpbm . 对于生产质量的应用程序,请考虑使用libnetpbm

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM