A tool to construct HDR-images from a series of exposures.

image.cpp 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #include <stdio.h>
  2. // for error recovery
  3. #include <setjmp.h>
  4. #include <iostream>
  5. #include <fstream>
  6. #include <sstream>
  7. #include <vector>
  8. #include "jpeglib.h"
  9. #define STB_IMAGE_IMPLEMENTATION
  10. #include "stb_image.h"
  11. #include "image.h"
  12. #include "exif.h"
  13. using namespace std;
  14. using namespace haader;
  15. Image::Image():
  16. m_width(0),
  17. m_height(0),
  18. m_components(0),
  19. m_exposure_time(0.0)
  20. {
  21. }
  22. void Image::to_string(string &s) const {
  23. stringstream ss;
  24. ss << "Image(";
  25. ss << m_width << 'x' << m_height << 'x' << m_components << ")";
  26. s = ss.str();
  27. }
  28. bool Image::read_from_file(const char *file_path) {
  29. int x = 0;
  30. int y = 0;
  31. int components = 0;
  32. unsigned char *data = stbi_load(file_path, &x, &y, &components, 0);
  33. if (data) {
  34. m_width = x;
  35. m_height = y;
  36. m_components = components;
  37. size_t size = (size_t)x * (size_t)y * (size_t)components;
  38. m_image_data.assign(data, data + size);
  39. // try to read EXIF data
  40. {
  41. ExifTags tags;
  42. ifstream stream;
  43. stream.open(file_path);
  44. if (stream.is_open() and ExifTags::read_from_jpeg(stream, tags)) {
  45. if (tags.get_exposure_time(m_exposure_time)) {
  46. cout << "Exposure time: " << m_exposure_time << " sec" << endl;
  47. }
  48. }
  49. }
  50. return true;
  51. } else {
  52. cerr << "Can not read \"" << file_path << "\" as an image." << endl;
  53. return false;
  54. }
  55. stbi_image_free(data);
  56. }
  57. struct my_error_mgr {
  58. struct jpeg_error_mgr pub; /* "public" fields */
  59. jmp_buf setjmp_buffer; /* for return to caller */
  60. };
  61. typedef struct my_error_mgr * my_error_ptr;
  62. /*
  63. * Here's the routine that will replace the standard error_exit method:
  64. */
  65. METHODDEF(void)
  66. my_error_exit (j_common_ptr cinfo)
  67. {
  68. /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  69. my_error_ptr myerr = (my_error_ptr) cinfo->err;
  70. /* Always display the message. */
  71. /* We could postpone this until after returning, if we chose. */
  72. (*cinfo->err->output_message) (cinfo);
  73. /* Return control to the setjmp point */
  74. longjmp(myerr->setjmp_buffer, 1);
  75. }
  76. bool Image::read_from_jpeg_file(const char *file_path) {
  77. /* This struct contains the JPEG decompression parameters and pointers to
  78. * working space (which is allocated as needed by the JPEG library).
  79. */
  80. struct jpeg_decompress_struct cinfo;
  81. /* We use our private extension JPEG error handler.
  82. * Note that this struct must live as long as the main JPEG parameter
  83. * struct, to avoid dangling-pointer problems.
  84. */
  85. struct my_error_mgr jerr;
  86. /* More stuff */
  87. FILE * infile; /* source file */
  88. JSAMPARRAY buffer; /* Output row buffer */
  89. int row_stride; /* physical row width in output buffer */
  90. /* In this example we want to open the input file before doing anything else,
  91. * so that the setjmp() error recovery below can assume the file is open.
  92. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
  93. * requires it in order to read binary files.
  94. */
  95. if ((infile = fopen(file_path, "rb")) == NULL) {
  96. cerr << "Can not open \"" << file_path << "\"" << endl;
  97. return false;
  98. }
  99. /* Step 1: allocate and initialize JPEG decompression object */
  100. /* We set up the normal JPEG error routines, then override error_exit. */
  101. cinfo.err = jpeg_std_error(&jerr.pub);
  102. jerr.pub.error_exit = my_error_exit;
  103. /* Establish the setjmp return context for my_error_exit to use. */
  104. if (setjmp(jerr.setjmp_buffer)) {
  105. /* If we get here, the JPEG code has signaled an error.
  106. * We need to clean up the JPEG object, close the input file, and return.
  107. */
  108. jpeg_destroy_decompress(&cinfo);
  109. fclose(infile);
  110. return false;
  111. }
  112. /* Now we can initialize the JPEG decompression object. */
  113. jpeg_create_decompress(&cinfo);
  114. /* Step 2: specify data source (eg, a file) */
  115. jpeg_stdio_src(&cinfo, infile);
  116. /* Step 3: read file parameters with jpeg_read_header() */
  117. (void) jpeg_read_header(&cinfo, TRUE);
  118. /* We can ignore the return value from jpeg_read_header since
  119. * (a) suspension is not possible with the stdio data source, and
  120. * (b) we passed TRUE to reject a tables-only JPEG file as an error.
  121. * See libjpeg.txt for more info.
  122. */
  123. /* Step 4: set parameters for decompression */
  124. /* In this example, we don't need to change any of the defaults set by
  125. * jpeg_read_header(), so we do nothing here.
  126. */
  127. /* Step 5: Start decompressor */
  128. (void) jpeg_start_decompress(&cinfo);
  129. /* We can ignore the return value since suspension is not possible
  130. * with the stdio data source.
  131. */
  132. m_image_data.reserve(cinfo.output_width * cinfo.output_height * cinfo.output_components);
  133. m_width = cinfo.output_width;
  134. m_height = cinfo.output_height;
  135. m_components = cinfo.output_components;
  136. /* We may need to do some setup of our own at this point before reading
  137. * the data. After jpeg_start_decompress() we have the correct scaled
  138. * output image dimensions available, as well as the output colormap
  139. * if we asked for color quantization.
  140. * In this example, we need to make an output work buffer of the right size.
  141. */
  142. /* JSAMPLEs per row in output buffer */
  143. row_stride = cinfo.output_width * cinfo.output_components;
  144. /* Make a one-row-high sample array that will go away when done with image */
  145. buffer = (*cinfo.mem->alloc_sarray)
  146. ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
  147. /* Step 6: while (scan lines remain to be read) */
  148. /* jpeg_read_scanlines(...); */
  149. /* Here we use the library's state variable cinfo.output_scanline as the
  150. * loop counter, so that we don't have to keep track ourselves.
  151. */
  152. while (cinfo.output_scanline < cinfo.output_height) {
  153. /* jpeg_read_scanlines expects an array of pointers to scanlines.
  154. * Here the array is only one element long, but you could ask for
  155. * more than one scanline at a time if that's more convenient.
  156. */
  157. (void) jpeg_read_scanlines(&cinfo, buffer, 1);
  158. /* Assume put_scanline_someplace wants a pointer and sample count. */
  159. //put_scanline_someplace(buffer[0], row_stride);
  160. for (int i = 0; i < row_stride; i++) {
  161. m_image_data.push_back(buffer[0][i]);
  162. }
  163. }
  164. /* Step 7: Finish decompression */
  165. (void) jpeg_finish_decompress(&cinfo);
  166. /* We can ignore the return value since suspension is not possible
  167. * with the stdio data source.
  168. */
  169. /* Step 8: Release JPEG decompression object */
  170. /* This is an important step since it will release a good deal of memory. */
  171. jpeg_destroy_decompress(&cinfo);
  172. /* After finish_decompress, we can close the input file.
  173. * Here we postpone it until after no more JPEG errors are possible,
  174. * so as to simplify the setjmp error logic above. (Actually, I don't
  175. * think that jpeg_destroy can do an error exit, but why assume anything...)
  176. */
  177. fclose(infile);
  178. if (jerr.pub.num_warnings != 0) {
  179. cout << jerr.pub.num_warnings << " errors occured." << endl;
  180. return false;
  181. } else {
  182. return true;
  183. }
  184. }
  185. bool Image::save_as_ppm_file(const char *file_path, bool ascii) const {
  186. if (ascii) {
  187. // ASCII
  188. ofstream out(file_path);
  189. out << "P3\n";
  190. out << m_width << ' ' << m_height << '\n';
  191. out << "255\n";
  192. unsigned int pixels = m_width * m_height;
  193. unsigned int index = 0;
  194. for (unsigned int i = 0; i < pixels; i++) {
  195. out << (int)m_image_data[index] << ' ' << (int)m_image_data[index + 1] << ' ' << (int)m_image_data[index + 2] << '\n';
  196. index += 3;
  197. }
  198. out.close();
  199. return true;
  200. } else {
  201. // binary
  202. ofstream out(file_path);
  203. out << "P6\n";
  204. out << m_width << ' ' << m_height << '\n';
  205. out << "255\n";
  206. unsigned int pixels = m_width * m_height;
  207. unsigned int index = 0;
  208. for (unsigned int i = 0; i < pixels; i++) {
  209. out << m_image_data[index] << m_image_data[index + 1] << m_image_data[index + 2];
  210. index += 3;
  211. }
  212. out.close();
  213. return true;
  214. }
  215. }
  216. unsigned int Image::get_width() const {
  217. return m_width;
  218. }
  219. unsigned int Image::get_height() const {
  220. return m_height;
  221. }
  222. unsigned int Image::get_components() const {
  223. return m_components;
  224. }
  225. bool Image::has_equal_dimensions(const Image &other) const {
  226. return (m_width == other.m_width &&
  227. m_height == other.m_height &&
  228. m_components == other.m_components);
  229. }
  230. double Image::get_exposure_time() const {
  231. return m_exposure_time;
  232. }