image_store.cc
Go to the documentation of this file.
1 /*
2  * This file is part of the rc_genicam_api package.
3  *
4  * Copyright (c) 2019 Roboception GmbH
5  * All rights reserved
6  *
7  * Author: Heiko Hirschmueller
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its contributors
20  * may be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include "image_store.h"
37 #include "pixel_formats.h"
38 
39 #include <exception>
40 
41 #include <iostream>
42 #include <fstream>
43 #include <sstream>
44 #include <iomanip>
45 #include <limits>
46 #include <algorithm>
47 
48 #ifdef INCLUDE_PNG
49 #include <png.h>
50 #endif
51 
52 #ifdef _WIN32
53 #undef min
54 #undef max
55 #endif
56 
57 namespace rcg
58 {
59 
60 std::string ensureNewFileName(std::string name)
61 {
62  // check if given name is already used
63 
64  std::ifstream file(name);
65 
66  if (file.is_open())
67  {
68  file.close();
69 
70  // split name in prefix and suffix
71 
72  std::string suffix;
73 
74  size_t i=name.rfind('.');
75  if (i != name.npos && name.size()-i <= 4)
76  {
77  suffix=name.substr(i);
78  name=name.substr(0, i);
79  }
80 
81  // add number for finding name that is nor used
82 
83  int n=1;
84  while (n < 100)
85  {
87  s << name << "_" << n << suffix;
88 
89  file.open(s.str());
90  if (!file.is_open())
91  {
92  name=s.str();
93  break;
94  }
95 
96  file.close();
97  n++;
98  }
99  }
100 
101  return name;
102 }
103 
104 namespace
105 {
106 
107 class IOException : public std::exception
108 {
109  public:
110 
111  IOException(const std::string &_msg) { msg=_msg; }
112  virtual const char *what() const noexcept { return msg.c_str(); }
113 
114  private:
115 
116  std::string msg;
117 };
118 
119 std::string storeImagePNM(const std::string &name, const Image &image, size_t yoffset,
120  size_t height)
121 {
122  size_t width=image.getWidth();
123  size_t real_height=image.getHeight();
124 
125  if (height == 0) height=real_height;
126 
127  yoffset=std::min(yoffset, real_height);
128  height=std::min(height, real_height-yoffset);
129 
130  const unsigned char *p=static_cast<const unsigned char *>(image.getPixels());
131 
132  size_t px=image.getXPadding();
133 
134  uint64_t format=image.getPixelFormat();
135  std::string full_name;
136 
137  switch (format)
138  {
139  case Mono8: // store 8 bit monochrome image
140  case Confidence8:
141  case Error8:
142  {
143  full_name=ensureNewFileName(name+".pgm");
144  std::ofstream out(full_name, std::ios::binary);
145 
146  out << "P5" << std::endl;
147  out << width << " " << height << std::endl;
148  out << 255 << "\n";
149 
150  std::streambuf *sb=out.rdbuf();
151 
152  p+=(width+px)*yoffset;
153  for (size_t k=0; k<height && out.good(); k++)
154  {
155  for (size_t i=0; i<width; i++)
156  {
157  sb->sputc(static_cast<char>(*p++));
158  }
159 
160  p+=px;
161  }
162 
163  out.close();
164  }
165  break;
166 
167  case Mono16:
168  case Coord3D_C16: // store 16 bit monochrome image
169  {
170  full_name=ensureNewFileName(name+".pgm");
171  std::ofstream out(full_name, std::ios::binary);
172 
173  out << "P5" << std::endl;
174  out << width << " " << height << std::endl;
175  out << 65535 << "\n";
176 
177  std::streambuf *sb=out.rdbuf();
178 
179  // copy image data, pgm is always big endian
180 
181  p+=(2*width+px)*yoffset;
182  if (image.isBigEndian())
183  {
184  for (size_t k=0; k<height && out.good(); k++)
185  {
186  for (size_t i=0; i<width; i++)
187  {
188  sb->sputc(static_cast<char>(*p++));
189  sb->sputc(static_cast<char>(*p++));
190  }
191 
192  p+=px;
193  }
194  }
195  else
196  {
197  for (size_t k=0; k<height && out.good(); k++)
198  {
199  for (size_t i=0; i<width; i++)
200  {
201  sb->sputc(static_cast<char>(p[1]));
202  sb->sputc(static_cast<char>(p[0]));
203  p+=2;
204  }
205 
206  p+=px;
207  }
208  }
209 
210  out.close();
211  }
212  break;
213 
214  case YCbCr411_8: // convert and store as color image
215  {
216  full_name=ensureNewFileName(name+".ppm");
217  std::ofstream out(full_name, std::ios::binary);
218 
219  out << "P6" << std::endl;
220  out << width << " " << height << std::endl;
221  out << 255 << "\n";
222 
223  std::streambuf *sb=out.rdbuf();
224 
225  size_t pstep=(width>>2)*6+px;
226  p+=pstep*yoffset;
227  for (size_t k=0; k<height && out.good(); k++)
228  {
229  for (size_t i=0; i<width; i+=4)
230  {
231  uint8_t rgb[12];
232  convYCbCr411toQuadRGB(rgb, p, static_cast<int>(i));
233 
234  for (int j=0; j<12; j++)
235  {
236  sb->sputc(static_cast<char>(rgb[j]));
237  }
238  }
239 
240  p+=pstep;
241  }
242 
243  out.close();
244  }
245  break;
246 
247  default: // try to store as color image
248  {
249  std::unique_ptr<uint8_t []> rgb_pixel(new uint8_t [3*width*height]);
250 
251  if (format == RGB8)
252  {
253  p+=(3*width+px)*yoffset;
254  }
255  else
256  {
257  p+=(width+px)*yoffset;
258  }
259 
260  if (convertImage(rgb_pixel.get(), 0, p, format, width, height, px))
261  {
262  p=rgb_pixel.get();
263 
264  full_name=ensureNewFileName(name+".ppm");
265  std::ofstream out(full_name, std::ios::binary);
266 
267  out << "P6" << std::endl;
268  out << width << " " << height << std::endl;
269  out << 255 << "\n";
270 
271  std::streambuf *sb=out.rdbuf();
272 
273  for (size_t k=0; k<height && out.good(); k++)
274  {
275  for (size_t i=0; i<width; i++)
276  {
277  sb->sputc(static_cast<char>(*p++));
278  sb->sputc(static_cast<char>(*p++));
279  sb->sputc(static_cast<char>(*p++));
280  }
281  }
282 
283  out.close();
284  }
285  else
286  {
287  throw IOException(std::string("storeImage(): Unsupported pixel format: ")+
288  GetPixelFormatName(static_cast<PfncFormat>(image.getPixelFormat())));
289  }
290  }
291  break;
292  }
293 
294  return full_name;
295 }
296 
297 #ifdef INCLUDE_PNG
298 
299 std::string storeImagePNG(const std::string &name, const Image &image, size_t yoffset,
300  size_t height)
301 {
302  size_t width=image.getWidth();
303  size_t real_height=image.getHeight();
304 
305  if (height == 0) height=real_height;
306 
307  yoffset=std::min(yoffset, real_height);
308  height=std::min(height, real_height-yoffset);
309 
310  const unsigned char *p=static_cast<const unsigned char *>(image.getPixels());
311 
312  size_t px=image.getXPadding();
313 
314  uint64_t format=image.getPixelFormat();
315  std::string full_name;
316 
317  switch (format)
318  {
319  case Mono8: // store 8 bit monochrome image
320  case Confidence8:
321  case Error8:
322  {
323  // open file and init
324 
325  full_name=ensureNewFileName(name+".png");
326  FILE *out=fopen(full_name.c_str(), "wb");
327 
328  if (!out)
329  {
330  throw new IOException("Cannot store file: "+full_name);
331  }
332 
333  png_structp png=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
334  png_infop info=png_create_info_struct(png);
335  setjmp(png_jmpbuf(png));
336 
337  // write header
338 
339  png_init_io(png, out);
340  png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_GRAY,
341  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
342  PNG_FILTER_TYPE_DEFAULT);
343  png_write_info(png, info);
344 
345  // write image body
346 
347  p+=(width+px)*yoffset;
348  for (size_t k=0; k<height; k++)
349  {
350  png_write_row(png, const_cast<png_bytep>(p));
351  p+=width+px;
352  }
353 
354  // close file
355 
356  png_write_end(png, info);
357  fclose(out);
358  png_destroy_write_struct(&png, &info);
359  }
360  break;
361 
362  case Mono16:
363  case Coord3D_C16: // store 16 bit monochrome image
364  {
365  // open file and init
366 
367  full_name=ensureNewFileName(name+".png");
368  FILE *out=fopen(full_name.c_str(), "wb");
369 
370  if (!out)
371  {
372  throw new IOException("Cannot store file: "+full_name);
373  }
374 
375  png_structp png=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
376  png_infop info=png_create_info_struct(png);
377  setjmp(png_jmpbuf(png));
378 
379  // write header
380 
381  png_init_io(png, out);
382  png_set_IHDR(png, info, width, height, 16, PNG_COLOR_TYPE_GRAY,
383  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
384  PNG_FILTER_TYPE_DEFAULT);
385  png_write_info(png, info);
386 
387  // write image body
388 
389  if (!image.isBigEndian())
390  {
391  png_set_swap(png);
392  }
393 
394  p+=(2*width+px)*yoffset;
395  for (size_t k=0; k<height; k++)
396  {
397  png_write_row(png, const_cast<png_bytep>(p));
398  p+=2*width+px;
399  }
400 
401  // close file
402 
403  png_write_end(png, info);
404  fclose(out);
405  png_destroy_write_struct(&png, &info);
406  }
407  break;
408 
409  case YCbCr411_8: // convert and store as color image
410  {
411  // open file and init
412 
413  full_name=ensureNewFileName(name+".png");
414  FILE *out=fopen(full_name.c_str(), "wb");
415 
416  if (!out)
417  {
418  throw new IOException("Cannot store file: "+full_name);
419  }
420 
421  png_structp png=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
422  png_infop info=png_create_info_struct(png);
423  setjmp(png_jmpbuf(png));
424 
425  // write header
426 
427  png_init_io(png, out);
428  png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB,
429  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
430  PNG_FILTER_TYPE_DEFAULT);
431  png_write_info(png, info);
432 
433  // write image body
434 
435  uint8_t *tmp=new uint8_t [3*width];
436 
437  size_t pstep=(width>>2)*6+px;
438 
439  p+=pstep*yoffset;
440  for (size_t k=0; k<height; k++)
441  {
442  for (size_t i=0; i<width; i+=4)
443  {
444  convYCbCr411toQuadRGB(tmp+3*i, p, static_cast<int>(i));
445  }
446 
447  png_write_row(png, tmp);
448  p+=pstep;
449  }
450 
451  // close file
452 
453  png_write_end(png, info);
454  fclose(out);
455  png_destroy_write_struct(&png, &info);
456  }
457  break;
458 
459  default: // try to store as color image
460  {
461  std::unique_ptr<uint8_t []> rgb_pixel(new uint8_t [3*width*height]);
462 
463  if (format == RGB8)
464  {
465  p+=(3*width+px)*yoffset;
466  }
467  else
468  {
469  p+=(width+px)*yoffset;
470  }
471 
472  if (convertImage(rgb_pixel.get(), 0, p, format, width, height, px))
473  {
474  p=rgb_pixel.get();
475 
476  // open file and init
477 
478  full_name=ensureNewFileName(name+".png");
479  FILE *out=fopen(full_name.c_str(), "wb");
480 
481  if (!out)
482  {
483  throw new IOException("Cannot store file: "+full_name);
484  }
485 
486  png_structp png=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
487  png_infop info=png_create_info_struct(png);
488  setjmp(png_jmpbuf(png));
489 
490  // write header
491 
492  png_init_io(png, out);
493  png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB,
494  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
495  PNG_FILTER_TYPE_DEFAULT);
496  png_write_info(png, info);
497 
498  // write image body
499 
500  for (size_t k=0; k<height; k++)
501  {
502  png_write_row(png, p);
503  p+=3*width;
504  }
505 
506  // close file
507 
508  png_write_end(png, info);
509  fclose(out);
510  png_destroy_write_struct(&png, &info);
511  }
512  else
513  {
514  throw IOException(std::string("storeImage(): Unsupported pixel format: ")+
515  GetPixelFormatName(static_cast<PfncFormat>(image.getPixelFormat())));
516  }
517  }
518  break;
519  }
520 
521  return full_name;
522 }
523 
524 #endif
525 
526 }
527 
528 std::string storeImage(const std::string &name, ImgFmt fmt, const Image &image,
529  size_t yoffset, size_t height)
530 {
531  std::string ret;
532 
533  switch (fmt)
534  {
535  case PNG:
536 #ifdef INCLUDE_PNG
537  ret=storeImagePNG(name, image, yoffset, height);
538 #else
539  throw IOException("storeImage(): Support for PNG image file format is not compiled in!");
540 #endif
541  break;
542 
543  default:
544  case PNM:
545  ret=storeImagePNM(name, image, yoffset, height);
546  break;
547  }
548 
549  return ret;
550 }
551 
552 std::string storeImageAsDisparityPFM(const std::string &name, const Image &image, int inv,
553  float scale, float offset)
554 {
555  if (image.getPixelFormat() != Coord3D_C16)
556  {
557  throw IOException(std::string("storeImageAsDisparityPFM(): Format Coord3D_C16 expected: ")+
558  GetPixelFormatName(static_cast<PfncFormat>(image.getPixelFormat())));
559  }
560 
561  if (scale == 0)
562  {
563  throw IOException(std::string("storeImageAsDisparityPFM(): Scale must not be 0!"));
564  }
565 
566  // convert values and store disparity image
567 
568  size_t px=image.getXPadding();
569  size_t width=image.getWidth();
570  size_t height=image.getHeight();
571  const unsigned char *p=static_cast<const unsigned char *>(image.getPixels())+
572  2*(width+px)*(height+1);
573 
574  std::string full_name=ensureNewFileName(name+".pfm");
575  std::ofstream out(full_name, std::ios::binary);
576 
577  out << "Pf" << std::endl;
578  out << width << " " << height << std::endl;
579  out << 1 << "\n";
580 
581  std::streambuf *sb=out.rdbuf();
582 
583  // get 16 bit data, scale and add offset and store as big endian
584 
585  bool msbfirst=true;
586 
587  {
588  int pp=1;
589  char *cc=reinterpret_cast<char *>(&pp);
590  msbfirst=(cc[0] != 1);
591  }
592 
593  for (size_t k=0; k<height && out.good(); k++)
594  {
595  p-=(width+px)<<2;
596  for (size_t i=0; i<width; i++)
597  {
598  int val;
599  if (image.isBigEndian())
600  {
601  val=(static_cast<int>(p[0])<<8)|p[1];
602  }
603  else
604  {
605  val=(static_cast<int>(p[1])<<8)|p[0];
606  }
607 
608  p+=2;
609 
610  float d=std::numeric_limits<float>::infinity();
611  if (val != inv)
612  {
613  d=static_cast<float>(val*scale+offset);
614  }
615 
616  char *c=reinterpret_cast<char *>(&d);
617 
618  if (msbfirst)
619  {
620  sb->sputc(c[0]);
621  sb->sputc(c[1]);
622  sb->sputc(c[2]);
623  sb->sputc(c[3]);
624  }
625  else
626  {
627  sb->sputc(c[3]);
628  sb->sputc(c[2]);
629  sb->sputc(c[1]);
630  sb->sputc(c[0]);
631  }
632 
633  p+=px;
634  }
635  }
636 
637  out.close();
638 
639  return full_name;
640 }
641 
642 }
std::string ensureNewFileName(std::string name)
This method checks if the given file name already exists and produces a new file name if this happens...
Definition: image_store.cc:60
The image class encapsulates image information.
Definition: image.h:55
size_t getWidth() const
Definition: image.h:78
ImgFmt
Definition: image_store.h:46
Definition: PFNC.h:272
size_t getHeight() const
Definition: image.h:79
std::string storeImage(const std::string &name, ImgFmt fmt, const Image &image, size_t yoffset, size_t height)
Stores the given image.
Definition: image_store.cc:528
uint64_t getPixelFormat() const
Definition: image.h:85
std::string str()
void convYCbCr411toQuadRGB(uint8_t rgb[12], const uint8_t *row, int i)
Conversion of a group of four pixels from YCbCr411 format (6 bytes for four pixels) to RGB...
Definition: image.cc:112
bool isBigEndian() const
Definition: image.h:86
#define Error8
Definition: pixel_formats.h:46
Definition: PFNC.h:311
bool convertImage(uint8_t *rgb_out, uint8_t *mono_out, const uint8_t *raw, uint64_t pixelformat, size_t width, size_t height, size_t xpadding)
Converts image to RGB and monochrome format.
Definition: image.cc:373
const uint8_t * getPixels() const
Pointer to pixel information of the image.
Definition: image.h:74
size_t getXPadding() const
Definition: image.h:82
Definition: PFNC.h:279
Definition: buffer.cc:47
std::string storeImageAsDisparityPFM(const std::string &name, const Image &image, int inv, float scale, float offset)
Stores the given image as disparity.
Definition: image_store.cc:552


rc_genicam_api
Author(s): Heiko Hirschmueller
autogenerated on Wed Mar 17 2021 02:48:40