#ifndef CERES_EXAMPLES_PGM_IMAGE_H_
#define CERES_EXAMPLES_PGM_IMAGE_H_
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "glog/logging.h"
namespace ceres {
namespace examples {
template<typename Real>
class PGMImage {
public:
PGMImage(int width, int height);
explicit PGMImage(std::string filename);
void Set(double constant);
int width() const;
int height() const;
int NumPixels() const;
Real* MutablePixel(int x, int y);
Real Pixel(int x, int y) const;
Real* MutablePixelFromLinearIndex(int index);
Real PixelFromLinearIndex(int index) const;
int LinearIndex(int x, int y) const;
void operator+=(const PGMImage& image);
void operator+=(Real a);
void operator*=(Real a);
bool WriteToFile(std::string filename) const;
bool ReadFromFile(std::string filename);
bool SetData(const std::vector<Real>& new_data);
const std::vector<Real>& data() const;
protected:
int height_, width_;
std::vector<Real> data_;
};
template<typename Real>
PGMImage<Real>::PGMImage(int width, int height)
: height_(height), width_(width), data_(width*height, 0.0) {
}
template<typename Real>
PGMImage<Real>::PGMImage(std::string filename) {
if (!ReadFromFile(filename)) {
height_ = 0;
width_ = 0;
}
}
template<typename Real>
void PGMImage<Real>::Set(double constant) {
for (int i = 0; i < data_.size(); ++i) {
data_[i] = constant;
}
}
template<typename Real>
int PGMImage<Real>::width() const {
return width_;
}
template<typename Real>
int PGMImage<Real>::height() const {
return height_;
}
template<typename Real>
int PGMImage<Real>::NumPixels() const {
return width_ * height_;
}
template<typename Real>
Real* PGMImage<Real>::MutablePixel(int x, int y) {
return MutablePixelFromLinearIndex(LinearIndex(x, y));
}
template<typename Real>
Real PGMImage<Real>::Pixel(int x, int y) const {
return PixelFromLinearIndex(LinearIndex(x, y));
}
template<typename Real>
Real* PGMImage<Real>::MutablePixelFromLinearIndex(int index) {
CHECK(index >= 0);
CHECK(index < width_ * height_);
CHECK(index < data_.size());
return &data_[index];
}
template<typename Real>
Real PGMImage<Real>::PixelFromLinearIndex(int index) const {
CHECK(index >= 0);
CHECK(index < width_ * height_);
CHECK(index < data_.size());
return data_[index];
}
template<typename Real>
int PGMImage<Real>::LinearIndex(int x, int y) const {
return x + width_*y;
}
template<typename Real>
void PGMImage<Real>::operator+= (const PGMImage<Real>& image) {
CHECK(data_.size() == image.data_.size());
for (int i = 0; i < data_.size(); ++i) {
data_[i] += image.data_[i];
}
}
template<typename Real>
void PGMImage<Real>::operator+= (Real a) {
for (int i = 0; i < data_.size(); ++i) {
data_[i] += a;
}
}
template<typename Real>
void PGMImage<Real>::operator*= (Real a) {
for (int i = 0; i < data_.size(); ++i) {
data_[i] *= a;
}
}
template<typename Real>
bool PGMImage<Real>::WriteToFile(std::string filename) const {
std::ofstream outputfile(filename.c_str());
outputfile << "P2" << std::endl;
outputfile << "# PGM format" << std::endl;
outputfile << " # <width> <height> <levels> " << std::endl;
outputfile << " # <data> ... " << std::endl;
outputfile << width_ << ' ' << height_ << " 255 " << std::endl;
int num_pixels = width_*height_;
for (int i = 0; i < num_pixels; ++i) {
outputfile << static_cast<int>(data_[i] + 0.5) << ' ';
}
return bool(outputfile); }
namespace {
template<typename T>
bool GetIgnoreComment(std::istream* in, T& t) {
std::string word;
bool ok;
do {
ok = true;
(*in) >> word;
if (word.length() > 0 && word[0] == '#') {
ok = false;
std::getline(*in, word);
}
} while (!ok);
std::stringstream sin(word);
sin >> t;
if (!in || !sin) {
return false;
}
return true;
}
}
template<typename Real>
bool PGMImage<Real>::ReadFromFile(std::string filename) {
std::ifstream inputfile(filename.c_str());
char ch1, ch2;
inputfile >> ch1 >> ch2;
if (!inputfile || ch1 != 'P' || (ch2 != '2' && ch2 != '5')) {
return false;
}
int two_fifty_five;
if (!GetIgnoreComment(&inputfile, width_) ||
!GetIgnoreComment(&inputfile, height_) ||
!GetIgnoreComment(&inputfile, two_fifty_five) ) {
return false;
}
if (two_fifty_five != 255) {
return false;
}
int num_pixels = width_*height_;
data_.resize(num_pixels);
if (ch2 == '2') {
for (int i = 0; i < num_pixels; ++i) {
int pixel_data;
bool res = GetIgnoreComment(&inputfile, pixel_data);
if (!res) {
return false;
}
data_[i] = pixel_data;
}
int temp;
bool res = GetIgnoreComment(&inputfile, temp);
if (res) {
return false;
}
} else {
if (inputfile.get() != '\n') {
return false;
}
for (int i = 0; i < num_pixels; ++i) {
unsigned char pixel_data = inputfile.get();
if (!inputfile) {
return false;
}
data_[i] = pixel_data;
}
inputfile.get();
if (inputfile) {
return false;
}
}
return true;
}
template<typename Real>
bool PGMImage<Real>::SetData(const std::vector<Real>& new_data) {
if (new_data.size() != data_.size()) {
return false;
}
std::copy(new_data.begin(), new_data.end(), data_.begin());
return true;
}
template<typename Real>
const std::vector<Real>& PGMImage<Real>::data() const {
return data_;
}
} }
#endif