Files
ceres-solver/examples/pgm_image.h
T
Keir Mierle 7492b0d8de Update copyright headers with new year and URL
Since Ceres is moving to using GitHub for issues, and the Google
Code URL in the current copyright header will soon become invalid,
update all the headers.

Change-Id: I1fce70375d1bcf098591f07b4d8f01a5c1e0789c
2015-03-18 05:43:23 +00:00

320 lines
8.4 KiB
C++

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