MRPT  1.9.9
COccupancyGridMap2D_io.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "maps-precomp.h" // Precomp header
11 
12 #include <mrpt/config.h>
13 #include <mrpt/core/round.h> // round()
16 #include <mrpt/math/CMatrixF.h>
17 #include <mrpt/random.h>
19 #include <mrpt/system/os.h>
20 #include <iostream>
21 
22 using namespace mrpt;
23 using namespace mrpt::maps;
24 using namespace mrpt::tfest;
25 using namespace mrpt::math;
26 using namespace mrpt::obs;
27 using namespace mrpt::random;
28 using namespace mrpt::poses;
29 using namespace mrpt::img;
30 using namespace mrpt::system;
31 using namespace std;
32 
33 /*---------------------------------------------------------------
34  saveAsBitmapFile
35  ---------------------------------------------------------------*/
37 {
39 #if MRPT_HAS_OPENCV
40 
41  CImage img;
42  getAsImage(img);
43  return img.saveToFile(file);
44 
45 #else
46  std::cerr << "[COccupancyGridMap2D::saveAsBitmapFile] Doing nothing, since "
47  "MRPT was built without OpenCV.\n";
48  return true;
49 #endif
50  MRPT_END
51 }
52 
53 uint8_t COccupancyGridMap2D::serializeGetVersion() const { return 6; }
55 {
56 // Version 3: Change to log-odds. The only change is in the loader, when
57 // translating
58 // from older versions.
59 
60 // Version 2: Save OCCUPANCY_GRIDMAP_CELL_SIZE_8BITS/16BITS
61 #ifdef OCCUPANCY_GRIDMAP_CELL_SIZE_8BITS
62  out << uint8_t(8);
63 #else
64  out << uint8_t(16);
65 #endif
66 
67  out << size_x << size_y << x_min << x_max << y_min << y_max << resolution;
68  ASSERT_(size_x * size_y == map.size());
69 
70 #ifdef OCCUPANCY_GRIDMAP_CELL_SIZE_8BITS
71  out.WriteBuffer(&map[0], sizeof(map[0]) * size_x * size_y);
72 #else
73  out.WriteBufferFixEndianness(&map[0], size_x * size_y);
74 #endif
75 
76  // insertionOptions:
77  out << insertionOptions.mapAltitude << insertionOptions.useMapAltitude
78  << insertionOptions.maxDistanceInsertion
79  << insertionOptions.maxOccupancyUpdateCertainty
80  << insertionOptions.considerInvalidRangesAsFreeSpace
81  << insertionOptions.decimation << insertionOptions.horizontalTolerance;
82 
83  // Likelihood:
84  out << (int32_t)likelihoodOptions.likelihoodMethod
85  << likelihoodOptions.LF_stdHit << likelihoodOptions.LF_zHit
86  << likelihoodOptions.LF_zRandom << likelihoodOptions.LF_maxRange
87  << likelihoodOptions.LF_decimation
88  << likelihoodOptions.LF_maxCorrsDistance
89  << likelihoodOptions.LF_alternateAverageMethod
90  << likelihoodOptions.MI_exponent << likelihoodOptions.MI_skip_rays
91  << likelihoodOptions.MI_ratio_max_distance
92  << likelihoodOptions.rayTracing_useDistanceFilter
93  << likelihoodOptions.rayTracing_decimation
94  << likelihoodOptions.rayTracing_stdHit
95  << likelihoodOptions.consensus_takeEachRange
96  << likelihoodOptions.consensus_pow << likelihoodOptions.OWA_weights
97  << likelihoodOptions.enableLikelihoodCache;
98 
99  // Insertion as 3D:
100  out << genericMapParams; // v6
101 
102  // Version 4:
103  out << insertionOptions.CFD_features_gaussian_size
104  << insertionOptions.CFD_features_median_size;
105 
106  // Version: 5;
107  out << insertionOptions.wideningBeamsWithDistance;
108 }
109 
111  mrpt::serialization::CArchive& in, uint8_t version)
112 {
113  m_is_empty = false;
114 
115  switch (version)
116  {
117  case 0:
118  case 1:
119  case 2:
120  case 3:
121  case 4:
122  case 5:
123  case 6:
124  {
125 #ifdef OCCUPANCY_GRIDMAP_CELL_SIZE_8BITS
126  const uint8_t MyBitsPerCell = 8;
127 #else
128  const uint8_t MyBitsPerCell = 16;
129 #endif
130 
131  uint8_t bitsPerCellStream;
132 
133  // Version 2: OCCUPANCY_GRIDMAP_CELL_SIZE_8BITS/16BITS
134  if (version >= 2)
135  in >> bitsPerCellStream;
136  else
137  bitsPerCellStream =
138  MyBitsPerCell; // Old versinons: hope it's the same...
139 
140  uint32_t new_size_x, new_size_y;
141  float new_x_min, new_x_max, new_y_min, new_y_max;
142  float new_resolution;
143 
144  // resetFeaturesCache();
145 
146  in >> new_size_x >> new_size_y >> new_x_min >> new_x_max >>
147  new_y_min >> new_y_max >> new_resolution;
148 
149  setSize(
150  new_x_min, new_x_max, new_y_min, new_y_max, new_resolution,
151  0.5);
152 
153  ASSERT_(size_x * size_y == map.size());
154 
155  if (bitsPerCellStream == MyBitsPerCell)
156  {
157 // Perfect:
158 #ifdef OCCUPANCY_GRIDMAP_CELL_SIZE_8BITS
159  in.ReadBuffer(&map[0], sizeof(map[0]) * map.size());
160 #else
161  in.ReadBufferFixEndianness(&map[0], map.size());
162 #endif
163  }
164  else
165  {
166 // We must do a conversion...
167 #ifdef OCCUPANCY_GRIDMAP_CELL_SIZE_8BITS
168  // We are 8-bit, stream is 16-bit
169  ASSERT_(bitsPerCellStream == 16);
170  std::vector<uint16_t> auxMap(map.size());
171  in.ReadBuffer(&auxMap[0], sizeof(auxMap[0]) * auxMap.size());
172 
173  size_t i, N = map.size();
174  auto* ptrTrg = (uint8_t*)&map[0];
175  const auto* ptrSrc = (const uint16_t*)&auxMap[0];
176  for (i = 0; i < N; i++) *ptrTrg++ = (*ptrSrc++) >> 8;
177 #else
178  // We are 16-bit, stream is 8-bit
179  ASSERT_(bitsPerCellStream == 8);
180  std::vector<uint8_t> auxMap(map.size());
181  in.ReadBuffer(&auxMap[0], sizeof(auxMap[0]) * auxMap.size());
182 
183  size_t i, N = map.size();
184  uint16_t* ptrTrg = (uint16_t*)&map[0];
185  const uint8_t* ptrSrc = (const uint8_t*)&auxMap[0];
186  for (i = 0; i < N; i++) *ptrTrg++ = (*ptrSrc++) << 8;
187 #endif
188  }
189 
190  // If we are converting an old dump, convert from probabilities to
191  // log-odds:
192  if (version < 3)
193  {
194  size_t i, N = map.size();
195  cellType* ptr = &map[0];
196  for (i = 0; i < N; i++)
197  {
198  double p = cellTypeUnsigned(*ptr) * (1.0f / 0xFF);
199  if (p < 0) p = 0;
200  if (p > 1) p = 1;
201  *ptr++ = p2l(p);
202  }
203  }
204 
205  // For the precomputed likelihood trick:
206  m_likelihoodCacheOutDated = true;
207 
208  if (version >= 1)
209  {
210  // insertionOptions:
211  in >> insertionOptions.mapAltitude >>
212  insertionOptions.useMapAltitude >>
213  insertionOptions.maxDistanceInsertion >>
214  insertionOptions.maxOccupancyUpdateCertainty >>
215  insertionOptions.considerInvalidRangesAsFreeSpace >>
216  insertionOptions.decimation >>
217  insertionOptions.horizontalTolerance;
218 
219  // Likelihood:
220  int32_t i;
221  in >> i;
222  likelihoodOptions.likelihoodMethod =
223  static_cast<TLikelihoodMethod>(i);
224  in >> likelihoodOptions.LF_stdHit >>
225  likelihoodOptions.LF_zHit >> likelihoodOptions.LF_zRandom >>
226  likelihoodOptions.LF_maxRange >>
227  likelihoodOptions.LF_decimation >>
228  likelihoodOptions.LF_maxCorrsDistance >>
229  likelihoodOptions.LF_alternateAverageMethod >>
230  likelihoodOptions.MI_exponent >>
231  likelihoodOptions.MI_skip_rays >>
232  likelihoodOptions.MI_ratio_max_distance >>
233  likelihoodOptions.rayTracing_useDistanceFilter >>
234  likelihoodOptions.rayTracing_decimation >>
235  likelihoodOptions.rayTracing_stdHit >>
236  likelihoodOptions.consensus_takeEachRange >>
237  likelihoodOptions.consensus_pow >>
238  likelihoodOptions.OWA_weights >>
239  likelihoodOptions.enableLikelihoodCache;
240 
241  // Insertion as 3D:
242  if (version >= 6)
243  in >> genericMapParams;
244  else
245  {
246  bool disableSaveAs3DObject;
247  in >> disableSaveAs3DObject;
248  genericMapParams.enableSaveAs3DObject =
249  !disableSaveAs3DObject;
250  }
251  }
252 
253  if (version >= 4)
254  {
255  in >> insertionOptions.CFD_features_gaussian_size >>
256  insertionOptions.CFD_features_median_size;
257  }
258 
259  if (version >= 5)
260  {
261  in >> insertionOptions.wideningBeamsWithDistance;
262  }
263  }
264  break;
265  default:
267  };
268 }
269 
271  const std::string& file, float res, const TPoint2D& origin)
272 {
273  MRPT_START
274 
275  CImage imgFl;
276  if (!imgFl.loadFromFile(file, 0)) return false;
277 
278  m_is_empty = false;
279  return loadFromBitmap(imgFl, res, origin);
280 
281  MRPT_END
282 }
283 
285  const mrpt::img::CImage& imgFl, float res,
286  const mrpt::math::TPoint2D& origin_)
287 {
288  MRPT_START
289 
290  // For the precomputed likelihood trick:
291  m_likelihoodCacheOutDated = true;
292 
293  size_t bmpWidth = imgFl.getWidth();
294  size_t bmpHeight = imgFl.getHeight();
295 
296  if (size_x != bmpWidth || size_y != bmpHeight)
297  {
298  auto origin = origin_;
299  // Middle of bitmap?
300  if (origin.x == std::numeric_limits<double>::max())
301  {
302  origin = mrpt::math::TPoint2D(
303  imgFl.getWidth() / 2.0, imgFl.getHeight() / 2.0);
304  }
305 
306  // Resize grid:
307  float new_x_max = (imgFl.getWidth() - origin.x) * res;
308  float new_x_min = -origin.x * res;
309  float new_y_max = (imgFl.getHeight() - origin.y) * res;
310  float new_y_min = -origin.y * res;
311 
312  setSize(new_x_min, new_x_max, new_y_min, new_y_max, res);
313  }
314 
315  // And load cells content:
316  for (size_t x = 0; x < bmpWidth; x++)
317  for (size_t y = 0; y < bmpHeight; y++)
318  {
319  float f = imgFl.getAsFloat(x, bmpHeight - 1 - y);
320  f = std::max(0.01f, f);
321  f = std::min(0.99f, f);
322  setCell(x, y, f);
323  }
324 
325  m_is_empty = false;
326  return true;
327 
328  MRPT_END
329 }
330 
331 /*---------------------------------------------------------------
332  saveAsBitmapTwoMapsWithCorrespondences
333  ---------------------------------------------------------------*/
335  const std::string& fileName, const COccupancyGridMap2D* m1,
336  const COccupancyGridMap2D* m2, const TMatchingPairList& corrs)
337 {
338  MRPT_START
339 
340  CImage img1, img2;
341  unsigned int i, n, Ay1, Ay2;
342  unsigned int px, py;
343 
344  // The individual maps:
345  // ---------------------------------------------
346  m1->getAsImage(img1, false);
347  m2->getAsImage(img2, false);
348  unsigned int lx1 = img1.getWidth();
349  unsigned int ly1 = img1.getHeight();
350 
351  unsigned int lx2 = img2.getWidth();
352  unsigned int ly2 = img2.getHeight();
353 
354  // The map with the lowest height has to be vertically aligned:
355  if (ly1 > ly2)
356  {
357  Ay1 = 0;
358  Ay2 = (ly1 - ly2) / 2;
359  }
360  else
361  {
362  Ay2 = 0;
363  Ay1 = (ly2 - ly1) / 2;
364  }
365 
366  // Compute the size of the composite image:
367  // ---------------------------------------------
368  CImage img(lx1 + lx2 + 1, max(ly1, ly2), mrpt::img::CH_RGB);
369  img.filledRectangle(
370  0, 0, img.getWidth() - 1, img.getHeight() - 1,
371  TColor::black()); // background: black
372  img.drawImage(0, Ay1, img1);
373  img.drawImage(lx1 + 1, Ay2, img2);
374 
375  // Draw the features:
376  // ---------------------------------------------
377  n = corrs.size();
378  TColor lineColor = TColor::black();
379  for (i = 0; i < n; i++)
380  {
381  // In M1:
382  px = m1->x2idx(corrs[i].this_x);
383  py = Ay1 + ly1 - 1 - m1->y2idx(corrs[i].this_y);
384  img.rectangle(px - 10, py - 10, px + 10, py + 10, lineColor);
385  img.rectangle(px - 11, py - 11, px + 11, py + 11, lineColor);
386 
387  // In M2:
388  px = lx1 + 1 + m2->x2idx(corrs[i].other_x);
389  py = Ay2 + ly2 - 1 - m2->y2idx(corrs[i].other_y);
390  img.rectangle(px - 10, py - 10, px + 10, py + 10, lineColor);
391  img.rectangle(px - 11, py - 11, px + 11, py + 11, lineColor);
392  }
393 
394  // Draw the correspondences as lines:
395  // ---------------------------------------------
396  for (i = 0; i < n; i++)
397  {
398  lineColor = TColor(
399  static_cast<long>(getRandomGenerator().drawUniform(0, 255.0f)),
400  static_cast<long>(getRandomGenerator().drawUniform(0, 255.0f)),
401  static_cast<long>(getRandomGenerator().drawUniform(0, 255.0f)));
402 
403  img.line(
404  m1->x2idx(corrs[i].this_x),
405  // lx1+1+ m1->x2idx( corrs[i].this_x ),
406  Ay1 + ly1 - 1 - m1->y2idx(corrs[i].this_y),
407  lx1 + 1 + m2->x2idx(corrs[i].other_x),
408  Ay2 + ly2 - 1 - m2->y2idx(corrs[i].other_y), lineColor);
409  } // i
410 
411  return img.saveToFile(fileName.c_str());
412 
413  MRPT_END
414 }
415 
416 /*---------------------------------------------------------------
417  saveAsEMFTwoMapsWithCorrespondences
418  ---------------------------------------------------------------*/
420  const std::string& fileName, const COccupancyGridMap2D* m1,
421  const COccupancyGridMap2D* m2, const TMatchingPairList& corrs)
422 {
423  MRPT_START
424 
425  CEnhancedMetaFile emf(fileName, 1);
426  CImage img1, img2;
427  TColor lineColor;
428  unsigned int i, Ay1, Ay2;
429  unsigned int px, py;
430 
431  lineColor = TColor::red();
432 
433 // The individual maps:
434 // ---------------------------------------------
435 #ifdef _WIN32
436  m1->getAsImage(img1, true);
437  m2->getAsImage(img2, true);
438 #else
439  m1->getAsImage(img1, false); // Linux: emulated EMF is different.
440  m2->getAsImage(img2, false);
441 #endif
442  unsigned int lx1 = img1.getWidth();
443  unsigned int ly1 = img1.getHeight();
444  // unsigned int lx2 = img2.getWidth();
445  unsigned int ly2 = img2.getHeight();
446 
447  // The map with the lowest height has to be vertically aligned:
448  if (ly1 > ly2)
449  {
450  Ay1 = 0;
451  Ay2 = (ly1 - ly2) / 2;
452  }
453  else
454  {
455  Ay2 = 0;
456  Ay1 = (ly2 - ly1) / 2;
457  }
458 
459  // Draw the pair of maps:
460  // ---------------------------------------------
461  emf.drawImage(0, Ay1, img1);
462  emf.drawImage(lx1 + 1, Ay2, img2);
463 
464  // Draw the features:
465  // ---------------------------------------------
466  const unsigned int n = corrs.size();
467  lineColor = TColor::black();
468  for (i = 0; i < n; i++)
469  {
470  // In M1:
471  px = m1->x2idx(corrs[i].this_x);
472  py = Ay1 + ly1 - 1 - m1->y2idx(corrs[i].this_y);
473  emf.rectangle(px - 10, py - 10, px + 10, py + 10, lineColor);
474  emf.rectangle(px - 11, py - 11, px + 11, py + 11, lineColor);
475 
476  // In M2:
477  px = lx1 + 1 + m2->x2idx(corrs[i].other_x);
478  py = Ay2 + ly2 - 1 - m2->y2idx(corrs[i].other_y);
479  emf.rectangle(px - 10, py - 10, px + 10, py + 10, lineColor);
480  emf.rectangle(px - 11, py - 11, px + 11, py + 11, lineColor);
481  }
482 
483  /** /
484  // Draw the correspondences as lines:
485  // ---------------------------------------------
486  for (i=0;i<n;i++)
487  {
488  lineColor =
489  ((unsigned long)RandomUni(0,255.0f)) +
490  (((unsigned long)RandomUni(0,255.0f)) << 8 ) +
491  (((unsigned long)RandomUni(0,255.0f)) << 16 );
492 
493  emf.line(
494  m1->x2idx( corrs[i].this_x ),
495  Ay1+ly1-1- m1->y2idx( corrs[i].this_y ),
496  lx1+1+ m2->x2idx( corrs[i].other_x ),
497  Ay2+ly2-1-m2->y2idx( corrs[i].other_y ),
498  lineColor);
499  } // i
500  / **/
501 
502  // Draw the correspondences as text labels:
503  // ---------------------------------------------
504  char str[100];
505  for (i = 0; i < n; i++)
506  {
507  os::sprintf(str, 100, "%i", i);
508 
509  emf.textOut(
510  m1->x2idx(corrs[i].this_x) - 10,
511  Ay1 + ly1 - 1 - m1->y2idx(corrs[i].this_y) - 25, str,
512  TColor::black());
513 
514  emf.textOut(
515  lx1 + 1 + m2->x2idx(corrs[i].other_x) - 10,
516  Ay2 + ly2 - 1 - m2->y2idx(corrs[i].other_y) - 25, str,
517  TColor::black());
518  } // i
519 
520  return true;
521 
522  MRPT_END
523 }
524 
526  const std::string& filNamePrefix) const
527 {
528  std::string fil(filNamePrefix + std::string(".png"));
529  saveAsBitmapFile(fil);
530 
531  fil = filNamePrefix + std::string("_limits.txt");
532  CMatrixF LIMITS(1, 4);
533  LIMITS(0, 0) = x_min;
534  LIMITS(0, 1) = x_max;
535  LIMITS(0, 2) = y_min;
536  LIMITS(0, 3) = y_max;
537  LIMITS.saveToTextFile(
538  fil, MATRIX_FORMAT_FIXED, false /* add mrpt header */,
539  "% Grid limits: [x_min x_max y_min y_max]\n");
540 }
A namespace of pseudo-random numbers generators of diferent distributions.
This class represents a Windows Enhanced Meta File (EMF) for generating and saving graphics...
#define MRPT_START
Definition: exceptions.h:241
void saveMetricMapRepresentationToFile(const std::string &filNamePrefix) const override
This virtual method saves the map to a file "filNamePrefix"+< some_file_extension >...
OccGridCellTraits::cellTypeUnsigned cellTypeUnsigned
TLikelihoodMethod
The type for selecting a likelihood computation method.
GLenum GLsizei n
Definition: glext.h:5136
size_t getHeight() const override
Returns the height of the image in pixels.
Definition: CImage.cpp:878
bool loadFromBitmapFile(const std::string &file, float resolution, const mrpt::math::TPoint2D &origin=mrpt::math::TPoint2D(std::numeric_limits< double >::max(), std::numeric_limits< double >::max()))
Load the gridmap from a image in a file (the format can be any supported by CImage::loadFromFile).
STL namespace.
static bool saveAsEMFTwoMapsWithCorrespondences(const std::string &fileName, const COccupancyGridMap2D *m1, const COccupancyGridMap2D *m2, const mrpt::tfest::TMatchingPairList &corrs)
Saves a composite image with two gridmaps and numbers for the correspondences between them...
float getAsFloat(unsigned int col, unsigned int row, unsigned int channel) const
Returns the contents of a given pixel at the desired channel, in float format: [0,255]->[0,1] The coordinate origin is pixel(0,0)=top-left corner of the image.
Definition: CImage.cpp:922
void saveToTextFile(const std::string &file, mrpt::math::TMatrixTextFileFormat fileFormat=mrpt::math::MATRIX_FORMAT_ENG, bool appendMRPTHeader=false, const std::string &userHeader=std::string()) const
Saves the vector/matrix to a file compatible with MATLAB/Octave text format.
static bool saveAsBitmapTwoMapsWithCorrespondences(const std::string &fileName, const COccupancyGridMap2D *m1, const COccupancyGridMap2D *m2, const mrpt::tfest::TMatchingPairList &corrs)
Saves a composite image with two gridmaps and lines representing a set of correspondences between the...
void serializeFrom(mrpt::serialization::CArchive &in, uint8_t serial_version) override
Pure virtual method for reading (deserializing) from an abstract archive.
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
Definition: exceptions.h:97
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
void serializeTo(mrpt::serialization::CArchive &out) const override
Pure virtual method for writing (serializing) to an abstract archive.
bool saveAsBitmapFile(const std::string &file) const
Saves the gridmap as a graphical file (BMP,PNG,...).
This base provides a set of functions for maths stuff.
size_t getWidth() const override
Returns the width of the image in pixels.
Definition: CImage.cpp:847
GLint GLvoid * img
Definition: glext.h:3769
A list of TMatchingPair.
Definition: TMatchingPair.h:70
This namespace contains representation of robot actions and observations.
__int32 int32_t
Definition: glext.h:3455
bool loadFromBitmap(const mrpt::img::CImage &img, float resolution, const mrpt::math::TPoint2D &origin=mrpt::math::TPoint2D(std::numeric_limits< double >::max(), std::numeric_limits< double >::max()))
Load the gridmap from a image in a file (the format can be any supported by CImage::loadFromFile).
GLsizei const GLchar ** string
Definition: glext.h:4116
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
fixed floating point &#39;f&#39;
A class for storing an occupancy grid map.
void getAsImage(mrpt::img::CImage &img, bool verticalFlip=false, bool forceRGB=false, bool tricolor=false) const
Returns the grid as a 8-bit graylevel image, where each pixel is a cell (output image is RGB only if ...
This class is a "CSerializable" wrapper for "CMatrixFloat".
Definition: CMatrixF.h:22
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:54
mrpt::vision::TStereoCalibResults out
#define MRPT_END
Definition: exceptions.h:245
GLuint in
Definition: glext.h:7391
OccGridCellTraits::cellType cellType
The type of the map cells:
GLenum GLint GLint y
Definition: glext.h:3542
GLuint res
Definition: glext.h:7385
A RGB color - 8bit.
Definition: TColor.h:20
GLenum GLint x
Definition: glext.h:3542
uint8_t serializeGetVersion() const override
Must return the current versioning number of the object.
CRandomGenerator & getRandomGenerator()
A static instance of a CRandomGenerator class, for use in single-thread applications.
Lightweight 2D point.
Definition: TPoint2D.h:31
Functions for estimating the optimal transformation between two frames of references given measuremen...
GLfloat GLfloat p
Definition: glext.h:6398
int x2idx(float x) const
Transform a coordinate value into a cell index.
int sprintf(char *buf, size_t bufSize, const char *format,...) noexcept MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
Definition: os.cpp:191
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:147



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: cfb2df9d3 Fri Nov 15 06:57:14 2019 +0100 at vie nov 15 07:00:11 CET 2019