Blame examples/pgm_image.h

Packit ea1746
// Ceres Solver - A fast non-linear least squares minimizer
Packit ea1746
// Copyright 2015 Google Inc. All rights reserved.
Packit ea1746
// http://ceres-solver.org/
Packit ea1746
//
Packit ea1746
// Redistribution and use in source and binary forms, with or without
Packit ea1746
// modification, are permitted provided that the following conditions are met:
Packit ea1746
//
Packit ea1746
// * Redistributions of source code must retain the above copyright notice,
Packit ea1746
//   this list of conditions and the following disclaimer.
Packit ea1746
// * Redistributions in binary form must reproduce the above copyright notice,
Packit ea1746
//   this list of conditions and the following disclaimer in the documentation
Packit ea1746
//   and/or other materials provided with the distribution.
Packit ea1746
// * Neither the name of Google Inc. nor the names of its contributors may be
Packit ea1746
//   used to endorse or promote products derived from this software without
Packit ea1746
//   specific prior written permission.
Packit ea1746
//
Packit ea1746
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit ea1746
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit ea1746
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit ea1746
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
Packit ea1746
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
Packit ea1746
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
Packit ea1746
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit ea1746
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
Packit ea1746
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit ea1746
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Packit ea1746
// POSSIBILITY OF SUCH DAMAGE.
Packit ea1746
//
Packit ea1746
// Author: strandmark@google.com (Petter Strandmark)
Packit ea1746
//
Packit ea1746
// Simple class for accessing PGM images.
Packit ea1746
Packit ea1746
#ifndef CERES_EXAMPLES_PGM_IMAGE_H_
Packit ea1746
#define CERES_EXAMPLES_PGM_IMAGE_H_
Packit ea1746
Packit ea1746
#include <algorithm>
Packit ea1746
#include <cstring>
Packit ea1746
#include <fstream>
Packit ea1746
#include <iostream>
Packit ea1746
#include <sstream>
Packit ea1746
#include <string>
Packit ea1746
#include <vector>
Packit ea1746
Packit ea1746
#include "glog/logging.h"
Packit ea1746
Packit ea1746
namespace ceres {
Packit ea1746
namespace examples {
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
class PGMImage {
Packit ea1746
 public:
Packit ea1746
  // Create an empty image
Packit ea1746
  PGMImage(int width, int height);
Packit ea1746
  // Load an image from file
Packit ea1746
  explicit PGMImage(std::string filename);
Packit ea1746
  // Sets an image to a constant
Packit ea1746
  void Set(double constant);
Packit ea1746
Packit ea1746
  // Reading dimensions
Packit ea1746
  int width() const;
Packit ea1746
  int height() const;
Packit ea1746
  int NumPixels() const;
Packit ea1746
Packit ea1746
  // Get individual pixels
Packit ea1746
  Real* MutablePixel(int x, int y);
Packit ea1746
  Real  Pixel(int x, int y) const;
Packit ea1746
  Real* MutablePixelFromLinearIndex(int index);
Packit ea1746
  Real  PixelFromLinearIndex(int index) const;
Packit ea1746
  int LinearIndex(int x, int y) const;
Packit ea1746
Packit ea1746
  // Adds an image to another
Packit ea1746
  void operator+=(const PGMImage& image);
Packit ea1746
  // Adds a constant to an image
Packit ea1746
  void operator+=(Real a);
Packit ea1746
  // Multiplies an image by a constant
Packit ea1746
  void operator*=(Real a);
Packit ea1746
Packit ea1746
  // File access
Packit ea1746
  bool WriteToFile(std::string filename) const;
Packit ea1746
  bool ReadFromFile(std::string filename);
Packit ea1746
Packit ea1746
  // Accessing the image data directly
Packit ea1746
  bool SetData(const std::vector<Real>& new_data);
Packit ea1746
  const std::vector<Real>& data() const;
Packit ea1746
Packit ea1746
 protected:
Packit ea1746
  int height_, width_;
Packit ea1746
  std::vector<Real> data_;
Packit ea1746
};
Packit ea1746
Packit ea1746
// --- IMPLEMENTATION
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
PGMImage<Real>::PGMImage(int width, int height)
Packit ea1746
  : height_(height), width_(width), data_(width*height, 0.0) {
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
PGMImage<Real>::PGMImage(std::string filename) {
Packit ea1746
  if (!ReadFromFile(filename)) {
Packit ea1746
    height_ = 0;
Packit ea1746
    width_  = 0;
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
void PGMImage<Real>::Set(double constant) {
Packit ea1746
  for (int i = 0; i < data_.size(); ++i) {
Packit ea1746
    data_[i] = constant;
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
int PGMImage<Real>::width() const {
Packit ea1746
  return width_;
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
int PGMImage<Real>::height() const {
Packit ea1746
  return height_;
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
int PGMImage<Real>::NumPixels() const {
Packit ea1746
  return width_ * height_;
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
Real* PGMImage<Real>::MutablePixel(int x, int y) {
Packit ea1746
  return MutablePixelFromLinearIndex(LinearIndex(x, y));
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
Real PGMImage<Real>::Pixel(int x, int y) const {
Packit ea1746
  return PixelFromLinearIndex(LinearIndex(x, y));
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
Real* PGMImage<Real>::MutablePixelFromLinearIndex(int index) {
Packit ea1746
  CHECK(index >= 0);
Packit ea1746
  CHECK(index < width_ * height_);
Packit ea1746
  CHECK(index < data_.size());
Packit ea1746
  return &data_[index];
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
Real  PGMImage<Real>::PixelFromLinearIndex(int index) const {
Packit ea1746
  CHECK(index >= 0);
Packit ea1746
  CHECK(index < width_ * height_);
Packit ea1746
  CHECK(index < data_.size());
Packit ea1746
  return data_[index];
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
int PGMImage<Real>::LinearIndex(int x, int y) const {
Packit ea1746
  return x + width_*y;
Packit ea1746
}
Packit ea1746
Packit ea1746
// Adds an image to another
Packit ea1746
template<typename Real>
Packit ea1746
void PGMImage<Real>::operator+= (const PGMImage<Real>& image) {
Packit ea1746
  CHECK(data_.size() == image.data_.size());
Packit ea1746
  for (int i = 0; i < data_.size(); ++i) {
Packit ea1746
    data_[i] += image.data_[i];
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
// Adds a constant to an image
Packit ea1746
template<typename Real>
Packit ea1746
void PGMImage<Real>::operator+= (Real a) {
Packit ea1746
  for (int i = 0; i < data_.size(); ++i) {
Packit ea1746
    data_[i] += a;
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
// Multiplies an image by a constant
Packit ea1746
template<typename Real>
Packit ea1746
void PGMImage<Real>::operator*= (Real a) {
Packit ea1746
  for (int i = 0; i < data_.size(); ++i) {
Packit ea1746
    data_[i] *= a;
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
bool PGMImage<Real>::WriteToFile(std::string filename) const {
Packit ea1746
  std::ofstream outputfile(filename.c_str());
Packit ea1746
  outputfile << "P2" << std::endl;
Packit ea1746
  outputfile << "# PGM format" << std::endl;
Packit ea1746
  outputfile << " # <width> <height> <levels> " << std::endl;
Packit ea1746
  outputfile << " # <data> ... " << std::endl;
Packit ea1746
  outputfile << width_ << ' ' << height_ << " 255 " << std::endl;
Packit ea1746
Packit ea1746
  // Write data
Packit ea1746
  int num_pixels = width_*height_;
Packit ea1746
  for (int i = 0; i < num_pixels; ++i) {
Packit ea1746
    // Convert to integer by rounding when writing file
Packit ea1746
    outputfile << static_cast<int>(data_[i] + 0.5) << ' ';
Packit ea1746
  }
Packit ea1746
Packit ea1746
  return bool(outputfile);  // Returns true/false
Packit ea1746
}
Packit ea1746
Packit ea1746
namespace  {
Packit ea1746
Packit ea1746
// Helper function to read data from a text file, ignoring "#" comments.
Packit ea1746
template<typename T>
Packit ea1746
bool GetIgnoreComment(std::istream* in, T& t) {
Packit ea1746
  std::string word;
Packit ea1746
  bool ok;
Packit ea1746
  do {
Packit ea1746
    ok = true;
Packit ea1746
    (*in) >> word;
Packit ea1746
    if (word.length() > 0 && word[0] == '#') {
Packit ea1746
      // Comment; read the whole line
Packit ea1746
      ok = false;
Packit ea1746
      std::getline(*in, word);
Packit ea1746
    }
Packit ea1746
  } while (!ok);
Packit ea1746
Packit ea1746
  // Convert the string
Packit ea1746
  std::stringstream sin(word);
Packit ea1746
  sin >> t;
Packit ea1746
Packit ea1746
  // Check for success
Packit ea1746
  if (!in || !sin) {
Packit ea1746
    return false;
Packit ea1746
  }
Packit ea1746
  return true;
Packit ea1746
}
Packit ea1746
}  // namespace
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
bool PGMImage<Real>::ReadFromFile(std::string filename) {
Packit ea1746
  std::ifstream inputfile(filename.c_str());
Packit ea1746
Packit ea1746
  // File must start with "P2"
Packit ea1746
  char ch1, ch2;
Packit ea1746
  inputfile >> ch1 >> ch2;
Packit ea1746
  if (!inputfile || ch1 != 'P' || (ch2 != '2' && ch2 != '5')) {
Packit ea1746
    return false;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Read the image header
Packit ea1746
  int two_fifty_five;
Packit ea1746
  if (!GetIgnoreComment(&inputfile, width_)  ||
Packit ea1746
      !GetIgnoreComment(&inputfile, height_) ||
Packit ea1746
      !GetIgnoreComment(&inputfile, two_fifty_five) ) {
Packit ea1746
    return false;
Packit ea1746
  }
Packit ea1746
  // Assert that the number of grey levels is 255.
Packit ea1746
  if (two_fifty_five != 255) {
Packit ea1746
    return false;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Now read the data
Packit ea1746
  int num_pixels = width_*height_;
Packit ea1746
  data_.resize(num_pixels);
Packit ea1746
  if (ch2 == '2') {
Packit ea1746
    // Ascii file
Packit ea1746
    for (int i = 0; i < num_pixels; ++i) {
Packit ea1746
      int pixel_data;
Packit ea1746
      bool res = GetIgnoreComment(&inputfile, pixel_data);
Packit ea1746
      if (!res) {
Packit ea1746
        return false;
Packit ea1746
      }
Packit ea1746
      data_[i] = pixel_data;
Packit ea1746
    }
Packit ea1746
    // There cannot be anything else in the file (except comments). Try reading
Packit ea1746
    // another number and return failure if that succeeded.
Packit ea1746
    int temp;
Packit ea1746
    bool res = GetIgnoreComment(&inputfile, temp);
Packit ea1746
    if (res) {
Packit ea1746
      return false;
Packit ea1746
    }
Packit ea1746
  } else {
Packit ea1746
    // Read the line feed character
Packit ea1746
    if (inputfile.get() != '\n') {
Packit ea1746
      return false;
Packit ea1746
    }
Packit ea1746
    // Binary file
Packit ea1746
    // TODO(strandmark): Will not work on Windows (linebreak conversion).
Packit ea1746
    for (int i = 0; i < num_pixels; ++i) {
Packit ea1746
      unsigned char pixel_data = inputfile.get();
Packit ea1746
      if (!inputfile) {
Packit ea1746
        return false;
Packit ea1746
      }
Packit ea1746
      data_[i] = pixel_data;
Packit ea1746
    }
Packit ea1746
    // There cannot be anything else in the file. Try reading another byte
Packit ea1746
    // and return failure if that succeeded.
Packit ea1746
    inputfile.get();
Packit ea1746
    if (inputfile) {
Packit ea1746
      return false;
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  return true;
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
bool PGMImage<Real>::SetData(const std::vector<Real>& new_data) {
Packit ea1746
  // This function cannot change the dimensions
Packit ea1746
  if (new_data.size() != data_.size()) {
Packit ea1746
    return false;
Packit ea1746
  }
Packit ea1746
  std::copy(new_data.begin(), new_data.end(), data_.begin());
Packit ea1746
  return true;
Packit ea1746
}
Packit ea1746
Packit ea1746
template<typename Real>
Packit ea1746
const std::vector<Real>& PGMImage<Real>::data() const {
Packit ea1746
  return data_;
Packit ea1746
}
Packit ea1746
Packit ea1746
}  // namespace examples
Packit ea1746
}  // namespace ceres
Packit ea1746
Packit ea1746
Packit ea1746
#endif  // CERES_EXAMPLES_PGM_IMAGE_H_