pgm_image.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. #ifndef CERES_EXAMPLES_PGM_IMAGE_H_
  33. #define CERES_EXAMPLES_PGM_IMAGE_H_
  34. #include <algorithm>
  35. #include <cstring>
  36. #include <fstream>
  37. #include <iostream>
  38. #include <sstream>
  39. #include <string>
  40. #include <vector>
  41. #include "glog/logging.h"
  42. namespace ceres::examples {
  43. template <typename Real>
  44. class PGMImage {
  45. public:
  46. // Create an empty image
  47. PGMImage(int width, int height);
  48. // Load an image from file
  49. explicit PGMImage(std::string filename);
  50. // Sets an image to a constant
  51. void Set(double constant);
  52. // Reading dimensions
  53. int width() const;
  54. int height() const;
  55. int NumPixels() const;
  56. // Get individual pixels
  57. Real* MutablePixel(int x, int y);
  58. Real Pixel(int x, int y) const;
  59. Real* MutablePixelFromLinearIndex(int index);
  60. Real PixelFromLinearIndex(int index) const;
  61. int LinearIndex(int x, int y) const;
  62. // Adds an image to another
  63. void operator+=(const PGMImage& image);
  64. // Adds a constant to an image
  65. void operator+=(Real a);
  66. // Multiplies an image by a constant
  67. void operator*=(Real a);
  68. // File access
  69. bool WriteToFile(std::string filename) const;
  70. bool ReadFromFile(std::string filename);
  71. // Accessing the image data directly
  72. bool SetData(const std::vector<Real>& new_data);
  73. const std::vector<Real>& data() const;
  74. protected:
  75. int height_, width_;
  76. std::vector<Real> data_;
  77. };
  78. // --- IMPLEMENTATION
  79. template <typename Real>
  80. PGMImage<Real>::PGMImage(int width, int height)
  81. : height_(height), width_(width), data_(width * height, 0.0) {}
  82. template <typename Real>
  83. PGMImage<Real>::PGMImage(std::string filename) {
  84. if (!ReadFromFile(filename)) {
  85. height_ = 0;
  86. width_ = 0;
  87. }
  88. }
  89. template <typename Real>
  90. void PGMImage<Real>::Set(double constant) {
  91. for (int i = 0; i < data_.size(); ++i) {
  92. data_[i] = constant;
  93. }
  94. }
  95. template <typename Real>
  96. int PGMImage<Real>::width() const {
  97. return width_;
  98. }
  99. template <typename Real>
  100. int PGMImage<Real>::height() const {
  101. return height_;
  102. }
  103. template <typename Real>
  104. int PGMImage<Real>::NumPixels() const {
  105. return width_ * height_;
  106. }
  107. template <typename Real>
  108. Real* PGMImage<Real>::MutablePixel(int x, int y) {
  109. return MutablePixelFromLinearIndex(LinearIndex(x, y));
  110. }
  111. template <typename Real>
  112. Real PGMImage<Real>::Pixel(int x, int y) const {
  113. return PixelFromLinearIndex(LinearIndex(x, y));
  114. }
  115. template <typename Real>
  116. Real* PGMImage<Real>::MutablePixelFromLinearIndex(int index) {
  117. CHECK(index >= 0);
  118. CHECK(index < width_ * height_);
  119. CHECK(index < data_.size());
  120. return &data_[index];
  121. }
  122. template <typename Real>
  123. Real PGMImage<Real>::PixelFromLinearIndex(int index) const {
  124. CHECK(index >= 0);
  125. CHECK(index < width_ * height_);
  126. CHECK(index < data_.size());
  127. return data_[index];
  128. }
  129. template <typename Real>
  130. int PGMImage<Real>::LinearIndex(int x, int y) const {
  131. return x + width_ * y;
  132. }
  133. // Adds an image to another
  134. template <typename Real>
  135. void PGMImage<Real>::operator+=(const PGMImage<Real>& image) {
  136. CHECK(data_.size() == image.data_.size());
  137. for (int i = 0; i < data_.size(); ++i) {
  138. data_[i] += image.data_[i];
  139. }
  140. }
  141. // Adds a constant to an image
  142. template <typename Real>
  143. void PGMImage<Real>::operator+=(Real a) {
  144. for (int i = 0; i < data_.size(); ++i) {
  145. data_[i] += a;
  146. }
  147. }
  148. // Multiplies an image by a constant
  149. template <typename Real>
  150. void PGMImage<Real>::operator*=(Real a) {
  151. for (int i = 0; i < data_.size(); ++i) {
  152. data_[i] *= a;
  153. }
  154. }
  155. template <typename Real>
  156. bool PGMImage<Real>::WriteToFile(std::string filename) const {
  157. std::ofstream outputfile(filename.c_str());
  158. outputfile << "P2" << std::endl;
  159. outputfile << "# PGM format" << std::endl;
  160. outputfile << " # <width> <height> <levels> " << std::endl;
  161. outputfile << " # <data> ... " << std::endl;
  162. outputfile << width_ << ' ' << height_ << " 255 " << std::endl;
  163. // Write data
  164. int num_pixels = width_ * height_;
  165. for (int i = 0; i < num_pixels; ++i) {
  166. // Convert to integer by rounding when writing file
  167. outputfile << static_cast<int>(data_[i] + 0.5) << ' ';
  168. }
  169. return bool(outputfile); // Returns true/false
  170. }
  171. namespace {
  172. // Helper function to read data from a text file, ignoring "#" comments.
  173. template <typename T>
  174. bool GetIgnoreComment(std::istream* in, T& t) {
  175. std::string word;
  176. bool ok;
  177. do {
  178. ok = true;
  179. (*in) >> word;
  180. if (word.length() > 0 && word[0] == '#') {
  181. // Comment; read the whole line
  182. ok = false;
  183. std::getline(*in, word);
  184. }
  185. } while (!ok);
  186. // Convert the string
  187. std::stringstream sin(word);
  188. sin >> t;
  189. // Check for success
  190. if (!in || !sin) {
  191. return false;
  192. }
  193. return true;
  194. }
  195. } // namespace
  196. template <typename Real>
  197. bool PGMImage<Real>::ReadFromFile(std::string filename) {
  198. std::ifstream inputfile(filename.c_str());
  199. // File must start with "P2"
  200. char ch1, ch2;
  201. inputfile >> ch1 >> ch2;
  202. if (!inputfile || ch1 != 'P' || (ch2 != '2' && ch2 != '5')) {
  203. return false;
  204. }
  205. // Read the image header
  206. int two_fifty_five;
  207. if (!GetIgnoreComment(&inputfile, width_) ||
  208. !GetIgnoreComment(&inputfile, height_) ||
  209. !GetIgnoreComment(&inputfile, two_fifty_five)) {
  210. return false;
  211. }
  212. // Assert that the number of grey levels is 255.
  213. if (two_fifty_five != 255) {
  214. return false;
  215. }
  216. // Now read the data
  217. int num_pixels = width_ * height_;
  218. data_.resize(num_pixels);
  219. if (ch2 == '2') {
  220. // Ascii file
  221. for (int i = 0; i < num_pixels; ++i) {
  222. int pixel_data;
  223. bool res = GetIgnoreComment(&inputfile, pixel_data);
  224. if (!res) {
  225. return false;
  226. }
  227. data_[i] = pixel_data;
  228. }
  229. // There cannot be anything else in the file (except comments). Try reading
  230. // another number and return failure if that succeeded.
  231. int temp;
  232. bool res = GetIgnoreComment(&inputfile, temp);
  233. if (res) {
  234. return false;
  235. }
  236. } else {
  237. // Read the line feed character
  238. if (inputfile.get() != '\n') {
  239. return false;
  240. }
  241. // Binary file
  242. // TODO(strandmark): Will not work on Windows (linebreak conversion).
  243. for (int i = 0; i < num_pixels; ++i) {
  244. unsigned char pixel_data = inputfile.get();
  245. if (!inputfile) {
  246. return false;
  247. }
  248. data_[i] = pixel_data;
  249. }
  250. // There cannot be anything else in the file. Try reading another byte
  251. // and return failure if that succeeded.
  252. inputfile.get();
  253. if (inputfile) {
  254. return false;
  255. }
  256. }
  257. return true;
  258. }
  259. template <typename Real>
  260. bool PGMImage<Real>::SetData(const std::vector<Real>& new_data) {
  261. // This function cannot change the dimensions
  262. if (new_data.size() != data_.size()) {
  263. return false;
  264. }
  265. std::copy(new_data.begin(), new_data.end(), data_.begin());
  266. return true;
  267. }
  268. template <typename Real>
  269. const std::vector<Real>& PGMImage<Real>::data() const {
  270. return data_;
  271. }
  272. } // namespace ceres::examples
  273. #endif // CERES_EXAMPLES_PGM_IMAGE_H_