Question

I understand there's no reason for implementing a function that reads pixel values of a pgm image on c++, but I have to do it for my assignment.

For accuracy reason, after I read the pixel values, I compared it with the pixel values read in matlab using imread(file), however, some of the values match, and some are off, and I'm not sure why.

Below is the function for c++, the image is in binary format:

int Read_File_PGM(string filename){

    int row = 0, col = 0, numrows = 0, numcols = 0, bits;

    string filename;
    ifstream infile(filename.c_str(), ios::binary);

    stringstream ss;
    string inputLine = "";

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

    // Second line : width and height
    ss << infile.rdbuf();
    ss >> numrows >> numcols;

    int max_bits;
    ss >> max_bits;
    unsigned char pixel;
    unsigned int pixel_value[numrows][numcols];
    //double sum = 0;

    // Following lines : data


            for(row = 0; row < numrows; ++row){
                    for (col = 0; col < numcols; ++col){
                            infile.read(pixel, 1);
                            ss >> pixel;
                            pixel_value[row][col] = (int)pixel;
            }

            }

    infile.close();


    }
    return 0;

}

Was it helpful?

Solution

As written, your code does not compile. After adding some headers, etc, I still ran into a couple of errors.

First - you re-declare "filename" - it is a parameter of the function, yet you have the line

string filename;

Right after the int row = 0 …etc

Second, my compiler (rightly) doesn't like your line

infile.read(pixel, 1);

The error message (this isn't even a warning - it's an error) is

readPgm.cpp:34: error: invalid conversion from ‘unsigned char’ to ‘char*’ 
readPgm.cpp:34: error:   initializing argument 1 of 
     ‘std::basic_istream<_CharT, _Traits>& 
      std::basic_istream<_CharT,_Traits>::read(_CharT*, std::streamsize) 
      [with _CharT = char, _Traits = std::char_traits<char>]’

But actually - I don't think you need that line at all - because the very next line is

ss >> pixel;

and since you already associated the ss with the file buffer when you did

    ss << infile.rdbuf();

I think you can just read the pixels now.

Do note however that your code implicitly assumes that the max value is < 255 (single byte per pixel). The standard specifies that you should look for double bytes if the number is > 255. You might consider handling that case separately.

Still - for a tiny test file that I made, the following modified code did an OK job reading things in. See if this works better for you?

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

int Read_File_PGM(string filename)
{
    int row = 0, col = 0, numrows = 0, numcols = 0, bits;
    stringstream ss;    
    ifstream infile(filename.c_str(), ios::binary);

    string inputLine = "";

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

    // Second line : width and height
    ss << infile.rdbuf();
    ss >> numrows >> numcols;

    int max_bits;
    ss >> max_bits;
    char pixel;
    unsigned int pixel_value[numrows][numcols];
    cout << "rows: " << numrows << "; cols: " << numcols << endl;
    cout << "max size: " << max_bits << endl;

    // Following lines : data
    for (row = 0; row < numrows; ++row){
        for (col = 0; col < numcols; ++col){
             ss >> pixel;
             pixel_value[row][col]= pixel;
             cout << (int)pixel << ";";
        }
        cout << endl;
    }
infile.close();    
}

int main(void) {
  Read_File_PGM("testfile.pgm");
  return 0;
}

For a test file, I created the following. Note that the ascii value of 1 is 49, etc.

P5
5 5 255
12345
23456
34567
45678
56789

Output of the above program:

Version : P5
rows: 5; cols: 5
max size: 255
49;50;51;52;53;
50;51;52;53;54;
51;52;53;54;55;
52;53;54;55;56;
53;54;55;56;57;

Final thought: you also have to remember that in C the last index is the "fast" one, and in Matlab it is the first one. Depending on how you compare things that might matter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top