All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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  case YCbCr422_8:
216  case YUV422_8:
217  {
218  full_name=ensureNewFileName(name+".ppm");
219  std::ofstream out(full_name, std::ios::binary);
220 
221  out << "P6" << std::endl;
222  out << width << " " << height << std::endl;
223  out << 255 << "\n";
224 
225  std::streambuf *sb=out.rdbuf();
226 
227  size_t pstep;
228  if (format == YCbCr411_8)
229  {
230  pstep=(width>>2)*6+px;
231  }
232  else
233  {
234  pstep=(width>>2)*8+px;
235  }
236 
237  p+=pstep*yoffset;
238  for (size_t k=0; k<height && out.good(); k++)
239  {
240  for (size_t i=0; i<width; i+=4)
241  {
242  uint8_t rgb[12];
243 
244  if (format == YCbCr411_8)
245  {
246  convYCbCr411toQuadRGB(rgb, p, static_cast<int>(i));
247  }
248  else
249  {
250  convYCbCr422toQuadRGB(rgb, p, static_cast<int>(i));
251  }
252 
253  for (int j=0; j<12; j++)
254  {
255  sb->sputc(static_cast<char>(rgb[j]));
256  }
257  }
258 
259  p+=pstep;
260  }
261 
262  out.close();
263  }
264  break;
265 
266  default: // try to store as color image
267  {
268  std::unique_ptr<uint8_t []> rgb_pixel(new uint8_t [3*width*height]);
269 
270  if (format == RGB8)
271  {
272  p+=(3*width+px)*yoffset;
273  }
274  else
275  {
276  p+=(width+px)*yoffset;
277  }
278 
279  if (convertImage(rgb_pixel.get(), 0, p, format, width, height, px))
280  {
281  p=rgb_pixel.get();
282 
283  full_name=ensureNewFileName(name+".ppm");
284  std::ofstream out(full_name, std::ios::binary);
285 
286  out << "P6" << std::endl;
287  out << width << " " << height << std::endl;
288  out << 255 << "\n";
289 
290  std::streambuf *sb=out.rdbuf();
291 
292  for (size_t k=0; k<height && out.good(); k++)
293  {
294  for (size_t i=0; i<width; i++)
295  {
296  sb->sputc(static_cast<char>(*p++));
297  sb->sputc(static_cast<char>(*p++));
298  sb->sputc(static_cast<char>(*p++));
299  }
300  }
301 
302  out.close();
303  }
304  else
305  {
306  throw IOException(std::string("storeImage(): Unsupported pixel format: ")+
307  GetPixelFormatName(static_cast<PfncFormat>(image.getPixelFormat())));
308  }
309  }
310  break;
311  }
312 
313  return full_name;
314 }
315 
316 #ifdef INCLUDE_PNG
317 
318 std::string storeImagePNG(const std::string &name, const Image &image, size_t yoffset,
319  size_t height)
320 {
321  size_t width=image.getWidth();
322  size_t real_height=image.getHeight();
323 
324  if (height == 0) height=real_height;
325 
326  yoffset=std::min(yoffset, real_height);
327  height=std::min(height, real_height-yoffset);
328 
329  const unsigned char *p=static_cast<const unsigned char *>(image.getPixels());
330 
331  size_t px=image.getXPadding();
332 
333  uint64_t format=image.getPixelFormat();
334  std::string full_name;
335 
336  switch (format)
337  {
338  case Mono8: // store 8 bit monochrome image
339  case Confidence8:
340  case Error8:
341  {
342  // open file and init
343 
344  full_name=ensureNewFileName(name+".png");
345  FILE *out=fopen(full_name.c_str(), "wb");
346 
347  if (!out)
348  {
349  throw new IOException("Cannot store file: "+full_name);
350  }
351 
352  png_structp png=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
353  png_infop info=png_create_info_struct(png);
354  setjmp(png_jmpbuf(png));
355 
356  // write header
357 
358  png_init_io(png, out);
359  png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_GRAY,
360  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
361  PNG_FILTER_TYPE_DEFAULT);
362  png_write_info(png, info);
363 
364  // write image body
365 
366  p+=(width+px)*yoffset;
367  for (size_t k=0; k<height; k++)
368  {
369  png_write_row(png, const_cast<png_bytep>(p));
370  p+=width+px;
371  }
372 
373  // close file
374 
375  png_write_end(png, info);
376  fclose(out);
377  png_destroy_write_struct(&png, &info);
378  }
379  break;
380 
381  case Mono16:
382  case Coord3D_C16: // store 16 bit monochrome image
383  {
384  // open file and init
385 
386  full_name=ensureNewFileName(name+".png");
387  FILE *out=fopen(full_name.c_str(), "wb");
388 
389  if (!out)
390  {
391  throw new IOException("Cannot store file: "+full_name);
392  }
393 
394  png_structp png=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
395  png_infop info=png_create_info_struct(png);
396  setjmp(png_jmpbuf(png));
397 
398  // write header
399 
400  png_init_io(png, out);
401  png_set_IHDR(png, info, width, height, 16, PNG_COLOR_TYPE_GRAY,
402  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
403  PNG_FILTER_TYPE_DEFAULT);
404  png_write_info(png, info);
405 
406  // write image body
407 
408  if (!image.isBigEndian())
409  {
410  png_set_swap(png);
411  }
412 
413  p+=(2*width+px)*yoffset;
414  for (size_t k=0; k<height; k++)
415  {
416  png_write_row(png, const_cast<png_bytep>(p));
417  p+=2*width+px;
418  }
419 
420  // close file
421 
422  png_write_end(png, info);
423  fclose(out);
424  png_destroy_write_struct(&png, &info);
425  }
426  break;
427 
428  case YCbCr411_8: // convert and store as color image
429  case YCbCr422_8:
430  case YUV422_8:
431  {
432  // open file and init
433 
434  full_name=ensureNewFileName(name+".png");
435  FILE *out=fopen(full_name.c_str(), "wb");
436 
437  if (!out)
438  {
439  throw new IOException("Cannot store file: "+full_name);
440  }
441 
442  png_structp png=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
443  png_infop info=png_create_info_struct(png);
444  setjmp(png_jmpbuf(png));
445 
446  // write header
447 
448  png_init_io(png, out);
449  png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB,
450  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
451  PNG_FILTER_TYPE_DEFAULT);
452  png_write_info(png, info);
453 
454  // write image body
455 
456  uint8_t *tmp=new uint8_t [3*width];
457 
458  size_t pstep;
459  if (format == YCbCr411_8)
460  {
461  pstep=(width>>2)*6+px;
462  }
463  else
464  {
465  pstep=(width>>2)*8+px;
466  }
467 
468  p+=pstep*yoffset;
469  for (size_t k=0; k<height; k++)
470  {
471  if (format == YCbCr411_8)
472  {
473  for (size_t i=0; i<width; i+=4)
474  {
475  convYCbCr411toQuadRGB(tmp+3*i, p, static_cast<int>(i));
476  }
477  }
478  else
479  {
480  for (size_t i=0; i<width; i+=4)
481  {
482  convYCbCr422toQuadRGB(tmp+3*i, p, static_cast<int>(i));
483  }
484  }
485 
486  png_write_row(png, tmp);
487  p+=pstep;
488  }
489 
490  // close file
491 
492  png_write_end(png, info);
493  fclose(out);
494  png_destroy_write_struct(&png, &info);
495  }
496  break;
497 
498  default: // try to store as color image
499  {
500  std::unique_ptr<uint8_t []> rgb_pixel(new uint8_t [3*width*height]);
501 
502  if (format == RGB8)
503  {
504  p+=(3*width+px)*yoffset;
505  }
506  else
507  {
508  p+=(width+px)*yoffset;
509  }
510 
511  if (convertImage(rgb_pixel.get(), 0, p, format, width, height, px))
512  {
513  p=rgb_pixel.get();
514 
515  // open file and init
516 
517  full_name=ensureNewFileName(name+".png");
518  FILE *out=fopen(full_name.c_str(), "wb");
519 
520  if (!out)
521  {
522  throw new IOException("Cannot store file: "+full_name);
523  }
524 
525  png_structp png=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
526  png_infop info=png_create_info_struct(png);
527  setjmp(png_jmpbuf(png));
528 
529  // write header
530 
531  png_init_io(png, out);
532  png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB,
533  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
534  PNG_FILTER_TYPE_DEFAULT);
535  png_write_info(png, info);
536 
537  // write image body
538 
539  for (size_t k=0; k<height; k++)
540  {
541  png_write_row(png, const_cast<png_bytep>(p));
542  p+=3*width;
543  }
544 
545  // close file
546 
547  png_write_end(png, info);
548  fclose(out);
549  png_destroy_write_struct(&png, &info);
550  }
551  else
552  {
553  throw IOException(std::string("storeImage(): Unsupported pixel format: ")+
554  GetPixelFormatName(static_cast<PfncFormat>(image.getPixelFormat())));
555  }
556  }
557  break;
558  }
559 
560  return full_name;
561 }
562 
563 #endif
564 
565 }
566 
567 std::string storeImage(const std::string &name, ImgFmt fmt, const Image &image,
568  size_t yoffset, size_t height)
569 {
570  std::string ret;
571 
572  switch (fmt)
573  {
574  case PNG:
575 #ifdef INCLUDE_PNG
576  ret=storeImagePNG(name, image, yoffset, height);
577 #else
578  throw IOException("storeImage(): Support for PNG image file format is not compiled in!");
579 #endif
580  break;
581 
582  default:
583  case PNM:
584  ret=storeImagePNM(name, image, yoffset, height);
585  break;
586  }
587 
588  return ret;
589 }
590 
591 std::string storeImageAsDisparityPFM(const std::string &name, const Image &image, int inv,
592  float scale, float offset)
593 {
594  if (image.getPixelFormat() != Coord3D_C16)
595  {
596  throw IOException(std::string("storeImageAsDisparityPFM(): Format Coord3D_C16 expected: ")+
597  GetPixelFormatName(static_cast<PfncFormat>(image.getPixelFormat())));
598  }
599 
600  if (scale == 0)
601  {
602  throw IOException(std::string("storeImageAsDisparityPFM(): Scale must not be 0!"));
603  }
604 
605  // convert values and store disparity image
606 
607  size_t px=image.getXPadding();
608  size_t width=image.getWidth();
609  size_t height=image.getHeight();
610  const unsigned char *p=static_cast<const unsigned char *>(image.getPixels())+
611  2*(width+px)*(height+1);
612 
613  std::string full_name=ensureNewFileName(name+".pfm");
614  std::ofstream out(full_name, std::ios::binary);
615 
616  out << "Pf" << std::endl;
617  out << width << " " << height << std::endl;
618  out << 1 << "\n";
619 
620  std::streambuf *sb=out.rdbuf();
621 
622  // get 16 bit data, scale and add offset and store as big endian
623 
624  bool msbfirst=true;
625 
626  {
627  int pp=1;
628  char *cc=reinterpret_cast<char *>(&pp);
629  msbfirst=(cc[0] != 1);
630  }
631 
632  for (size_t k=0; k<height && out.good(); k++)
633  {
634  p-=(width+px)<<2;
635  for (size_t i=0; i<width; i++)
636  {
637  int val;
638  if (image.isBigEndian())
639  {
640  val=(static_cast<int>(p[0])<<8)|p[1];
641  }
642  else
643  {
644  val=(static_cast<int>(p[1])<<8)|p[0];
645  }
646 
647  p+=2;
648 
649  float d=std::numeric_limits<float>::infinity();
650  if (val != inv)
651  {
652  d=static_cast<float>(val*scale+offset);
653  }
654 
655  char *c=reinterpret_cast<char *>(&d);
656 
657  if (msbfirst)
658  {
659  sb->sputc(c[0]);
660  sb->sputc(c[1]);
661  sb->sputc(c[2]);
662  sb->sputc(c[3]);
663  }
664  else
665  {
666  sb->sputc(c[3]);
667  sb->sputc(c[2]);
668  sb->sputc(c[1]);
669  sb->sputc(c[0]);
670  }
671 
672  p+=px;
673  }
674  }
675 
676  out.close();
677 
678  return full_name;
679 }
680 
681 }
YUV422_8
@ YUV422_8
Definition: PFNC.h:565
Confidence8
@ Confidence8
Definition: PFNC.h:442
rcg::Image
The image class encapsulates image information.
Definition: image.h:55
YCbCr422_8
@ YCbCr422_8
Definition: PFNC.h:503
rcg::Image::getHeight
size_t getHeight() const
Definition: image.h:79
YCbCr411_8
@ YCbCr411_8
Definition: PFNC.h:499
rcg::Image::isBigEndian
bool isBigEndian() const
Definition: image.h:86
rcg
Definition: buffer.cc:47
pixel_formats.h
rcg::ImgFmt
ImgFmt
Definition: image_store.h:46
rcg::storeImage
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:567
rcg::storeImageAsDisparityPFM
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:591
rcg::Image::getPixelFormat
uint64_t getPixelFormat() const
Definition: image.h:85
rcg::Image::getXPadding
size_t getXPadding() const
Definition: image.h:82
rcg::convYCbCr411toQuadRGB
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:123
Coord3D_C16
@ Coord3D_C16
Definition: PFNC.h:438
rcg::ensureNewFileName
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
Mono16
@ Mono16
Definition: PFNC.h:314
rcg::convertImage
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:486
std::ostringstream::str
std::string str()
RGB8
@ RGB8
Definition: PFNC.h:359
std::ostringstream
Definition: Portability.hh:42
width
Definition: Manipulator.hh:15
Error8
#define Error8
Definition: pixel_formats.h:46
PfncFormat
enum PfncFormat_ PfncFormat
rcg::Image::getWidth
size_t getWidth() const
Definition: image.h:78
image_store.h
rcg::Image::getPixels
const uint8_t * getPixels() const
Pointer to pixel information of the image.
Definition: image.h:74
rcg::PNM
@ PNM
Definition: image_store.h:46
rcg::convYCbCr422toQuadRGB
void convYCbCr422toQuadRGB(uint8_t rgb[12], const uint8_t *row, int i)
Conversion of a group of four pixels from YCbCr422 format (8 bytes for 4 pixels) to RGB.
Definition: image.cc:163
Mono8
@ Mono8
Definition: PFNC.h:306
rcg::PNG
@ PNG
Definition: image_store.h:46


rc_genicam_api
Author(s): Heiko Hirschmueller
autogenerated on Wed Dec 4 2024 03:10:11