Imported Upstream version ceres 1.13.0
[platform/upstream/ceres-solver.git] / examples / pgm_image.h
1 // Ceres Solver - A fast non-linear least squares minimizer
2 // Copyright 2015 Google Inc. All rights reserved.
3 // http://ceres-solver.org/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
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.
16 //
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.
28 //
29 // Author: strandmark@google.com (Petter Strandmark)
30 //
31 // Simple class for accessing PGM images.
32
33 #ifndef CERES_EXAMPLES_PGM_IMAGE_H_
34 #define CERES_EXAMPLES_PGM_IMAGE_H_
35
36 #include <algorithm>
37 #include <cstring>
38 #include <fstream>
39 #include <iostream>
40 #include <sstream>
41 #include <string>
42 #include <vector>
43
44 #include "glog/logging.h"
45
46 namespace ceres {
47 namespace examples {
48
49 template<typename Real>
50 class PGMImage {
51  public:
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);
58
59   // Reading dimensions
60   int width() const;
61   int height() const;
62   int NumPixels() const;
63
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;
70
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);
77
78   // File access
79   bool WriteToFile(std::string filename) const;
80   bool ReadFromFile(std::string filename);
81
82   // Accessing the image data directly
83   bool SetData(const std::vector<Real>& new_data);
84   const std::vector<Real>& data() const;
85
86  protected:
87   int height_, width_;
88   std::vector<Real> data_;
89 };
90
91 // --- IMPLEMENTATION
92
93 template<typename Real>
94 PGMImage<Real>::PGMImage(int width, int height)
95   : height_(height), width_(width), data_(width*height, 0.0) {
96 }
97
98 template<typename Real>
99 PGMImage<Real>::PGMImage(std::string filename) {
100   if (!ReadFromFile(filename)) {
101     height_ = 0;
102     width_  = 0;
103   }
104 }
105
106 template<typename Real>
107 void PGMImage<Real>::Set(double constant) {
108   for (int i = 0; i < data_.size(); ++i) {
109     data_[i] = constant;
110   }
111 }
112
113 template<typename Real>
114 int PGMImage<Real>::width() const {
115   return width_;
116 }
117
118 template<typename Real>
119 int PGMImage<Real>::height() const {
120   return height_;
121 }
122
123 template<typename Real>
124 int PGMImage<Real>::NumPixels() const {
125   return width_ * height_;
126 }
127
128 template<typename Real>
129 Real* PGMImage<Real>::MutablePixel(int x, int y) {
130   return MutablePixelFromLinearIndex(LinearIndex(x, y));
131 }
132
133 template<typename Real>
134 Real PGMImage<Real>::Pixel(int x, int y) const {
135   return PixelFromLinearIndex(LinearIndex(x, y));
136 }
137
138 template<typename Real>
139 Real* PGMImage<Real>::MutablePixelFromLinearIndex(int index) {
140   CHECK(index >= 0);
141   CHECK(index < width_ * height_);
142   CHECK(index < data_.size());
143   return &data_[index];
144 }
145
146 template<typename Real>
147 Real  PGMImage<Real>::PixelFromLinearIndex(int index) const {
148   CHECK(index >= 0);
149   CHECK(index < width_ * height_);
150   CHECK(index < data_.size());
151   return data_[index];
152 }
153
154 template<typename Real>
155 int PGMImage<Real>::LinearIndex(int x, int y) const {
156   return x + width_*y;
157 }
158
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];
165   }
166 }
167
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) {
172     data_[i] += a;
173   }
174 }
175
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) {
180     data_[i] *= a;
181   }
182 }
183
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;
192
193   // Write data
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) << ' ';
198   }
199
200   return bool(outputfile);  // Returns true/false
201 }
202
203 namespace  {
204
205 // Helper function to read data from a text file, ignoring "#" comments.
206 template<typename T>
207 bool GetIgnoreComment(std::istream* in, T& t) {
208   std::string word;
209   bool ok;
210   do {
211     ok = true;
212     (*in) >> word;
213     if (word.length() > 0 && word[0] == '#') {
214       // Comment; read the whole line
215       ok = false;
216       std::getline(*in, word);
217     }
218   } while (!ok);
219
220   // Convert the string
221   std::stringstream sin(word);
222   sin >> t;
223
224   // Check for success
225   if (!in || !sin) {
226     return false;
227   }
228   return true;
229 }
230 }  // namespace
231
232 template<typename Real>
233 bool PGMImage<Real>::ReadFromFile(std::string filename) {
234   std::ifstream inputfile(filename.c_str());
235
236   // File must start with "P2"
237   char ch1, ch2;
238   inputfile >> ch1 >> ch2;
239   if (!inputfile || ch1 != 'P' || (ch2 != '2' && ch2 != '5')) {
240     return false;
241   }
242
243   // Read the image header
244   int two_fifty_five;
245   if (!GetIgnoreComment(&inputfile, width_)  ||
246       !GetIgnoreComment(&inputfile, height_) ||
247       !GetIgnoreComment(&inputfile, two_fifty_five) ) {
248     return false;
249   }
250   // Assert that the number of grey levels is 255.
251   if (two_fifty_five != 255) {
252     return false;
253   }
254
255   // Now read the data
256   int num_pixels = width_*height_;
257   data_.resize(num_pixels);
258   if (ch2 == '2') {
259     // Ascii file
260     for (int i = 0; i < num_pixels; ++i) {
261       int pixel_data;
262       bool res = GetIgnoreComment(&inputfile, pixel_data);
263       if (!res) {
264         return false;
265       }
266       data_[i] = pixel_data;
267     }
268     // There cannot be anything else in the file (except comments). Try reading
269     // another number and return failure if that succeeded.
270     int temp;
271     bool res = GetIgnoreComment(&inputfile, temp);
272     if (res) {
273       return false;
274     }
275   } else {
276     // Read the line feed character
277     if (inputfile.get() != '\n') {
278       return false;
279     }
280     // Binary file
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();
284       if (!inputfile) {
285         return false;
286       }
287       data_[i] = pixel_data;
288     }
289     // There cannot be anything else in the file. Try reading another byte
290     // and return failure if that succeeded.
291     inputfile.get();
292     if (inputfile) {
293       return false;
294     }
295   }
296
297   return true;
298 }
299
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()) {
304     return false;
305   }
306   std::copy(new_data.begin(), new_data.end(), data_.begin());
307   return true;
308 }
309
310 template<typename Real>
311 const std::vector<Real>& PGMImage<Real>::data() const {
312   return data_;
313 }
314
315 }  // namespace examples
316 }  // namespace ceres
317
318
319 #endif  // CERES_EXAMPLES_PGM_IMAGE_H_