到目前为止,我可以读取每一行并将其打印到控制台:
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 ++不熟悉,所以任何帮助都是有用的。
由于
答案 0 :(得分:8)
解析文件有很多种不同的方法。对于这样的事情,您可以查看this site上的答案。就个人而言,我会使用getline()循环并测试/解析每一行(存储在变量“line”中),你也可以使用stringstream,因为它更容易使用多个值:
第一行:测试P2(Portable graymap)是否存在,可能与
类似if(line.compare("P2")) ...
第二行:什么都不做,你可以继续使用下一个getline()
第三行:存储图片的大小;使用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();
}
修改强>
答案 1 :(得分:2)
简化PNM(PBM / PGM / PPM)标头处理的一种方法是逐行构建标题字符串,直到您捕获了所有必需的数据。仅使用标准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') - 无论是否在输入流上启用了异常,它都能正常工作。
读取标题后,读取图像数据通常很简单,因为格式定义为顺序数据转储(可能是ASCII或二进制,具体取决于'魔术'值)。在16位二进制编码样本的情况下,格式规范指示“最重要的字节是第一个”(大端),因此这种情况可能需要一些特定于平台的处理。
正如所写,这需要C ++ 11 - 可能是由于我使用stringstream
作为临时的方式。
一个警告:在病态情况下,这可能会在尝试读取无效标头时浪费大量时间/ RAM - 因为getline
调用本身并非有限。有一个相对简单的解决方案(replace getline
with something more robust),但它需要更多的代码。
对于生产质量的应用程序,请考虑使用libnetpbm。