1 // Ceres Solver - A fast non-linear least squares minimizer
2 // Copyright 2015 Google Inc. All rights reserved.
3 // http://ceres-solver.org/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors may be
14 // used to endorse or promote products derived from this software without
15 // specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
29 // Author: strandmark@google.com (Petter Strandmark)
31 // Simple class for accessing PGM images.
33 #ifndef CERES_EXAMPLES_PGM_IMAGE_H_
34 #define CERES_EXAMPLES_PGM_IMAGE_H_
44 #include "glog/logging.h"
49 template<typename Real>
52 // Create an empty image
53 PGMImage(int width, int height);
54 // Load an image from file
55 explicit PGMImage(std::string filename);
56 // Sets an image to a constant
57 void Set(double constant);
62 int NumPixels() const;
64 // Get individual pixels
65 Real* MutablePixel(int x, int y);
66 Real Pixel(int x, int y) const;
67 Real* MutablePixelFromLinearIndex(int index);
68 Real PixelFromLinearIndex(int index) const;
69 int LinearIndex(int x, int y) const;
71 // Adds an image to another
72 void operator+=(const PGMImage& image);
73 // Adds a constant to an image
74 void operator+=(Real a);
75 // Multiplies an image by a constant
76 void operator*=(Real a);
79 bool WriteToFile(std::string filename) const;
80 bool ReadFromFile(std::string filename);
82 // Accessing the image data directly
83 bool SetData(const std::vector<Real>& new_data);
84 const std::vector<Real>& data() const;
88 std::vector<Real> data_;
93 template<typename Real>
94 PGMImage<Real>::PGMImage(int width, int height)
95 : height_(height), width_(width), data_(width*height, 0.0) {
98 template<typename Real>
99 PGMImage<Real>::PGMImage(std::string filename) {
100 if (!ReadFromFile(filename)) {
106 template<typename Real>
107 void PGMImage<Real>::Set(double constant) {
108 for (int i = 0; i < data_.size(); ++i) {
113 template<typename Real>
114 int PGMImage<Real>::width() const {
118 template<typename Real>
119 int PGMImage<Real>::height() const {
123 template<typename Real>
124 int PGMImage<Real>::NumPixels() const {
125 return width_ * height_;
128 template<typename Real>
129 Real* PGMImage<Real>::MutablePixel(int x, int y) {
130 return MutablePixelFromLinearIndex(LinearIndex(x, y));
133 template<typename Real>
134 Real PGMImage<Real>::Pixel(int x, int y) const {
135 return PixelFromLinearIndex(LinearIndex(x, y));
138 template<typename Real>
139 Real* PGMImage<Real>::MutablePixelFromLinearIndex(int index) {
141 CHECK(index < width_ * height_);
142 CHECK(index < data_.size());
143 return &data_[index];
146 template<typename Real>
147 Real PGMImage<Real>::PixelFromLinearIndex(int index) const {
149 CHECK(index < width_ * height_);
150 CHECK(index < data_.size());
154 template<typename Real>
155 int PGMImage<Real>::LinearIndex(int x, int y) const {
159 // Adds an image to another
160 template<typename Real>
161 void PGMImage<Real>::operator+= (const PGMImage<Real>& image) {
162 CHECK(data_.size() == image.data_.size());
163 for (int i = 0; i < data_.size(); ++i) {
164 data_[i] += image.data_[i];
168 // Adds a constant to an image
169 template<typename Real>
170 void PGMImage<Real>::operator+= (Real a) {
171 for (int i = 0; i < data_.size(); ++i) {
176 // Multiplies an image by a constant
177 template<typename Real>
178 void PGMImage<Real>::operator*= (Real a) {
179 for (int i = 0; i < data_.size(); ++i) {
184 template<typename Real>
185 bool PGMImage<Real>::WriteToFile(std::string filename) const {
186 std::ofstream outputfile(filename.c_str());
187 outputfile << "P2" << std::endl;
188 outputfile << "# PGM format" << std::endl;
189 outputfile << " # <width> <height> <levels> " << std::endl;
190 outputfile << " # <data> ... " << std::endl;
191 outputfile << width_ << ' ' << height_ << " 255 " << std::endl;
194 int num_pixels = width_*height_;
195 for (int i = 0; i < num_pixels; ++i) {
196 // Convert to integer by rounding when writing file
197 outputfile << static_cast<int>(data_[i] + 0.5) << ' ';
200 return bool(outputfile); // Returns true/false
205 // Helper function to read data from a text file, ignoring "#" comments.
207 bool GetIgnoreComment(std::istream* in, T& t) {
213 if (word.length() > 0 && word[0] == '#') {
214 // Comment; read the whole line
216 std::getline(*in, word);
220 // Convert the string
221 std::stringstream sin(word);
232 template<typename Real>
233 bool PGMImage<Real>::ReadFromFile(std::string filename) {
234 std::ifstream inputfile(filename.c_str());
236 // File must start with "P2"
238 inputfile >> ch1 >> ch2;
239 if (!inputfile || ch1 != 'P' || (ch2 != '2' && ch2 != '5')) {
243 // Read the image header
245 if (!GetIgnoreComment(&inputfile, width_) ||
246 !GetIgnoreComment(&inputfile, height_) ||
247 !GetIgnoreComment(&inputfile, two_fifty_five) ) {
250 // Assert that the number of grey levels is 255.
251 if (two_fifty_five != 255) {
256 int num_pixels = width_*height_;
257 data_.resize(num_pixels);
260 for (int i = 0; i < num_pixels; ++i) {
262 bool res = GetIgnoreComment(&inputfile, pixel_data);
266 data_[i] = pixel_data;
268 // There cannot be anything else in the file (except comments). Try reading
269 // another number and return failure if that succeeded.
271 bool res = GetIgnoreComment(&inputfile, temp);
276 // Read the line feed character
277 if (inputfile.get() != '\n') {
281 // TODO(strandmark): Will not work on Windows (linebreak conversion).
282 for (int i = 0; i < num_pixels; ++i) {
283 unsigned char pixel_data = inputfile.get();
287 data_[i] = pixel_data;
289 // There cannot be anything else in the file. Try reading another byte
290 // and return failure if that succeeded.
300 template<typename Real>
301 bool PGMImage<Real>::SetData(const std::vector<Real>& new_data) {
302 // This function cannot change the dimensions
303 if (new_data.size() != data_.size()) {
306 std::copy(new_data.begin(), new_data.end(), data_.begin());
310 template<typename Real>
311 const std::vector<Real>& PGMImage<Real>::data() const {
315 } // namespace examples
319 #endif // CERES_EXAMPLES_PGM_IMAGE_H_