-4

i need to convert a pgm image 16 bit per pixel to a pgm image 8 bit per pixel but i have problem to read a pgm image 16 bpp and i don't understand what i'm doing wrong. here the code:

#include "pgm.h"

#include <iterator>
#include <algorithm>
#include <fstream>
#include <sstream>

using namespace std;

bool convert16to8bit(const std::string& inFilename, mat<uint8_t>& img, const std::string& outFilename){
    mat<uint16_t> imgTemp;

    ifstream is(inFilename, ios::binary);
    if (!is)
        return false;

    string magic;
    is >> magic;
    if (magic != "P2" && magic != "P5")
        return false;

    size_t rows, cols, nlevels;
    is >> cols >> rows >> nlevels;

    if (nlevels < 255)
        return false;

    is.get();

    img = mat<uint8_t>(rows, cols);
    if (nlevels == 255){
        if (magic == "P5"){
            is.unsetf(ios::skipws);
            img.data_.assign(istream_iterator<uint8_t>(is), istream_iterator<uint8_t>());
        }else
            img.data_.assign(istream_iterator<int>(is), istream_iterator<int>());
    }
    else{
        imgTemp = mat<uint16_t>(rows, cols);
        if (magic == "P5"){
            is.unsetf(ios::skipws);
            imgTemp.data_.assign(istream_iterator<uint16_t>(is), istream_iterator<uint16_t>());
        }
        else
            imgTemp.data_.assign(istream_iterator<int>(is), istream_iterator<int>());

        for (size_t r = 0; r < rows; r++)
            for (size_t c = 0; c < cols; c++)
                img(r, c) = imgTemp(r, c);
    }

    stringstream ss; 
    ss << outFilename << ".pgm";
    ofstream os(ss.str(), ios::binary);
    if (!os)
        return false;
    os << magic <<"\n" << cols << " " << rows << "\n255\n";
    if (magic == "P2") 
        copy(begin(img), end(img), ostream_iterator<int>(os, " ")); 
    else 
        copy(begin(img), end(img), ostream_iterator<uint8_t>(os));

    return true;
}


//mat.h

#if !defined MAT_H 
#define MAT_H

#include <vector>

template <typename T> 
struct mat {
    size_t rows_, cols_; 
    std::vector<T> data_;

    mat(size_t rows = 0, size_t cols = 0) : rows_(rows), cols_(cols), data_(rows*cols) {}

    const size_t rows() const { return rows_; } 
    const size_t cols() const { return cols_; }

    const T& operator()(size_t r, size_t c) const { return data_[r*cols_ + c]; } 
    T& operator()(size_t r, size_t c) { return data_[r*cols_ + c]; }

    auto begin() -> decltype(data_.begin()) { return data_.begin(); } 
    auto end() -> decltype(data_.end()) { return data_.end(); } 
    auto begin() const -> decltype(data_.begin()) { return data_.begin(); } 
    auto end() const -> decltype(data_.end()) { return data_.end(); }
};
#endif // MAT_H

this code create a error when it tries to execute the istruction img(r, c) = imgTemp ( r, c) (error: vector subscript out of range) with a pgm 16bpp but with a pgm 8bpp i can open it without problems and recreate it as the original without error. i think that the problem is with istream_iterator < uint16_t > because istream_iterator < uint8_t > works (with pgm 8bit). any solution?

thanks for any help

  • 1
    any solution to what, exactly? "i have problem to read a pgm image" is not a problem statement. Can you please be more precise as to what is not working? – Federico klez Culloca Jun 28 '17 at 15:41
  • i can't read and memorize in imgTemp.data_ pixels with size of 16 bit – Danix Danilovic Jun 28 '17 at 15:45
  • 1
    Do you have an exception? A compiler error? Variables with values you don't expect? This is the kind of information that helps us help you. Can you please gather them and edit your question as to include them? – Federico klez Culloca Jun 28 '17 at 15:49
  • create a error when it tries to execute the istruction img(r, c) = imgTemp ( r, c) (error: vector subscript out of range) – Danix Danilovic Jun 28 '17 at 16:16
  • Why reinvent the wheel? Try using OpenCV. The `imread` function will read a PGM and I believe you can specify the bitdepth. Otherwise try freeimage. – marcman Jun 28 '17 at 17:41

1 Answers1

0

i've found solution to my problem. here is the right code if it can be useful for someone:

#include "pgm.h"

#include <iterator>
#include <algorithm>
#include <fstream>
#include <sstream>

using namespace std;

bool convert16to8bit(const std::string& inFilename, mat<uint8_t>& img, const std::string& outFilename){
    mat<uint16_t> imgTemp;

    ifstream is(inFilename, ios::binary);
    if (!is)
        return false;

    string magic;
    is >> magic;
    if (magic != "P2" && magic != "P5")
        return false;

    size_t rows, cols, nlevels;
    is >> cols >> rows >> nlevels;

    if (nlevels < 255)
        return false;

    is.get();

    img = mat<uint8_t>(rows, cols);
    if (nlevels == 255){
        if (magic == "P5"){
            is.unsetf(ios::skipws);
            img.data_.assign(istream_iterator<uint8_t>(is), istream_iterator<uint8_t>());
        }else
            img.data_.assign(istream_iterator<int>(is), istream_iterator<int>());
    }
    else{
        imgTemp = mat<uint16_t>(rows, cols);
        if (magic == "P5"){

            //here is the line changed
            is.read(reinterpret_cast<char *>(&imgTemp.data_[0]), imgTemp.rows()*imgTemp.cols() * 2);          
        }
        else
            imgTemp.data_.assign(istream_iterator<int>(is), istream_iterator<int>());

        for (size_t r = 0; r < rows; r++)
            for (size_t c = 0; c < cols; c++)
                img(r, c) = imgTemp(r, c);
    }

    stringstream ss; 
    ss << outFilename << ".pgm";
    ofstream os(ss.str(), ios::binary);
    if (!os)
        return false;
    os << magic <<"\n" << cols << " " << rows << "\n255\n";
    if (magic == "P2") 
        copy(begin(img), end(img), ostream_iterator<int>(os, " ")); 
    else 
        copy(begin(img), end(img), ostream_iterator<uint8_t>(os));

    return true;
}