Main MRPT website > C++ reference for MRPT 1.9.9
CImage.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "base-precomp.h" // Precompiled headers
11 
12 #include <mrpt/utils/CImage.h>
16 #include <mrpt/compress/zip.h>
17 #include <mrpt/math/CMatrix.h>
18 #include <mrpt/math/fourier.h>
19 #include <mrpt/math/utils.h> // for roundup()
20 #include <mrpt/utils/round.h> // for round()
21 #include <mrpt/utils/CTicTac.h>
22 #include <mrpt/utils/CTimeLogger.h>
23 #include <mrpt/system/memory.h>
24 #include <mrpt/system/filesystem.h>
25 
26 // Universal include for all versions of OpenCV
27 #include <mrpt/otherlibs/do_opencv_includes.h>
28 
29 #if MRPT_HAS_MATLAB
30 #include <mexplus/mxarray.h>
31 #endif
32 
33 // Prototypes of SSE2/SSE3/SSSE3 optimized functions:
34 #include "CImage_SSEx.h"
35 
36 #if MRPT_HAS_WXWIDGETS
37 #include <wx/image.h>
38 #endif
39 
40 using namespace mrpt;
41 using namespace mrpt::utils;
42 using namespace mrpt::math;
43 using namespace mrpt::system;
44 using namespace std;
45 
46 // This must be added to any CSerializable class implementation file.
48 
52 
53 static std::string IMAGES_PATH_BASE(".");
54 
56 {
57  return IMAGES_PATH_BASE;
58 }
60 {
61  IMAGES_PATH_BASE = path;
62 }
63 
64 // Do performance time logging?
65 #define IMAGE_ALLOC_PERFLOG 0
66 
67 #if IMAGE_ALLOC_PERFLOG
68 mrpt::utils::CTimeLogger alloc_tims;
69 #endif
70 
71 /*---------------------------------------------------------------
72  Constructor
73  ---------------------------------------------------------------*/
75  unsigned int width, unsigned int height, TImageChannels nChannels,
76  bool originTopLeft)
77  : img(nullptr), m_imgIsReadOnly(false), m_imgIsExternalStorage(false)
78 {
80  changeSize(width, height, nChannels, originTopLeft);
81  MRPT_END
82 }
83 /*---------------------------------------------------------------
84  Default Constructor
85  ---------------------------------------------------------------*/
87  : img(nullptr), m_imgIsReadOnly(false), m_imgIsExternalStorage(false)
88 {
89 #if MRPT_HAS_OPENCV
91  changeSize(1, 1, CH_RGB, true);
92  MRPT_END
93 #endif
94 }
95 
96 /*---------------------------------------------------------------
97  Copy constructor
98  ---------------------------------------------------------------*/
100  : img(nullptr), m_imgIsReadOnly(false), m_imgIsExternalStorage(false)
101 {
102  MRPT_START
103  *this = o;
104  MRPT_END
105 }
106 
107 /*---------------------------------------------------------------
108  Copy operator
109  ---------------------------------------------------------------*/
111 {
112  MRPT_START
113  if (this == &o) return *this;
114  releaseIpl();
116  m_imgIsReadOnly = false;
117 
118  if (!o.m_imgIsExternalStorage)
119  { // A normal image
120 #if MRPT_HAS_OPENCV
121  ASSERTMSG_(
122  o.img != nullptr,
123  "Source image in = operator has nullptr IplImage*")
124  img = cvCloneImage((IplImage*)o.img);
125 #endif
126  }
127  else
128  { // An externally stored image:
130  }
131  return *this;
132  MRPT_END
133 }
134 
135 /*---------------------------------------------------------------
136  swap
137  ---------------------------------------------------------------*/
139 {
140  std::swap(img, o.img);
141  std::swap(m_imgIsReadOnly, o.m_imgIsReadOnly);
143  std::swap(m_externalFile, o.m_externalFile);
144 }
145 
146 /*---------------------------------------------------------------
147  copyFromForceLoad
148 
149  Copies from another image, and, if that one is externally
150  stored, the image file will be actually loaded into memory
151  in "this" object.
152  ---------------------------------------------------------------*/
154 {
155  if (o.isExternallyStored())
156  {
157  // Load from that file:
161  "Error loading externally-stored image from: %s",
163  }
164  else
165  { // It's not external storage.
166  *this = o;
167  }
168 }
169 
170 /*---------------------------------------------------------------
171  copyFastFrom
172  ---------------------------------------------------------------*/
174 {
175  MRPT_START
176  if (this == &o) return;
178  {
179  // Just copy the reference to the ext. file:
180  *this = o;
181  }
182  else
183  { // Normal copy
184 #if MRPT_HAS_OPENCV
185  if (!o.img) THROW_EXCEPTION("Origin image is empty! (o.img==nullptr)")
186 #endif
187  // Erase current image:
188  releaseIpl();
189 
190  // Make the transfer of just the pointer:
191  img = o.img;
195 
196  o.img = nullptr;
197  o.m_imgIsReadOnly = false;
198  o.m_imgIsExternalStorage = false;
199  }
200 
201  MRPT_END
202 }
203 
204 /*---------------------------------------------------------------
205  Constructor from IplImage
206  ---------------------------------------------------------------*/
207 CImage::CImage(void* iplImage)
208  : img(nullptr), m_imgIsReadOnly(false), m_imgIsExternalStorage(false)
209 {
210  MRPT_START
211 
212 #if MRPT_HAS_OPENCV
213  if (!iplImage)
214  changeSize(1, 1, 1, true);
215  else
216  img = cvCloneImage((IplImage*)iplImage);
217 #endif
218  MRPT_END
219 }
220 
221 /*---------------------------------------------------------------
222  Destructor
223  ---------------------------------------------------------------*/
225 /*---------------------------------------------------------------
226  changeSize
227  ---------------------------------------------------------------*/
229  unsigned int width, unsigned int height, TImageChannels nChannels,
230  bool originTopLeft)
231 {
232  MRPT_START
233 
234 #if MRPT_HAS_OPENCV
235  // If we're resizing to exactly the current size, do nothing and avoid
236  // wasting mem allocs/deallocs!
237  if (img)
238  {
239  makeSureImageIsLoaded(); // For delayed loaded images stored externally
240  IplImage* ipl = static_cast<IplImage*>(img);
241  if (static_cast<unsigned int>(ipl->width) == width &&
242  static_cast<unsigned int>(ipl->height) == height &&
243  ipl->nChannels == nChannels &&
244  ipl->origin == (originTopLeft ? 0 : 1))
245  {
246  return; // nothing to do, we're already right with the current
247  // IplImage!
248  }
249  }
250 
251  // Delete current img
252  releaseIpl();
253 
254 #if IMAGE_ALLOC_PERFLOG
255  const std::string sLog = mrpt::format("cvCreateImage %ux%u", width, height);
256  alloc_tims.enter(sLog.c_str());
257 #endif
258 
259  img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, nChannels);
260  ((IplImage*)img)->origin = originTopLeft ? 0 : 1;
261 
262 #if IMAGE_ALLOC_PERFLOG
263  alloc_tims.leave(sLog.c_str());
264 #endif
265 
266 #else
267  THROW_EXCEPTION("The MRPT has been compiled with MRPT_HAS_OPENCV=0 !");
268 #endif
269 
270  MRPT_END
271 }
272 
273 /*---------------------------------------------------------------
274  loadFromFile
275  ---------------------------------------------------------------*/
276 bool CImage::loadFromFile(const std::string& fileName, int isColor)
277 {
278  MRPT_START
279 
280 #if MRPT_HAS_OPENCV
281  IplImage* newImg = cvLoadImage(fileName.c_str(), isColor);
282  if (newImg != nullptr)
283  {
284  releaseIpl();
285  img = newImg;
286  return true;
287  }
288  else
289  {
290  return false;
291  }
292 #else
293  THROW_EXCEPTION("The MRPT has been compiled with MRPT_HAS_OPENCV=0 !");
294 #endif
295  MRPT_END
296 }
297 
298 /*---------------------------------------------------------------
299  saveToFile
300  ---------------------------------------------------------------*/
301 bool CImage::saveToFile(const std::string& fileName, int jpeg_quality) const
302 {
303  MRPT_START
304 #if MRPT_HAS_OPENCV
305  makeSureImageIsLoaded(); // For delayed loaded images stored externally
306  ASSERT_(img != nullptr);
307 
308 #if MRPT_OPENCV_VERSION_NUM > 0x110
309  int p[3];
310  p[0] = CV_IMWRITE_JPEG_QUALITY;
311  p[1] = jpeg_quality;
312  p[2] = 0;
313  return (0 != cvSaveImage(fileName.c_str(), img, p));
314 #else
315  return (0 != cvSaveImage(fileName.c_str(), img));
316 #endif
317 #else
318  THROW_EXCEPTION("The MRPT has been compiled with MRPT_HAS_OPENCV=0 !");
319 #endif
320  MRPT_END
321 }
322 
323 /*---------------------------------------------------------------
324  loadFromIplImage
325  ---------------------------------------------------------------*/
326 void CImage::loadFromIplImage(void* iplImage)
327 {
328  MRPT_START
329  ASSERT_(iplImage != nullptr)
330  releaseIpl();
331  if (iplImage)
332  {
333 #if MRPT_HAS_OPENCV
334  img = cvCloneImage((IplImage*)iplImage);
335 #else
336  THROW_EXCEPTION("The MRPT has been compiled with MRPT_HAS_OPENCV=0 !");
337 #endif
338  }
339  MRPT_END
340 }
341 
342 /*---------------------------------------------------------------
343  setFromIplImageReadOnly
344  ---------------------------------------------------------------*/
346 {
347  MRPT_START
348  releaseIpl();
349 #if MRPT_HAS_OPENCV
350  ASSERT_(iplImage != nullptr)
351  ASSERTMSG_(iplImage != this->img, "Trying to assign read-only to itself.")
352 
353  img = (IplImage*)iplImage;
354 #else
355  if (iplImage)
356  {
357  THROW_EXCEPTION("The MRPT has been compiled with MRPT_HAS_OPENCV=0 !");
358  }
359 #endif
360  m_imgIsReadOnly = true;
361  m_imgIsExternalStorage = false;
362  MRPT_END
363 }
364 
365 /*---------------------------------------------------------------
366  setFromIplImage
367  ---------------------------------------------------------------*/
368 void CImage::setFromIplImage(void* iplImage)
369 {
370  MRPT_START
371 
372  releaseIpl();
373  if (iplImage)
374  {
375 #if MRPT_HAS_OPENCV
376  img = (IplImage*)iplImage;
377 #else
378  THROW_EXCEPTION("The MRPT has been compiled with MRPT_HAS_OPENCV=0 !");
379 #endif
380  }
381  m_imgIsReadOnly = false;
382  m_imgIsExternalStorage = false;
383 
384  MRPT_END
385 }
386 
387 /*---------------------------------------------------------------
388  loadFromMemoryBuffer
389  ---------------------------------------------------------------*/
391  unsigned int width, unsigned int height, bool color,
392  unsigned char* rawpixels, bool swapRedBlue)
393 {
394  MRPT_START
395 
396 #if MRPT_HAS_OPENCV
397  resize(width, height, color ? 3 : 1, true);
398  m_imgIsReadOnly = false;
399  m_imgIsExternalStorage = false;
400 
401  if (color && swapRedBlue)
402  {
403  // Do copy & swap at once:
404  unsigned char* ptr_src = rawpixels;
405  unsigned char* ptr_dest =
406  reinterpret_cast<unsigned char*>(((IplImage*)img)->imageData);
407  const int bytes_per_row_out = ((IplImage*)img)->widthStep;
408 
409  for (int h = height; h--;)
410  {
411  for (unsigned int i = 0; i < width;
412  i++, ptr_src += 3, ptr_dest += 3)
413  {
414  unsigned char t0 = ptr_src[0], t1 = ptr_src[1], t2 = ptr_src[2];
415  ptr_dest[2] = t0;
416  ptr_dest[1] = t1;
417  ptr_dest[0] = t2;
418  }
419  ptr_dest += bytes_per_row_out - width * 3;
420  }
421  }
422  else
423  {
424  if (((IplImage*)img)->widthStep ==
425  ((IplImage*)img)->width * ((IplImage*)img)->nChannels)
426  {
427  // Copy the image data:
428  memcpy(
429  ((IplImage*)img)->imageData, rawpixels,
430  ((IplImage*)img)->imageSize);
431  }
432  else
433  {
434  // Copy the image row by row:
435  unsigned char* ptr_src = rawpixels;
436  unsigned char* ptr_dest =
437  reinterpret_cast<unsigned char*>(((IplImage*)img)->imageData);
438  int bytes_per_row = width * (color ? 3 : 1);
439  int bytes_per_row_out = ((IplImage*)img)->widthStep;
440  for (unsigned int y = 0; y < height; y++)
441  {
442  memcpy(ptr_dest, ptr_src, bytes_per_row);
443  ptr_src += bytes_per_row;
444  ptr_dest += bytes_per_row_out;
445  }
446  }
447  }
448 #else
449  THROW_EXCEPTION("The MRPT has been compiled with MRPT_HAS_OPENCV=0 !");
450 #endif
451  MRPT_END
452 }
453 
454 /*---------------------------------------------------------------
455  operator()
456  ---------------------------------------------------------------*/
457 unsigned char* CImage::operator()(
458  unsigned int col, unsigned int row, unsigned int channel) const
459 {
460 #if MRPT_HAS_OPENCV
461 
462 #if defined(_DEBUG) || (MRPT_ALWAYS_CHECKS_DEBUG)
463  MRPT_START
464 #endif
465 
466  makeSureImageIsLoaded(); // For delayed loaded images stored externally
467  IplImage* ipl = ((IplImage*)img);
468 
469 #if defined(_DEBUG) || (MRPT_ALWAYS_CHECKS_DEBUG)
470  ASSERT_(ipl);
471  if (row >= (unsigned int)ipl->height || col >= (unsigned int)ipl->width ||
472  channel >= (unsigned int)ipl->nChannels)
473  {
475  format(
476  "Pixel coordinates/channel out of bounds: row=%u/%u col=%u/%u "
477  "chan=%u/%u",
478  row, ipl->height, col, ipl->width, channel, ipl->nChannels));
479  }
480 #endif
481 
482  return (unsigned char*)&ipl
483  ->imageData[row * ipl->widthStep + col * ipl->nChannels + channel];
484 #if defined(_DEBUG) || (MRPT_ALWAYS_CHECKS_DEBUG)
485  MRPT_END
486 #endif
487 
488 #else
489  THROW_EXCEPTION("MRPT was compiled without OpenCV")
490 #endif
491 }
492 
493 /*---------------------------------------------------------------
494  get_unsafe()
495  ---------------------------------------------------------------*/
496 unsigned char* CImage::get_unsafe(
497  unsigned int col, unsigned int row, unsigned int channel) const
498 {
499 #if MRPT_HAS_OPENCV
500  makeSureImageIsLoaded(); // For delayed loaded images stored externally
501  IplImage* ipl = ((IplImage*)img);
502  return (unsigned char*)&ipl
503  ->imageData[row * ipl->widthStep + col * ipl->nChannels + channel];
504 #else
505  return nullptr;
506 #endif
507 }
508 
509 /*---------------------------------------------------------------
510  Implements the writing to a CStream capability of CSerializable objects
511  ---------------------------------------------------------------*/
512 void CImage::writeToStream(mrpt::utils::CStream& out, int* version) const
513 {
514 #if !MRPT_HAS_OPENCV
515  if (version)
516  *version = 100;
517  else
518  {
519  out << m_imgIsExternalStorage;
520 
522  // Nothing else to serialize!
523  }
524 #else
525  if (version)
526  *version = 8;
527  else
528  {
529  // Added in version 6: possibility of being stored offline:
530  out << m_imgIsExternalStorage;
531 
533  {
534  out << m_externalFile;
535  }
536  else
537  { // Normal image loaded in memory:
538  ASSERT_(img != nullptr);
539 
540  const bool hasColor = isColor();
541 
542  out << hasColor;
543 
544  // Version >2: Color->JPEG, GrayScale->BYTE's array!
545  if (!hasColor)
546  {
547  // GRAY-SCALE: Raw bytes:
548  // Version 3: ZIP compression!
549  // Version 4: Skip zip if the image size <= 16Kb
550  int32_t width = ((IplImage*)img)->width;
551  int32_t height = ((IplImage*)img)->height;
552  int32_t origin = ((IplImage*)img)->origin;
553  int32_t imageSize = ((IplImage*)img)->imageSize;
554 
555  out << width << height << origin << imageSize;
556 
557  // Version 5: Use CImage::DISABLE_ZIP_COMPRESSION
558  bool imageStoredAsZip =
559  !CImage::DISABLE_ZIP_COMPRESSION && (imageSize > 16 * 1024);
560 
561  out << imageStoredAsZip;
562 
563  // Version 4: Skip zip if the image size <= 16Kb
564  if (imageStoredAsZip)
565  {
566  std::vector<unsigned char> tempBuf;
568  ((IplImage*)img)->imageData, // Data
569  ((IplImage*)img)->imageSize, // Size
570  tempBuf);
571 
572  int32_t zipDataLen = (int32_t)tempBuf.size();
573 
574  out << zipDataLen;
575 
576  out.WriteBuffer(&tempBuf[0], tempBuf.size());
577  tempBuf.clear();
578  }
579  else
580  {
581  out.WriteBuffer(
582  ((IplImage*)img)->imageData,
583  ((IplImage*)img)->imageSize);
584  }
585  }
586  else
587  {
588  // COLOR: High quality JPEG image
589 
590  // v7: If size is 0xN or Nx0, don't call "saveToStreamAsJPEG"!!
591  const int32_t width = ((IplImage*)img)->width;
592  const int32_t height = ((IplImage*)img)->height;
593 
594  // v8: If DISABLE_JPEG_COMPRESSION
596  {
597  // normal behavior: compress images:
598  out << width << height;
599 
600  if (width >= 1 && height >= 1)
601  {
602  // Save to temporary memory stream:
603  CMemoryStream aux;
606 
607  const uint32_t nBytes =
608  static_cast<uint32_t>(aux.getTotalBytesCount());
609 
610  out << nBytes;
611  out.WriteBuffer(aux.getRawBufferData(), nBytes);
612  }
613  }
614  else
615  { // (New in v8)
616  // Don't JPEG-compress behavior:
617  // Use negative image sizes to signal this behavior:
618  const int32_t neg_width = -width;
619  const int32_t neg_height = -height;
620 
621  out << neg_width << neg_height;
622 
623  // Dump raw image data:
624  const IplImage* ipl = static_cast<const IplImage*>(img);
625  const size_t bytes_per_row = ipl->width * 3;
626 
627  out.WriteBuffer(
628  &ipl->imageData[0], bytes_per_row * ipl->height);
629  }
630  }
631  } // end m_imgIsExternalStorage=false
632  }
633 #endif
634 }
635 
636 /*---------------------------------------------------------------
637  Implements the reading from a CStream capability of CSerializable objects
638  ---------------------------------------------------------------*/
640 {
641 #if !MRPT_HAS_OPENCV
642  if (version == 100)
643  {
646  in >> m_externalFile;
647  else
648  {
650  "[CImage] Cannot deserialize image since MRPT has been "
651  "compiled without OpenCV")
652  }
653  }
654 #else
655  releaseIpl(); // First, free current image.
656 
657  switch (version)
658  {
659  case 100: // Saved from an MRPT build without OpenCV:
660  {
663  }
664  break;
665  case 0:
666  {
667  uint32_t width, height, nChannels, imgLength;
668  uint8_t originTopLeft;
669 
670  in >> width >> height >> nChannels >> originTopLeft >> imgLength;
671 
672  changeSize(width, height, nChannels, originTopLeft != 0);
673  in.ReadBuffer(((IplImage*)img)->imageData, imgLength);
674  }
675  break;
676  case 1:
677  {
678  // Version 1: High quality JPEG image
679  CMemoryStream aux;
680  uint32_t nBytes;
681  in >> nBytes;
682 
683  aux.changeSize(nBytes + 10);
684 
685  in.ReadBuffer(aux.getRawBufferData(), nBytes);
686 
687  aux.Seek(0);
688 
690  }
691  break;
692  case 2:
693  case 3:
694  case 4:
695  case 5:
696  case 6:
697  case 7:
698  case 8:
699  {
700  // Version 6: m_imgIsExternalStorage ??
701  if (version >= 6)
703  else
704  m_imgIsExternalStorage = false;
705 
707  {
708  // Just the file name:
709  in >> m_externalFile;
710  }
711  else
712  { // Normal, the whole image data:
713 
714  // Version 2: Color->JPEG, GrayScale->BYTE's array!
715  uint8_t hasColor;
716  in >> hasColor;
717  if (!hasColor)
718  {
719  // GRAY SCALE:
720  int32_t width, height, origin, imageSize;
721  in >> width >> height >> origin >> imageSize;
722 
723  changeSize(width, height, 1, origin == 0);
724  ASSERT_(imageSize == ((IplImage*)img)->imageSize);
725 
726  if (version == 2)
727  {
728  // RAW BYTES:
729  in.ReadBuffer(((IplImage*)img)->imageData, imageSize);
730  }
731  else
732  {
733  // Version 3: ZIP compression!
734  bool imageIsZIP = true;
735 
736  // Version 4: Skip zip if the image size <= 16Kb
737  // Version 5: Use CImage::DISABLE_ZIP_COMPRESSION
738  if (version == 4 && imageSize <= 16 * 1024)
739  imageIsZIP = false;
740 
741  if (version >= 5)
742  {
743  // It is stored int the stream:
744  in >> imageIsZIP;
745  }
746 
747  if (imageIsZIP)
748  {
749  uint32_t zipDataLen;
750  in >> zipDataLen;
751 
752  size_t outDataBufferSize = imageSize;
753  size_t outDataActualSize;
754 
756  in, zipDataLen, ((IplImage*)img)->imageData,
757  outDataBufferSize, outDataActualSize);
758 
759  ASSERT_(outDataActualSize == outDataBufferSize);
760  }
761  else
762  {
763  // Raw bytes:
764  in.ReadBuffer(
765  ((IplImage*)img)->imageData,
766  ((IplImage*)img)->imageSize);
767  }
768  }
769  }
770  else
771  {
772  bool loadJPEG = true;
773 
774  if (version >= 7)
775  {
777  in >> width >> height;
778 
779  if (width >= 1 && height >= 1)
780  {
781  loadJPEG = true;
782  }
783  else
784  {
785  loadJPEG = false;
786 
787  if (width < 0 && height < 0)
788  {
789  // v8: raw image:
790  const int32_t real_w = -width;
791  const int32_t real_h = -height;
792 
793  this->changeSize(real_w, real_h, 3, true);
794 
795  const IplImage* ipl =
796  static_cast<const IplImage*>(img);
797  const size_t bytes_per_row = ipl->width * 3;
798  for (int y = 0; y < ipl->height; y++)
799  {
800  const size_t nRead = in.ReadBuffer(
801  &ipl->imageData[y * ipl->widthStep],
802  bytes_per_row);
803  if (nRead != bytes_per_row)
805  "Error: Truncated data stream "
806  "while parsing raw image?")
807  }
808  }
809  else
810  {
811  // it's a 0xN or Nx0 image: just resize and load
812  // nothing:
813  this->changeSize(width, height, 3, true);
814  }
815  }
816  }
817 
818  // COLOR IMAGE: JPEG
819  if (loadJPEG)
820  {
821  CMemoryStream aux;
822  uint32_t nBytes;
823  in >> nBytes;
824  aux.changeSize(nBytes + 10);
825  in.ReadBuffer(aux.getRawBufferData(), nBytes);
826  aux.Seek(0);
828  }
829  }
830  }
831  }
832  break;
833  default:
835  };
836 #endif
837 }
838 
839 /*---------------------------------------------------------------
840  Implements the writing to a mxArray for Matlab
841  ---------------------------------------------------------------*/
842 #if MRPT_HAS_MATLAB
843 // Add to implement mexplus::from template specialization
845 
847 {
848  cv::Mat cvImg = cv::cvarrToMat(this->getAs<IplImage>());
849  return mexplus::from(cvImg);
850 }
851 #endif
852 
853 /*---------------------------------------------------------------
854  getSize
855  ---------------------------------------------------------------*/
857 {
858 #if MRPT_HAS_OPENCV
859  makeSureImageIsLoaded(); // For delayed loaded images stored externally
860  ASSERT_(img != nullptr);
861  s.x = ((IplImage*)img)->width;
862  s.y = ((IplImage*)img)->height;
863 #endif
864 }
865 
866 /*---------------------------------------------------------------
867  getWidth
868  ---------------------------------------------------------------*/
869 size_t CImage::getWidth() const
870 {
871 #if MRPT_HAS_OPENCV
872  makeSureImageIsLoaded(); // For delayed loaded images stored externally
873  ASSERT_(img != nullptr);
874  return ((IplImage*)img)->width;
875 #else
876  return 0;
877 #endif
878 }
879 
880 /*---------------------------------------------------------------
881  getRowStride
882  ---------------------------------------------------------------*/
883 size_t CImage::getRowStride() const
884 {
885 #if MRPT_HAS_OPENCV
886  makeSureImageIsLoaded(); // For delayed loaded images stored externally
887  ASSERT_(img != nullptr);
888  return ((IplImage*)img)->widthStep;
889 #else
890  return 0;
891 #endif
892 }
893 
894 /*---------------------------------------------------------------
895  getWidth
896  ---------------------------------------------------------------*/
897 size_t CImage::getHeight() const
898 {
899 #if MRPT_HAS_OPENCV
900  makeSureImageIsLoaded(); // For delayed loaded images stored externally
901  ASSERT_(img != nullptr);
902  return ((IplImage*)img)->height;
903 #else
904  return 0;
905 #endif
906 }
907 
908 /*---------------------------------------------------------------
909  isColor
910  ---------------------------------------------------------------*/
911 bool CImage::isColor() const
912 {
913 #if MRPT_HAS_OPENCV
914  makeSureImageIsLoaded(); // For delayed loaded images stored externally
915  ASSERT_(img != nullptr);
916  return ((IplImage*)img)->nChannels > 1;
917 #else
918  return false;
919 #endif
920 }
921 
922 /*---------------------------------------------------------------
923  getChannelCount
924  ---------------------------------------------------------------*/
926 {
927 #if MRPT_HAS_OPENCV
928  makeSureImageIsLoaded(); // For delayed loaded images stored externally
929  ASSERT_(img != nullptr);
930  return static_cast<unsigned int>(((IplImage*)img)->nChannels);
931 #else
932  return 0;
933 #endif
934 }
935 
936 /*---------------------------------------------------------------
937  isOriginTopLeft
938  ---------------------------------------------------------------*/
940 {
941 #if MRPT_HAS_OPENCV
942  makeSureImageIsLoaded(); // For delayed loaded images stored externally
943  ASSERT_(img != nullptr);
944  return ((IplImage*)img)->origin == 0;
945 #else
946  THROW_EXCEPTION("MRPT compiled without OpenCV")
947 #endif
948 }
949 
950 /*---------------------------------------------------------------
951  getAsFloat
952  ---------------------------------------------------------------*/
954  unsigned int col, unsigned int row, unsigned int channel) const
955 {
956  makeSureImageIsLoaded(); // For delayed loaded images stored externally
957  // [0,255]->[0,1]
958  return (*(*this)(col, row, channel)) / 255.0f;
959 }
960 
961 /*---------------------------------------------------------------
962  getAsFloat
963  ---------------------------------------------------------------*/
964 float CImage::getAsFloat(unsigned int col, unsigned int row) const
965 {
966  // Is a RGB image??
967  if (isColor())
968  {
969  // Luminance: Y = 0.3R + 0.59G + 0.11B
970  unsigned char* pixels = (*this)(col, row, 0);
971  return (pixels[0] * 0.3f + pixels[1] * 0.59f + pixels[2] * 0.11f) /
972  255.0f;
973  }
974  else
975  {
976  // [0,255]->[0,1]
977  return (*(*this)(col, row, 0 /* Channel 0:Gray level */)) / 255.0f;
978  }
979 }
980 
981 /*---------------------------------------------------------------
982  getMaxAsFloat
983  ---------------------------------------------------------------*/
985 {
986  int x, y, cx = getWidth(), cy = getHeight();
987 
988  float maxPixel = 0;
989 
990  for (x = 0; x < cx; x++)
991  for (y = 0; y < cy; y++) maxPixel = max(maxPixel, getAsFloat(x, y));
992 
993  return maxPixel;
994 }
995 
996 /*---------------------------------------------------------------
997  grayscale
998  ---------------------------------------------------------------*/
1000 {
1001  CImage ret;
1002  grayscale(ret);
1003  return ret;
1004 }
1005 
1006 // Auxiliary function for both ::grayscale() and ::grayscaleInPlace()
1007 #if MRPT_HAS_OPENCV
1008 IplImage* ipl_to_grayscale(const IplImage* img_src)
1009 {
1010  IplImage* img_dest =
1011  cvCreateImage(cvSize(img_src->width, img_src->height), IPL_DEPTH_8U, 1);
1012  img_dest->origin = img_src->origin;
1013 
1014 // If possible, use SSE optimized version:
1015 #if MRPT_HAS_SSE3
1016  if (is_aligned<16>(img_src->imageData) && (img_src->width & 0xF) == 0 &&
1017  img_src->widthStep == img_src->width * img_src->nChannels &&
1018  img_dest->widthStep == img_dest->width * img_dest->nChannels)
1019  {
1020  ASSERT_(is_aligned<16>(img_dest->imageData))
1022  (const uint8_t*)img_src->imageData, (uint8_t*)img_dest->imageData,
1023  img_src->width, img_src->height);
1024  return img_dest;
1025  }
1026 #endif
1027 
1028  // OpenCV Method:
1029  cvCvtColor(img_src, img_dest, CV_BGR2GRAY);
1030  return img_dest;
1031 }
1032 #endif
1033 
1034 /*---------------------------------------------------------------
1035  grayscale
1036  ---------------------------------------------------------------*/
1037 void CImage::grayscale(CImage& ret) const
1038 {
1039 #if MRPT_HAS_OPENCV
1040  // The image is already grayscale??
1041  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1042  const IplImage* ipl = this->getAs<const IplImage>();
1043  ASSERT_(ipl)
1044 
1045  if (ipl->nChannels == 1)
1046  {
1047  ret = *this;
1048  return;
1049  }
1050  else
1051  {
1052  // Convert to a single luminance channel image
1054  }
1055 #endif
1056 }
1057 
1058 /*---------------------------------------------------------------
1059  grayscaleInPlace
1060  ---------------------------------------------------------------*/
1062 {
1063 #if MRPT_HAS_OPENCV
1064  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1065  const IplImage* ipl = this->getAs<const IplImage>();
1066  ASSERT_(ipl)
1067  if (ipl->nChannels == 1) return; // Already done.
1068 
1070 #endif
1071 }
1072 
1073 /*---------------------------------------------------------------
1074  scaleHalf
1075  ---------------------------------------------------------------*/
1076 void CImage::scaleHalf(CImage& out) const
1077 {
1078 #if MRPT_HAS_OPENCV
1079  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1080  ASSERT_(img != nullptr)
1081 
1082  // Get this image size:
1083  const IplImage* img_src = ((IplImage*)img);
1084  const int w = img_src->width;
1085  const int h = img_src->height;
1086 
1087  // Create target image:
1088  IplImage* img_dest =
1089  cvCreateImage(cvSize(w >> 1, h >> 1), IPL_DEPTH_8U, img_src->nChannels);
1090  img_dest->origin = img_src->origin;
1091  memcpy(img_dest->colorModel, img_src->colorModel, 4);
1092  memcpy(img_dest->channelSeq, img_src->channelSeq, 4);
1093  img_dest->dataOrder = img_src->dataOrder;
1094 
1095 // If possible, use SSE optimized version:
1096 #if MRPT_HAS_SSE3
1097  if (img_src->nChannels == 3 && is_aligned<16>(img_src->imageData) &&
1098  is_aligned<16>(img_dest->imageData) && (w & 0xF) == 0 &&
1099  img_src->widthStep == img_src->width * img_src->nChannels &&
1100  img_dest->widthStep == img_dest->width * img_dest->nChannels)
1101  {
1103  (const uint8_t*)img_src->imageData, (uint8_t*)img_dest->imageData,
1104  w, h);
1105  out.setFromIplImage(img_dest);
1106  return;
1107  }
1108 #endif
1109 
1110 #if MRPT_HAS_SSE2
1111  if (img_src->nChannels == 1 && is_aligned<16>(img_src->imageData) &&
1112  is_aligned<16>(img_dest->imageData) && (w & 0xF) == 0 &&
1113  img_src->widthStep == img_src->width * img_src->nChannels &&
1114  img_dest->widthStep == img_dest->width * img_dest->nChannels)
1115  {
1117  (const uint8_t*)img_src->imageData, (uint8_t*)img_dest->imageData,
1118  w, h);
1119 
1120  out.setFromIplImage(img_dest);
1121  return;
1122  }
1123 #endif
1124 
1125  // Fall back to slow method:
1126  cvResize(img_src, img_dest, IMG_INTERP_NN);
1127  out.setFromIplImage(img_dest);
1128 #endif
1129 }
1130 
1131 /*---------------------------------------------------------------
1132  scaleHalfSmooth
1133  ---------------------------------------------------------------*/
1135 {
1136 #if MRPT_HAS_OPENCV
1137  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1138  ASSERT_(img != nullptr)
1139 
1140  // Get this image size:
1141  const IplImage* img_src = ((IplImage*)img);
1142  const int w = img_src->width;
1143  const int h = img_src->height;
1144 
1145  // Create target image:
1146  IplImage* img_dest =
1147  cvCreateImage(cvSize(w >> 1, h >> 1), IPL_DEPTH_8U, img_src->nChannels);
1148  img_dest->origin = img_src->origin;
1149  memcpy(img_dest->colorModel, img_src->colorModel, 4);
1150  memcpy(img_dest->channelSeq, img_src->channelSeq, 4);
1151  img_dest->dataOrder = img_src->dataOrder;
1152 
1153 // If possible, use SSE optimized version:
1154 #if MRPT_HAS_SSE2
1155  if (img_src->nChannels == 1 && is_aligned<16>(img_src->imageData) &&
1156  is_aligned<16>(img_dest->imageData) && (w & 0xF) == 0 &&
1157  img_src->widthStep == img_src->width * img_src->nChannels &&
1158  img_dest->widthStep == img_dest->width * img_dest->nChannels)
1159  {
1161  (const uint8_t*)img_src->imageData, (uint8_t*)img_dest->imageData,
1162  w, h);
1163 
1164  out.setFromIplImage(img_dest);
1165  return;
1166  }
1167 #endif
1168 
1169  // Fall back to slow method:
1170  cvResize(img_src, img_dest, IMG_INTERP_LINEAR);
1171  out.setFromIplImage(img_dest);
1172 #endif
1173 }
1174 
1175 /*---------------------------------------------------------------
1176  scaleDouble
1177  ---------------------------------------------------------------*/
1178 void CImage::scaleDouble(CImage& out) const
1179 {
1180  out = *this;
1181  const TImageSize siz = this->getSize();
1182  out.scaleImage(siz.x * 2, siz.y * 2);
1183 }
1184 
1185 /*---------------------------------------------------------------
1186  getChannelsOrder
1187  ---------------------------------------------------------------*/
1188 const char* CImage::getChannelsOrder() const
1189 {
1190 #if MRPT_HAS_OPENCV
1191  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1192  ASSERT_(img);
1193  return ((IplImage*)img)->channelSeq;
1194 #else
1195  THROW_EXCEPTION("MRPT compiled without OpenCV")
1196 #endif
1197 }
1198 
1199 /*---------------------------------------------------------------
1200  loadFromMemoryBuffer
1201  ---------------------------------------------------------------*/
1203  unsigned int width, unsigned int height, unsigned int bytesPerRow,
1204  unsigned char* red, unsigned char* green, unsigned char* blue)
1205 {
1206 #if MRPT_HAS_OPENCV
1207  MRPT_START
1208 
1209  // Fill in the IPL structure:
1210  changeSize(width, height, 3, true);
1211 
1212  // Copy the image data:
1213  for (unsigned int y = 0; y < height; y++)
1214  {
1215  // The target pixels:
1216  unsigned char* dest = (unsigned char*)((IplImage*)img)->imageData +
1217  ((IplImage*)img)->widthStep * y;
1218 
1219  // Source channels:
1220  unsigned char* srcR = red + bytesPerRow * y;
1221  unsigned char* srcG = green + bytesPerRow * y;
1222  unsigned char* srcB = blue + bytesPerRow * y;
1223 
1224  for (unsigned int x = 0; x < width; x++)
1225  {
1226  *(dest++) = *(srcB++);
1227  *(dest++) = *(srcG++);
1228  *(dest++) = *(srcR++);
1229  } // end of x
1230  } // end of y
1231 
1232  MRPT_END
1233 #endif
1234 }
1235 
1236 /*---------------------------------------------------------------
1237  setOriginTopLeft
1238  ---------------------------------------------------------------*/
1240 {
1241 #if MRPT_HAS_OPENCV
1242  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1243  ASSERT_(img);
1244  ((IplImage*)img)->origin = val ? 0 : 1;
1245 #endif
1246 }
1247 
1248 /*---------------------------------------------------------------
1249  setPixel
1250  ---------------------------------------------------------------*/
1251 void CImage::setPixel(int x, int y, size_t color)
1252 {
1253 #if MRPT_HAS_OPENCV
1254 
1255 #if defined(_DEBUG) || (MRPT_ALWAYS_CHECKS_DEBUG)
1256  MRPT_START
1257 #endif
1258 
1259  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1260 
1261  IplImage* ipl = ((IplImage*)img);
1262 
1263 #if defined(_DEBUG) || (MRPT_ALWAYS_CHECKS_DEBUG)
1264  ASSERT_(ipl);
1265 #endif
1266 
1267  if (x >= 0 && y >= 0 && y < ipl->height && x < ipl->width)
1268  {
1269  // The pixel coordinates is valid:
1270  if (ipl->nChannels == 1)
1271  {
1272  *((unsigned char*)&ipl->imageData[y * ipl->widthStep + x]) =
1273  (unsigned char)color;
1274  }
1275  else
1276  {
1277 #if defined(_DEBUG) || (MRPT_ALWAYS_CHECKS_DEBUG)
1278  ASSERT_(ipl->nChannels == 3);
1279  if (ipl->dataOrder != 0)
1281  "Please, use interleaved images like normal people!!! :-)");
1282 #endif
1283  unsigned char* dest =
1284  (unsigned char*)&ipl->imageData[y * ipl->widthStep + 3 * x];
1285  unsigned char* src = (unsigned char*)&color;
1286 
1287  // Copy the color:
1288  *dest++ = *src++; // R
1289  *dest++ = *src++; // G
1290  *dest++ = *src++; // B
1291  }
1292  }
1293 
1294 #if defined(_DEBUG) || (MRPT_ALWAYS_CHECKS_DEBUG)
1295  MRPT_END
1296 #endif
1297 
1298 #endif
1299 }
1300 
1301 /*---------------------------------------------------------------
1302  line
1303  ---------------------------------------------------------------*/
1305  int x0, int y0, int x1, int y1, const mrpt::utils::TColor color,
1306  unsigned int width, TPenStyle penStyle)
1307 {
1308 #if MRPT_HAS_OPENCV
1309  MRPT_UNUSED_PARAM(penStyle);
1310  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1311  IplImage* ipl = ((IplImage*)img);
1312  ASSERT_(ipl);
1313 
1314  cvLine(
1315  ipl, cvPoint(x0, y0), cvPoint(x1, y1),
1316  CV_RGB(color.R, color.G, color.B), width);
1317 #endif
1318 }
1319 
1320 /*---------------------------------------------------------------
1321  drawCircle
1322  ---------------------------------------------------------------*/
1324  int x, int y, int radius, const mrpt::utils::TColor& color,
1325  unsigned int width)
1326 {
1327 #if MRPT_HAS_OPENCV
1328  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1329  IplImage* ipl = ((IplImage*)img);
1330  ASSERT_(ipl);
1331 
1332  cvCircle(
1333  ipl, cvPoint(x, y), radius, CV_RGB(color.R, color.G, color.B), width);
1334 #endif
1335 } // end
1336 
1337 /*---------------------------------------------------------------
1338  update_patch
1339  --------------------------------------------------------------*/
1341  const CImage& patch, const unsigned int col_, const unsigned int row_)
1342 {
1343 #if MRPT_HAS_OPENCV
1344  IplImage* ipl_int = ((IplImage*)img);
1345  IplImage* ipl_ext = ((IplImage*)patch.img);
1346  ASSERT_(ipl_int);
1347  ASSERT_(ipl_ext);
1348  // We check that patch do not jut out of the image.
1349  if (row_ + ipl_ext->height > getHeight() ||
1350  col_ + ipl_ext->width > getWidth())
1351  {
1352  THROW_EXCEPTION("Error : Patch jut out of image")
1353  }
1354  for (unsigned int i = 0; i < patch.getHeight(); i++)
1355  {
1356  memcpy(
1357  &ipl_int->imageData[(i + row_) * ipl_int->widthStep +
1358  col_ * ipl_int->nChannels],
1359  &ipl_ext->imageData[i * ipl_ext->widthStep], ipl_ext->widthStep);
1360  }
1361 #endif
1362 }
1363 
1364 /*---------------------------------------------------------------
1365  extract_patch
1366  ---------------------------------------------------------------*/
1368  CImage& patch, const unsigned int col_, const unsigned int row_,
1369  const unsigned int col_num, const unsigned int row_num) const
1370 {
1371 #if MRPT_HAS_OPENCV
1372  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1373 
1374  IplImage* ipl_int = ((IplImage*)img);
1375  ASSERT_(ipl_int);
1376 
1377  if ((ipl_int->width < (int)(col_ + col_num)) ||
1378  (ipl_int->height < (int)(row_ + row_num)))
1379  {
1381  format(
1382  "Trying to extract patch out of image boundaries: Image "
1383  "size=%ix%i, Patch size=%ux%u, extraction location=(%u,%u)",
1384  ipl_int->width, ipl_int->height, col_num, row_num, col_, row_))
1385  }
1386 
1387  patch.resize(col_num, row_num, ((IplImage*)img)->nChannels, true);
1388  IplImage* ipl_ext = ((IplImage*)patch.img);
1389  ASSERT_(ipl_ext);
1390 
1391  for (unsigned int i = 0; i < row_num; i++)
1392  {
1393  memcpy(
1394  &ipl_ext->imageData[i * ipl_ext->widthStep],
1395  &ipl_int->imageData[(i + row_) * ipl_int->widthStep +
1396  col_ * ipl_int->nChannels],
1397  ipl_ext->widthStep);
1398  }
1399 
1400 #endif
1401 }
1402 
1403 /*---------------------------------------------------------------
1404  correlate
1405  ---------------------------------------------------------------*/
1407  const CImage& img2, int width_init, int height_init) const
1408 {
1409 #if MRPT_HAS_OPENCV
1410  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1411 
1412  if ((img2.getWidth() + width_init > getWidth()) |
1413  (img2.getHeight() + height_init > getHeight()))
1414  THROW_EXCEPTION("Correlation Error!, image to correlate out of bounds");
1415 
1416  unsigned int i, j;
1417  float x1, x2;
1418  float syy = 0.0f, sxy = 0.0f, sxx = 0.0f, m1 = 0.0f, m2 = 0.0f,
1419  n = (float)(img2.getHeight() * img2.getWidth());
1420  // IplImage *ipl1 = (*this).img;
1421  // IplImage *ipl2 = img2.img;
1422 
1423  // find the means
1424  for (i = 0; i < img2.getHeight(); i++)
1425  {
1426  for (j = 0; j < img2.getWidth(); j++)
1427  {
1428  m1 += *(*this)(
1429  j + width_init,
1430  i + height_init); //(double)(ipl1->imageData[i*ipl1->widthStep
1431  //+ j ]);
1432  m2 += *img2(
1433  j, i); //(double)(ipl2->imageData[i*ipl2->widthStep + j ]);
1434  } //[ row * ipl->widthStep + col * ipl->nChannels + channel ];
1435  }
1436  m1 /= n;
1437  m2 /= n;
1438 
1439  for (i = 0; i < img2.getHeight(); i++)
1440  {
1441  for (j = 0; j < img2.getWidth(); j++)
1442  {
1443  x1 = *(*this)(j + width_init, i + height_init) -
1444  m1; //(double)(ipl1->imageData[i*ipl1->widthStep + j]) - m1;
1445  x2 = *img2(j, i) -
1446  m2; //(double)(ipl2->imageData[i*ipl2->widthStep + j]) - m2;
1447  sxx += x1 * x1;
1448  syy += x2 * x2;
1449  sxy += x1 * x2;
1450  }
1451  }
1452 
1453  return sxy / sqrt(sxx * syy);
1454 #else
1455  return 0;
1456 #endif
1457 }
1458 
1459 /*---------------------------------------------------------------
1460  cross_correlation
1461  ---------------------------------------------------------------*/
1463  const CImage& patch_img, size_t& x_max, size_t& y_max, double& max_val,
1464  int x_search_ini, int y_search_ini, int x_search_size, int y_search_size,
1465  CImage* out_corr_image) const
1466 {
1467  MRPT_START
1468 
1469  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1470 
1471 #if MRPT_HAS_OPENCV
1472  double mini;
1473  CvPoint min_point, max_point;
1474 
1475  bool entireImg =
1476  (x_search_ini < 0 || y_search_ini < 0 || x_search_size < 0 ||
1477  y_search_size < 0);
1478 
1479  const IplImage *im, *patch_im;
1480 
1481  if (this->isColor() && patch_img.isColor())
1482  {
1483  const IplImage* im_ = this->getAs<IplImage>();
1484  const IplImage* patch_im_ = patch_img.getAs<IplImage>();
1485 
1486  IplImage* aux = cvCreateImage(cvGetSize(im_), 8, 1);
1487  IplImage* aux2 = cvCreateImage(cvGetSize(patch_im_), 8, 1);
1488  cvCvtColor(im_, aux, CV_BGR2GRAY);
1489  cvCvtColor(patch_im_, aux2, CV_BGR2GRAY);
1490  im = aux;
1491  patch_im = aux2;
1492  }
1493  else
1494  {
1495  im = this->getAs<IplImage>();
1496  patch_im = patch_img.getAs<IplImage>();
1497  }
1498 
1499  if (entireImg)
1500  {
1501  x_search_size = im->width - patch_im->width;
1502  y_search_size = im->height - patch_im->height;
1503  }
1504 
1505  // JLBC: Perhaps is better to raise the exception always??
1506  if ((x_search_ini + x_search_size + patch_im->width - 1) > im->width)
1507  x_search_size -=
1508  (x_search_ini + x_search_size + patch_im->width - 1) - im->width;
1509 
1510  if ((y_search_ini + y_search_size + patch_im->height - 1) > im->height)
1511  y_search_size -=
1512  (y_search_ini + y_search_size + patch_im->height - 1) - im->height;
1513 
1514  ASSERT_((x_search_ini + x_search_size + patch_im->width - 1) <= im->width)
1515  ASSERT_((y_search_ini + y_search_size + patch_im->height - 1) <= im->height)
1516 
1517  IplImage* result = cvCreateImage(
1518  cvSize(x_search_size + 1, y_search_size + 1), IPL_DEPTH_32F, 1);
1519 
1520  const IplImage* ipl_ext;
1521 
1522  if (!entireImg)
1523  {
1524  IplImage* aux = cvCreateImage(
1525  cvSize(
1526  patch_im->width + x_search_size,
1527  patch_im->height + y_search_size),
1528  IPL_DEPTH_8U, 1);
1529  for (unsigned int i = 0; i < (unsigned int)y_search_size; i++)
1530  {
1531  memcpy(
1532  &aux->imageData[i * aux->widthStep],
1533  &im->imageData[(i + y_search_ini) * im->widthStep +
1534  x_search_ini * im->nChannels],
1535  aux->width * aux->nChannels); // widthStep); <-- JLBC:
1536  // widthstep SHOULD NOT be used
1537  // as the length of each row (the
1538  // last one may be shorter!!)
1539  }
1540  ipl_ext = aux;
1541  }
1542  else
1543  {
1544  ipl_ext = im;
1545  }
1546 
1547  // Compute cross correlation:
1548  cvMatchTemplate(ipl_ext, patch_im, result, CV_TM_CCORR_NORMED);
1549  // cvMatchTemplate(ipl_ext,patch_im,result,CV_TM_CCOEFF_NORMED);
1550 
1551  // Find the max point:
1552  cvMinMaxLoc(result, &mini, &max_val, &min_point, &max_point, nullptr);
1553  x_max = max_point.x + x_search_ini + (round(patch_im->width - 1) / 2);
1554  y_max = max_point.y + y_search_ini + (round(patch_im->height - 1) / 2);
1555 
1556  // Free memory:
1557  if (!entireImg)
1558  {
1559  IplImage* aux = const_cast<IplImage*>(ipl_ext);
1560  cvReleaseImage(&aux);
1561  ipl_ext = nullptr;
1562  }
1563 
1564  // Leave output image?
1565  if (out_corr_image)
1566  out_corr_image->setFromIplImage(result);
1567  else
1568  cvReleaseImage(&result);
1569 #else
1570  THROW_EXCEPTION("The MRPT has been compiled with MRPT_HAS_OPENCV=0 !");
1571 #endif
1572 
1573  MRPT_END
1574 }
1575 
1576 /*---------------------------------------------------------------
1577  normalize
1578  ---------------------------------------------------------------*/
1580 {
1581 #if MRPT_HAS_OPENCV
1582  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1583  IplImage* ipl = getAs<IplImage>(); // Source Image
1584  ASSERT_(ipl)
1585  ASSERTMSG_(
1586  ipl->nChannels == 1,
1587  "CImage::normalize() only defined for grayscale images.")
1588 
1589  uint8_t min_ = 255, max_ = 1;
1590  for (int y = 0; y < ipl->height; y++)
1591  {
1592  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(
1593  ipl->imageData + y * ipl->widthStep);
1594  for (int x = 0; x < ipl->width; x++)
1595  {
1596  const uint8_t val = *ptr++;
1597  if (min_ > val) min_ = val;
1598  if (max_ < val) max_ = val;
1599  }
1600  }
1601 
1602  // Compute scale factor & build convert look-up-table:
1603  const double s = 255.0 / ((double)max_ - (double)min_);
1604  uint8_t lut[256];
1605  for (int v = 0; v < 256; v++) lut[v] = static_cast<uint8_t>((v - min_) * s);
1606 
1607  // Apply LUT:
1608  for (int y = 0; y < ipl->height; y++)
1609  {
1610  uint8_t* ptr =
1611  reinterpret_cast<uint8_t*>(ipl->imageData + y * ipl->widthStep);
1612  for (int x = 0; x < ipl->width; x++)
1613  {
1614  *ptr = lut[*ptr];
1615  ptr++;
1616  }
1617  }
1618 #endif
1619 }
1620 
1621 /*---------------------------------------------------------------
1622  getAsMatrix
1623  ---------------------------------------------------------------*/
1625  CMatrixFloat& outMatrix, bool doResize, int x_min, int y_min, int x_max,
1626  int y_max) const
1627 {
1628 #if MRPT_HAS_OPENCV
1629  MRPT_START
1630 
1631  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1632  ASSERT_(img);
1633 
1634  // Set sizes:
1635  if (x_max == -1) x_max = ((IplImage*)img)->width - 1;
1636  if (y_max == -1) y_max = ((IplImage*)img)->height - 1;
1637 
1638  ASSERT_(x_min >= 0 && x_min < ((IplImage*)img)->width && x_min < x_max);
1639  ASSERT_(y_min >= 0 && y_min < ((IplImage*)img)->height && y_min < y_max);
1640 
1641  int lx = (x_max - x_min + 1);
1642  int ly = (y_max - y_min + 1);
1643 
1644  if (doResize || (int)outMatrix.getRowCount() < ly ||
1645  (int)outMatrix.getColCount() < lx)
1646  outMatrix.setSize(y_max - y_min + 1, x_max - x_min + 1);
1647 
1648  if (isColor())
1649  {
1650  // Luminance: Y = 0.3R + 0.59G + 0.11B
1651  for (int y = 0; y < ly; y++)
1652  {
1653  unsigned char* pixels = this->get_unsafe(x_min, y_min + y, 0);
1654  float aux;
1655  for (int x = 0; x < lx; x++)
1656  {
1657  aux = *pixels++ * 0.3f * (1.0f / 255);
1658  aux += *pixels++ * 0.59f * (1.0f / 255);
1659  aux += *pixels++ * 0.11f * (1.0f / 255);
1660  outMatrix.set_unsafe(y, x, aux);
1661  }
1662  }
1663  }
1664  else
1665  {
1666  for (int y = 0; y < ly; y++)
1667  {
1668  unsigned char* pixels = this->get_unsafe(x_min, y_min + y, 0);
1669  for (int x = 0; x < lx; x++)
1670  outMatrix.set_unsafe(y, x, (*pixels++) * (1.0f / 255));
1671  }
1672  }
1673 
1674  MRPT_END
1675 #endif
1676 }
1677 
1678 /*---------------------------------------------------------------
1679  getAsRGBMatrices
1680  ---------------------------------------------------------------*/
1682  mrpt::math::CMatrixFloat& outMatrixR, mrpt::math::CMatrixFloat& outMatrixG,
1683  mrpt::math::CMatrixFloat& outMatrixB, bool doResize, int x_min, int y_min,
1684  int x_max, int y_max) const
1685 {
1686 #if MRPT_HAS_OPENCV
1687  MRPT_START
1688 
1689  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1690  ASSERT_(img);
1691 
1692  // Set sizes:
1693  if (x_max == -1) x_max = ((IplImage*)img)->width - 1;
1694  if (y_max == -1) y_max = ((IplImage*)img)->height - 1;
1695 
1696  ASSERT_(x_min >= 0 && x_min < ((IplImage*)img)->width && x_min < x_max);
1697  ASSERT_(y_min >= 0 && y_min < ((IplImage*)img)->height && y_min < y_max);
1698 
1699  int lx = (x_max - x_min + 1);
1700  int ly = (y_max - y_min + 1);
1701 
1702  if (doResize || (int)outMatrixR.getRowCount() < ly ||
1703  (int)outMatrixR.getColCount() < lx)
1704  outMatrixR.setSize(y_max - y_min + 1, x_max - x_min + 1);
1705  if (doResize || (int)outMatrixG.getRowCount() < ly ||
1706  (int)outMatrixG.getColCount() < lx)
1707  outMatrixG.setSize(y_max - y_min + 1, x_max - x_min + 1);
1708  if (doResize || (int)outMatrixB.getRowCount() < ly ||
1709  (int)outMatrixB.getColCount() < lx)
1710  outMatrixB.setSize(y_max - y_min + 1, x_max - x_min + 1);
1711 
1712  if (isColor())
1713  {
1714  for (int y = 0; y < ly; y++)
1715  {
1716  unsigned char* pixels = this->get_unsafe(x_min, y_min + y, 0);
1717  float aux;
1718  for (int x = 0; x < lx; x++)
1719  {
1720  aux = *pixels++ * (1.0f / 255);
1721  outMatrixR.set_unsafe(y, x, aux);
1722  aux = *pixels++ * (1.0f / 255);
1723  outMatrixG.set_unsafe(y, x, aux);
1724  aux = *pixels++ * (1.0f / 255);
1725  outMatrixB.set_unsafe(y, x, aux);
1726  }
1727  }
1728  }
1729  else
1730  {
1731  for (int y = 0; y < ly; y++)
1732  {
1733  unsigned char* pixels = this->get_unsafe(x_min, y_min + y, 0);
1734  for (int x = 0; x < lx; x++)
1735  {
1736  outMatrixR.set_unsafe(y, x, (*pixels) * (1.0f / 255));
1737  outMatrixG.set_unsafe(y, x, (*pixels) * (1.0f / 255));
1738  outMatrixB.set_unsafe(y, x, (*pixels++) * (1.0f / 255));
1739  }
1740  }
1741  }
1742 
1743  MRPT_END
1744 #endif
1745 }
1746 
1747 /*---------------------------------------------------------------
1748  cross_correlation_FFT
1749  ---------------------------------------------------------------*/
1751  const CImage& in_img, CMatrixFloat& out_corr, int u_search_ini,
1752  int v_search_ini, int u_search_size, int v_search_size, float biasThisImg,
1753  float biasInImg) const
1754 {
1755  MRPT_START
1756 
1757  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1758  ASSERT_(img);
1759 
1760  // Set limits:
1761  if (u_search_ini == -1) u_search_ini = 0;
1762  if (v_search_ini == -1) v_search_ini = 0;
1763  if (u_search_size == -1) u_search_size = getWidth();
1764  if (v_search_size == -1) v_search_size = getHeight();
1765 
1766  int u_search_end = u_search_ini + u_search_size - 1;
1767  int v_search_end = v_search_ini + v_search_size - 1;
1768 
1769  ASSERT_(u_search_end < (int)getWidth());
1770  ASSERT_(v_search_end < (int)getHeight());
1771 
1772  // Find smallest valid size:
1773  size_t x, y;
1774  size_t actual_lx = max(u_search_size, (int)in_img.getWidth());
1775  size_t actual_ly = max(v_search_size, (int)in_img.getHeight());
1776  size_t lx = math::round2up(actual_lx);
1777  size_t ly = math::round2up(actual_ly);
1778 
1779  // printf("ly=%u lx=%u\n",ly,lx);
1780 
1781  CMatrix i1(ly, lx), i2(ly, lx);
1782 
1783  // We fill the images with the bias, such as when we substract the bias
1784  // later on,
1785  // those pixels not really occupied by the image really becomes zero:
1786  i1.fill(biasInImg);
1787  i2.fill(biasThisImg);
1788 
1789  // Get as matrixes, padded with zeros up to power-of-two sizes:
1790  getAsMatrix(
1791  i2, false, u_search_ini, v_search_ini, u_search_ini + u_search_size - 1,
1792  v_search_ini + v_search_size - 1);
1793  in_img.getAsMatrix(i1, false);
1794 
1795  // Remove the bias now:
1796  i2.array() -= biasThisImg;
1797  i1.array() -= biasInImg;
1798 
1799  // Fill the "padded zeros" with copies of the images:
1800  // SAVE_MATRIX(i1); SAVE_MATRIX(i2);
1801 
1802  // FFT:
1803  CMatrix I1_R, I1_I, I2_R, I2_I, ZEROS(ly, lx);
1804  math::dft2_complex(i1, ZEROS, I1_R, I1_I);
1805  math::dft2_complex(i2, ZEROS, I2_R, I2_I);
1806 
1807  // SAVE_MATRIX(I1_R); SAVE_MATRIX(I1_I);
1808  // SAVE_MATRIX(I2_R); SAVE_MATRIX(I2_I);
1809 
1810  // Compute the COMPLEX division of I2 by I1:
1811  for (y = 0; y < ly; y++)
1812  for (x = 0; x < lx; x++)
1813  {
1814  float r1 = I1_R.get_unsafe(y, x);
1815  float r2 = I2_R.get_unsafe(y, x);
1816 
1817  float ii1 = I1_I.get_unsafe(y, x);
1818  float ii2 = I2_I.get_unsafe(y, x);
1819 
1820  float den = square(r1) + square(ii1);
1821  I2_R.set_unsafe(y, x, (r1 * r2 + ii1 * ii2) / den);
1822  I2_I.set_unsafe(y, x, (ii2 * r1 - r2 * ii1) / den);
1823  }
1824 
1825  // I2_R.saveToTextFile("DIV_R.txt");
1826  // I2_I.saveToTextFile("DIV_I.txt");
1827 
1828  // IFFT:
1829  CMatrix res_R, res_I;
1830  math::idft2_complex(I2_R, I2_I, res_R, res_I);
1831 
1832  out_corr.setSize(actual_ly, actual_lx);
1833  for (y = 0; y < actual_ly; y++)
1834  for (x = 0; x < actual_lx; x++)
1835  out_corr(y, x) = sqrt(square(res_R(y, x)) + square(res_I(y, x)));
1836 
1837  MRPT_END
1838 }
1839 
1840 /*---------------------------------------------------------------
1841  getAsMatrixTiled
1842  ---------------------------------------------------------------*/
1843 void CImage::getAsMatrixTiled(CMatrix& outMatrix) const
1844 {
1845 #if MRPT_HAS_OPENCV
1846  MRPT_START
1847 
1848  makeSureImageIsLoaded(); // For delayed loaded images stored externally
1849  ASSERT_(img);
1850 
1851  // The size of the matrix:
1852  size_t matrix_lx = outMatrix.getColCount();
1853  size_t matrix_ly = outMatrix.getRowCount();
1854 
1855  if (isColor())
1856  {
1857  // Luminance: Y = 0.3R + 0.59G + 0.11B
1858  for (unsigned int y = 0; y < matrix_ly; y++)
1859  {
1860  unsigned char* min_pixels =
1861  (*this)(0, y % ((IplImage*)img)->height, 0);
1862  unsigned char* max_pixels =
1863  min_pixels + ((IplImage*)img)->width * 3;
1864  unsigned char* pixels = min_pixels;
1865  float aux;
1866  for (unsigned int x = 0; x < matrix_lx; x++)
1867  {
1868  aux = *pixels++ * 0.30f;
1869  aux += *pixels++ * 0.59f;
1870  aux += *pixels++ * 0.11f;
1871  outMatrix.set_unsafe(y, x, aux);
1872  if (pixels >= max_pixels) pixels = min_pixels;
1873  }
1874  }
1875  }
1876  else
1877  {
1878  for (unsigned int y = 0; y < matrix_ly; y++)
1879  {
1880  unsigned char* min_pixels =
1881  (*this)(0, y % ((IplImage*)img)->height, 0);
1882  unsigned char* max_pixels = min_pixels + ((IplImage*)img)->width;
1883  unsigned char* pixels = min_pixels;
1884  for (unsigned int x = 0; x < matrix_lx; x++)
1885  {
1886  outMatrix.set_unsafe(y, x, *pixels++);
1887  if (pixels >= max_pixels) pixels = min_pixels;
1888  }
1889  }
1890  }
1891 
1892  MRPT_END
1893 #endif
1894 }
1895 
1896 /*---------------------------------------------------------------
1897  setExternalStorage
1898  ---------------------------------------------------------------*/
1899 void CImage::setExternalStorage(const std::string& fileName) noexcept
1900 {
1901  releaseIpl();
1902  m_externalFile = fileName;
1903  m_imgIsExternalStorage = true;
1904 }
1905 
1906 /*---------------------------------------------------------------
1907  unload
1908  ---------------------------------------------------------------*/
1909 void CImage::unload() const noexcept
1910 {
1912  const_cast<CImage*>(this)->releaseIpl(
1913  true); // Do NOT mark the image as NON external
1914 }
1915 
1916 /*---------------------------------------------------------------
1917  releaseIpl
1918  ---------------------------------------------------------------*/
1919 void CImage::releaseIpl(bool thisIsExternalImgUnload) noexcept
1920 {
1921 #if MRPT_HAS_OPENCV
1922  if (img && !m_imgIsReadOnly)
1923  {
1924  IplImage* ptr = (IplImage*)img;
1925  cvReleaseImage(&ptr);
1926  }
1927  img = nullptr;
1928  m_imgIsReadOnly = false;
1929  if (!thisIsExternalImgUnload)
1930  {
1931  m_imgIsExternalStorage = false;
1932  m_externalFile = string();
1933  }
1934 #endif
1935 }
1936 
1937 /*---------------------------------------------------------------
1938  makeSureImageIsLoaded
1939  ---------------------------------------------------------------*/
1941 {
1942  if (img != nullptr) return; // OK, continue
1943 
1945  {
1946  // Load the file:
1947  string wholeFile;
1949 
1950  const std::string tmpFile = m_externalFile;
1951 
1952  bool ret = const_cast<CImage*>(this)->loadFromFile(wholeFile);
1953 
1954  // These are removed by "loadFromFile", and that's good, just fix it
1955  // here and carry on.
1956  m_imgIsExternalStorage = true;
1957  m_externalFile = tmpFile;
1958 
1959  if (!ret)
1962  "Error loading externally-stored image from: %s",
1963  wholeFile.c_str());
1964  }
1965  else
1966  THROW_EXCEPTION("img is nullptr in a non-externally stored image.");
1967 }
1968 
1969 /*---------------------------------------------------------------
1970  getExternalStorageFileAbsolutePath
1971  ---------------------------------------------------------------*/
1973 {
1974  ASSERT_(m_externalFile.size() > 2);
1975 
1976  if (m_externalFile[0] == '/' ||
1977  (m_externalFile[1] == ':' && m_externalFile[2] == '\\'))
1978  {
1979  out_path = m_externalFile;
1980  }
1981  else
1982  {
1983  out_path = IMAGES_PATH_BASE;
1984 
1985  size_t N = IMAGES_PATH_BASE.size() - 1;
1986  if (IMAGES_PATH_BASE[N] != '/' && IMAGES_PATH_BASE[N] != '\\')
1987  out_path += "/";
1988 
1989  out_path += m_externalFile;
1990  }
1991 }
1992 
1993 /*---------------------------------------------------------------
1994  flipVertical
1995  ---------------------------------------------------------------*/
1996 void CImage::flipVertical(bool also_swapRB)
1997 {
1998 #if MRPT_HAS_OPENCV
1999  IplImage* ptr = (IplImage*)img;
2000  int options = CV_CVTIMG_FLIP;
2001  if (also_swapRB) options |= CV_CVTIMG_SWAP_RB;
2002  cvConvertImage(ptr, ptr, options);
2003 #endif
2004 }
2005 
2007 {
2008 #if MRPT_HAS_OPENCV
2009  IplImage* ptr = (IplImage*)img;
2010  cvFlip(ptr, nullptr, 1);
2011 #endif
2012 }
2013 
2014 /*---------------------------------------------------------------
2015  swapRB
2016  ---------------------------------------------------------------*/
2018 {
2019 #if MRPT_HAS_OPENCV
2020  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2021  ASSERT_(img != nullptr);
2022  IplImage* ptr = (IplImage*)img;
2023  cvConvertImage(ptr, ptr, CV_CVTIMG_SWAP_RB);
2024 #endif
2025 }
2026 
2027 /*---------------------------------------------------------------
2028  rectifyImageInPlace
2029  ---------------------------------------------------------------*/
2030 void CImage::rectifyImageInPlace(void* mapX, void* mapY)
2031 {
2032 #if MRPT_HAS_OPENCV
2033  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2034  ASSERT_(img != nullptr);
2035 
2036 #if MRPT_OPENCV_VERSION_NUM < 0x200
2037  THROW_EXCEPTION("This method requires OpenCV 2.0.0 or above.")
2038 #else
2039 
2040  IplImage* srcImg = getAs<IplImage>(); // Source Image
2041  IplImage* outImg =
2042  cvCreateImage(cvGetSize(srcImg), srcImg->depth, srcImg->nChannels);
2043 
2044  cv::Mat *_mapX, *_mapY;
2045  _mapX = static_cast<cv::Mat*>(mapX);
2046  _mapY = static_cast<cv::Mat*>(mapY);
2047 
2048  IplImage _mapXX = *_mapX;
2049  IplImage _mapYY = *_mapY;
2050 
2051  cvRemap(srcImg, outImg, &_mapXX, &_mapYY, CV_INTER_CUBIC);
2052 #endif
2053 
2054  releaseIpl();
2055  img = outImg;
2056 #endif
2057 }
2058 
2059 /*---------------------------------------------------------------
2060  rectifyImageInPlace
2061  ---------------------------------------------------------------*/
2063 {
2064 #if MRPT_HAS_OPENCV
2065  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2066  ASSERT_(img != nullptr);
2067  // MRPT -> OpenCV Input Transformation
2068  IplImage* srcImg = getAs<IplImage>(); // Source Image
2069  IplImage* outImg; // Output Image
2070  outImg = cvCreateImage(cvGetSize(srcImg), srcImg->depth, srcImg->nChannels);
2071 
2072  double aux1[3][3], aux2[1][5];
2073  const CMatrixDouble33& cameraMatrix = cameraParams.intrinsicParams;
2074 
2075  for (int i = 0; i < 3; i++)
2076  for (int j = 0; j < 3; j++) aux1[i][j] = cameraMatrix(i, j);
2077  for (int i = 0; i < 5; i++) aux2[0][i] = cameraParams.dist[i];
2078 
2079  CvMat inMat = cvMat(
2080  cameraMatrix.getRowCount(), cameraMatrix.getColCount(), CV_64F, aux1);
2081  CvMat distM = cvMat(1, 5, CV_64F, aux2);
2082 
2083  // Remove distortion
2084  cvUndistort2(srcImg, outImg, &inMat, &distM);
2085 
2086  // Assign the output image to the IPLImage pointer within the CImage
2087  releaseIpl();
2088  img = outImg;
2089 #endif
2090 }
2091 
2092 /*---------------------------------------------------------------
2093  rectifyImage
2094  ---------------------------------------------------------------*/
2096  CImage& out_img, const mrpt::utils::TCamera& cameraParams) const
2097 {
2098 #if MRPT_HAS_OPENCV
2099  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2100  ASSERT_(img != nullptr);
2101  // MRPT -> OpenCV Input Transformation
2102  const IplImage* srcImg = getAs<IplImage>(); // Source Image
2103  IplImage* outImg; // Output Image
2104  outImg = cvCreateImage(cvGetSize(srcImg), srcImg->depth, srcImg->nChannels);
2105 
2106  double aux1[3][3], aux2[1][5];
2107  const CMatrixDouble33& cameraMatrix = cameraParams.intrinsicParams;
2108 
2109  for (int i = 0; i < 3; i++)
2110  for (int j = 0; j < 3; j++) aux1[i][j] = cameraMatrix(i, j);
2111  for (int i = 0; i < 5; i++) aux2[0][i] = cameraParams.dist[i];
2112 
2113  CvMat inMat = cvMat(
2114  cameraMatrix.getRowCount(), cameraMatrix.getColCount(), CV_64F, aux1);
2115  CvMat distM = cvMat(1, 5, CV_64F, aux2);
2116 
2117  // Remove distortion
2118  cvUndistort2(srcImg, outImg, &inMat, &distM);
2119 
2120  // OpenCV -> MRPT Output Transformation
2121  out_img.loadFromIplImage(outImg);
2122 
2123  // Release Output Image
2124  cvReleaseImage(&outImg);
2125 #endif
2126 } // end CImage::rectifyImage
2127 
2128 /*---------------------------------------------------------------
2129  filterMedian
2130  ---------------------------------------------------------------*/
2131 void CImage::filterMedian(CImage& out_img, int W) const
2132 {
2133 #if MRPT_HAS_OPENCV
2134  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2135  ASSERT_(img != nullptr);
2136  // MRPT -> OpenCV Input Transformation
2137  const IplImage* srcImg = getAs<IplImage>(); // Source Image
2138  IplImage* outImg; // Output Image
2139  outImg = cvCreateImage(cvGetSize(srcImg), srcImg->depth, srcImg->nChannels);
2140 
2141  // Filter
2142  cvSmooth(srcImg, outImg, CV_MEDIAN, W);
2143 
2144  outImg->origin = srcImg->origin;
2145 
2146  // OpenCV -> MRPT Output Transformation
2147  out_img.loadFromIplImage(outImg);
2148 
2149  // Release Output Image
2150  cvReleaseImage(&outImg);
2151 #endif
2152 }
2153 
2154 /*---------------------------------------------------------------
2155  filterMedian
2156  ---------------------------------------------------------------*/
2158 {
2159 #if MRPT_HAS_OPENCV
2160  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2161  ASSERT_(img != nullptr);
2162  // MRPT -> OpenCV Input Transformation
2163  IplImage* srcImg = getAs<IplImage>(); // Source Image
2164  IplImage* outImg; // Output Image
2165  outImg = cvCreateImage(cvGetSize(srcImg), srcImg->depth, srcImg->nChannels);
2166 
2167  // Filter
2168  cvSmooth(srcImg, outImg, CV_MEDIAN, W);
2169 
2170  outImg->origin = srcImg->origin;
2171 
2172  // Assign the output image to the IPLImage pointer within the CImage
2173  releaseIpl();
2174  img = outImg;
2175 #endif
2176 }
2177 
2178 /*---------------------------------------------------------------
2179  filterGaussian
2180  ---------------------------------------------------------------*/
2181 void CImage::filterGaussian(CImage& out_img, int W, int H) const
2182 {
2183 #if MRPT_HAS_OPENCV
2184  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2185  ASSERT_(img != nullptr);
2186  // MRPT -> OpenCV Input Transformation
2187  const IplImage* srcImg = getAs<IplImage>(); // Source Image
2188  IplImage* outImg; // Output Image
2189  outImg = cvCreateImage(cvGetSize(srcImg), srcImg->depth, srcImg->nChannels);
2190 
2191  // Filter
2192  cvSmooth(srcImg, outImg, CV_GAUSSIAN, W, H);
2193 
2194  outImg->origin = srcImg->origin;
2195 
2196  // OpenCV -> MRPT Output Transformation
2197  out_img.loadFromIplImage(outImg);
2198 
2199  // Release Output Image
2200  cvReleaseImage(&outImg);
2201 #endif
2202 }
2203 
2204 /*---------------------------------------------------------------
2205  filterGaussianInPlace
2206  ---------------------------------------------------------------*/
2208 {
2209 #if MRPT_HAS_OPENCV
2210  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2211  ASSERT_(img != nullptr);
2212  // MRPT -> OpenCV Input Transformation
2213  IplImage* srcImg = getAs<IplImage>(); // Source Image
2214  IplImage* outImg; // Output Image
2215  outImg = cvCreateImage(cvGetSize(srcImg), srcImg->depth, srcImg->nChannels);
2216 
2217  // Filter
2218  cvSmooth(srcImg, outImg, CV_GAUSSIAN, W, H);
2219 
2220  outImg->origin = srcImg->origin;
2221 
2222  // Assign the output image to the IPLImage pointer within the CImage
2223  releaseIpl();
2224  img = outImg;
2225 #endif
2226 }
2227 
2228 /*---------------------------------------------------------------
2229  scaleImage
2230  ---------------------------------------------------------------*/
2232  unsigned int width, unsigned int height, TInterpolationMethod interp)
2233 {
2234 #if MRPT_HAS_OPENCV
2235  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2236  ASSERT_(img != nullptr);
2237  IplImage* srcImg = getAs<IplImage>(); // Source Image
2238 
2239  if (static_cast<unsigned int>(srcImg->width) == width &&
2240  static_cast<unsigned int>(srcImg->height) == height)
2241  return;
2242 
2243  IplImage* outImg; // Output Image
2244  outImg =
2245  cvCreateImage(cvSize(width, height), srcImg->depth, srcImg->nChannels);
2246 
2247  // Resize:
2248  cvResize(srcImg, outImg, (int)interp);
2249 
2250  outImg->origin = srcImg->origin;
2251 
2252  // Assign the output image to the IPLImage pointer within the CImage
2253  releaseIpl();
2254  img = outImg;
2255 #endif
2256 }
2257 
2258 /*---------------------------------------------------------------
2259  scaleImage
2260  ---------------------------------------------------------------*/
2262  CImage& out_img, unsigned int width, unsigned int height,
2264 {
2265 #if MRPT_HAS_OPENCV
2266  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2267  ASSERT_(img != nullptr);
2268  const IplImage* srcImg = getAs<IplImage>(); // Source Image
2269 
2270  if (static_cast<unsigned int>(srcImg->width) == width &&
2271  static_cast<unsigned int>(srcImg->height) == height)
2272  {
2273  // already at the required size:
2274  out_img = *this;
2275  return;
2276  }
2277 
2278  IplImage* outImg; // Output Image
2279  outImg =
2280  cvCreateImage(cvSize(width, height), srcImg->depth, srcImg->nChannels);
2281 
2282  // Resize:
2283  cvResize(srcImg, outImg, (int)interp);
2284  outImg->origin = srcImg->origin;
2285 
2286  // Assign:
2287  out_img.setFromIplImage(outImg);
2288 #endif
2289 }
2290 
2291 /*---------------------------------------------------------------
2292  rotateImage
2293  ---------------------------------------------------------------*/
2295  double angle_radians, unsigned int center_x, unsigned int center_y,
2296  double scale)
2297 {
2298 #if MRPT_HAS_OPENCV
2299  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2300  ASSERT_(img != nullptr);
2301 
2302  IplImage* srcImg = getAs<IplImage>(); // Source Image
2303  IplImage* outImg; // Output Image
2304  outImg = cvCreateImage(cvGetSize(srcImg), srcImg->depth, srcImg->nChannels);
2305 
2306  // Based on the blog entry:
2307  // http://blog.weisu.org/2007/12/opencv-image-rotate-and-zoom-rotation.html
2308 
2309  // Apply rotation & scale:
2310  float m[6];
2311  CvMat M = cvMat(2, 3, CV_32F, m);
2312 
2313  m[0] = (float)(scale * cos(angle_radians));
2314  m[1] = (float)(scale * sin(angle_radians));
2315  m[3] = -m[1];
2316  m[4] = m[0];
2317  m[2] = center_x;
2318  m[5] = center_y;
2319 
2320  cvGetQuadrangleSubPix(srcImg, outImg, &M);
2321 
2322  outImg->origin = srcImg->origin;
2323 
2324  // Assign the output image to the IPLImage pointer within the CImage
2325  releaseIpl();
2326  img = outImg;
2327 
2328 #endif
2329 }
2330 
2331 /** Draw onto this image the detected corners of a chessboard. The length of
2332 * cornerCoords must be the product of the two check_sizes.
2333 *
2334 * \param cornerCoords [IN] The pixel coordinates of all the corners.
2335 * \param check_size_x [IN] The number of squares, in the X direction
2336 * \param check_size_y [IN] The number of squares, in the Y direction
2337 *
2338 * \return false if the length of cornerCoords is inconsistent (nothing is drawn
2339 * then).
2340 */
2342  std::vector<TPixelCoordf>& cornerCoords, unsigned int check_size_x,
2343  unsigned int check_size_y, unsigned int lines_width, unsigned int r)
2344 {
2345 #if MRPT_HAS_OPENCV
2346 
2347  if (cornerCoords.size() != check_size_x * check_size_y) return false;
2348 
2349  IplImage* ipl = this->getAs<IplImage>();
2350 
2351  unsigned int x, y, i;
2352  CvPoint prev_pt = cvPoint(0, 0);
2353  const int line_max = 8;
2354  CvScalar line_colors[8];
2355 
2356  line_colors[0] = CV_RGB(255, 0, 0);
2357  line_colors[1] = CV_RGB(255, 128, 0);
2358  line_colors[2] = CV_RGB(255, 128, 0);
2359  line_colors[3] = CV_RGB(200, 200, 0);
2360  line_colors[4] = CV_RGB(0, 255, 0);
2361  line_colors[5] = CV_RGB(0, 200, 200);
2362  line_colors[6] = CV_RGB(0, 0, 255);
2363  line_colors[7] = CV_RGB(255, 0, 255);
2364 
2365  CCanvas::selectTextFont("10x20");
2366 
2367  for (y = 0, i = 0; y < check_size_y; y++)
2368  {
2369  CvScalar color = line_colors[y % line_max];
2370  for (x = 0; x < check_size_x; x++, i++)
2371  {
2372  CvPoint pt;
2373  pt.x = cvRound(cornerCoords[i].x);
2374  pt.y = cvRound(cornerCoords[i].y);
2375 
2376  if (i != 0) cvLine(ipl, prev_pt, pt, color, lines_width);
2377 
2378  cvLine(
2379  ipl, cvPoint(pt.x - r, pt.y - r), cvPoint(pt.x + r, pt.y + r),
2380  color, lines_width);
2381  cvLine(
2382  ipl, cvPoint(pt.x - r, pt.y + r), cvPoint(pt.x + r, pt.y - r),
2383  color, lines_width);
2384 
2385  if (r > 0) cvCircle(ipl, pt, r + 1, color);
2386  prev_pt = pt;
2387 
2388  // Text label with the corner index in the first and last corners:
2389  if (i == 0 || i == cornerCoords.size() - 1)
2391  pt.x + 5, pt.y - 5, mrpt::format("%u", i),
2393  }
2394  }
2395 
2396  return true;
2397 #else
2398  return false;
2399 #endif
2400 }
2401 
2402 /** Replaces this grayscale image with a RGB version of it.
2403  * \sa grayscaleInPlace
2404  */
2405 void CImage::colorImage(CImage& ret) const
2406 {
2407 #if MRPT_HAS_OPENCV
2408  if (this->isColor())
2409  {
2410  ret = *this;
2411  return;
2412  }
2413 
2414  const IplImage* srcImg = getAs<IplImage>(); // Source Image
2415  IplImage* outImg = cvCreateImage(cvGetSize(srcImg), srcImg->depth, 3);
2416 
2417  cvCvtColor(srcImg, outImg, CV_GRAY2BGR);
2418 
2419  outImg->origin = srcImg->origin;
2420 
2421  // Assign the output image to the IPLImage pointer within the CImage
2422  ret.setFromIplImage(outImg);
2423 #endif
2424 }
2425 
2426 /** Replaces this grayscale image with a RGB version of it.
2427  * \sa grayscaleInPlace
2428  */
2430 {
2431 #if MRPT_HAS_OPENCV
2432  if (this->isColor()) return;
2433 
2434  IplImage* srcImg = getAs<IplImage>(); // Source Image
2435  IplImage* outImg; // Output Image
2436  outImg = cvCreateImage(cvGetSize(srcImg), srcImg->depth, 3);
2437 
2438  cvCvtColor(srcImg, outImg, CV_GRAY2BGR);
2439 
2440  outImg->origin = srcImg->origin;
2441 
2442  // Assign the output image to the IPLImage pointer within the CImage
2443  releaseIpl();
2444  img = outImg;
2445 #endif
2446 }
2447 
2448 /*---------------------------------------------------------------
2449  joinImagesHorz
2450  ---------------------------------------------------------------*/
2451 void CImage::joinImagesHorz(const CImage& im1, const CImage& im2)
2452 {
2453 #if MRPT_HAS_OPENCV
2454  ASSERT_(im1.getHeight() == im2.getHeight());
2455 
2456  const IplImage* _im1 = im1.getAs<IplImage>();
2457  const IplImage* _im2 = im2.getAs<IplImage>();
2458 
2459  ASSERT_(_im1->depth == _im2->depth && _im1->nChannels == _im2->nChannels);
2460 
2461  IplImage* out = cvCreateImage(
2462  cvSize(_im1->width + _im2->width, _im1->height), _im1->depth,
2463  _im1->nChannels);
2464 
2465  cvSetImageROI(out, cvRect(0, 0, _im1->width, _im1->height));
2466  cvCopy(_im1, out);
2467  cvSetImageROI(out, cvRect(_im1->width, 0, _im2->width, _im2->height));
2468  cvCopy(_im2, out);
2469  cvSetImageROI(out, cvRect(0, 0, out->width, out->height));
2470 
2471  IplImage* out2;
2472  if ((int)_im1->nChannels != (int)this->getChannelCount()) // Convert the
2473  // input to the
2474  // output channel
2475  // format
2476  {
2477  out2 = cvCreateImage(
2478  cvSize(_im1->width + _im2->width, _im1->height), _im1->depth,
2479  this->getChannelCount());
2480  cvCvtColor(out, out2, CV_GRAY2BGR);
2481  this->setFromIplImageReadOnly(out2);
2482  }
2483  else // Assign the output image to the IPLImage pointer within the CImage
2484  this->setFromIplImageReadOnly(out);
2485 
2486 #endif
2487 } // end
2488 
2489 /*---------------------------------------------------------------
2490  equalizeHist
2491  ---------------------------------------------------------------*/
2492 void CImage::equalizeHist(CImage& outImg) const
2493 {
2494 #if MRPT_HAS_OPENCV
2495  // Convert to a single luminance channel image
2496  const IplImage* srcImg = getAs<IplImage>(); // Source Image
2497  ASSERT_(srcImg != nullptr)
2498 
2499  outImg.changeSize(srcImg->width, srcImg->height, 1, isOriginTopLeft());
2500 
2501  if (srcImg->nChannels == 1)
2502  { // Grayscale:
2503  cvEqualizeHist(srcImg, outImg.getAs<IplImage>());
2504  }
2505  else
2506  { // Color:
2507  IplImage* hsv = cvCreateImage(cvGetSize(srcImg), 8, 3);
2508  IplImage* h = cvCreateImage(cvGetSize(srcImg), 8, 1);
2509  IplImage* s = cvCreateImage(cvGetSize(srcImg), 8, 1);
2510  IplImage* v = cvCreateImage(cvGetSize(srcImg), 8, 1);
2511 
2512  cvCvtColor(srcImg, hsv, CV_BGR2HSV);
2513  cvSplit(hsv, h, s, v, nullptr);
2514 
2515  cvEqualizeHist(v, v);
2516 
2517  cvMerge(h, s, v, nullptr, hsv);
2518  cvCvtColor(hsv, outImg.getAs<IplImage>(), CV_HSV2BGR);
2519 
2520  cvReleaseImage(&hsv);
2521  cvReleaseImage(&h);
2522  cvReleaseImage(&s);
2523  cvReleaseImage(&v);
2524  }
2525 
2526 #endif
2527 }
2528 
2529 /*---------------------------------------------------------------
2530  equalizeHistInPlace
2531  ---------------------------------------------------------------*/
2533 {
2534 #if MRPT_HAS_OPENCV
2535  // Convert to a single luminance channel image
2536  IplImage* srcImg = getAs<IplImage>(); // Source Image
2537  ASSERT_(srcImg != nullptr);
2538 
2539  IplImage* outImg =
2540  cvCreateImage(cvGetSize(srcImg), srcImg->depth, srcImg->nChannels);
2541  outImg->origin = srcImg->origin;
2542 
2543  if (srcImg->nChannels == 1)
2544  { // Grayscale:
2545  cvEqualizeHist(srcImg, outImg);
2546  }
2547  else
2548  { // Color:
2549  IplImage* hsv = cvCreateImage(cvGetSize(srcImg), 8, 3);
2550  IplImage* h = cvCreateImage(cvGetSize(srcImg), 8, 1);
2551  IplImage* s = cvCreateImage(cvGetSize(srcImg), 8, 1);
2552  IplImage* v = cvCreateImage(cvGetSize(srcImg), 8, 1);
2553 
2554  cvCvtColor(srcImg, hsv, CV_BGR2HSV);
2555  cvSplit(hsv, h, s, v, nullptr);
2556 
2557  cvEqualizeHist(v, v);
2558 
2559  cvMerge(h, s, v, nullptr, hsv);
2560  cvCvtColor(hsv, outImg, CV_HSV2BGR);
2561 
2562  cvReleaseImage(&hsv);
2563  cvReleaseImage(&h);
2564  cvReleaseImage(&s);
2565  cvReleaseImage(&v);
2566  }
2567 
2568  // Assign the output image to the IPLImage pointer within the CImage
2569  releaseIpl();
2570  img = outImg;
2571 
2572 #endif
2573 }
2574 
2575 template <unsigned int HALF_WIN_SIZE>
2577  const uint8_t* in, const int widthStep, int x, int y, int32_t& _gxx,
2578  int32_t& _gyy, int32_t& _gxy)
2579 {
2580  const unsigned int min_x = x - HALF_WIN_SIZE;
2581  const unsigned int min_y = y - HALF_WIN_SIZE;
2582 
2583  int32_t gxx = 0;
2584  int32_t gxy = 0;
2585  int32_t gyy = 0;
2586 
2587  const unsigned int WIN_SIZE = 1 + 2 * HALF_WIN_SIZE;
2588 
2589  unsigned int yy = min_y;
2590  for (unsigned int iy = WIN_SIZE; iy; --iy, ++yy)
2591  {
2592  const uint8_t* ptr = in + widthStep * yy + min_x;
2593  unsigned int xx = min_x;
2594  for (unsigned int ix = WIN_SIZE; ix; --ix, ++xx)
2595  {
2596  const int32_t dx = ptr[+1] - ptr[-1];
2597  const int32_t dy = ptr[+widthStep] - ptr[-widthStep];
2598  gxx += dx * dx;
2599  gxy += dx * dy;
2600  gyy += dy * dy;
2601  }
2602  }
2603  _gxx = gxx;
2604  _gyy = gyy;
2605  _gxy = gxy;
2606 }
2607 
2609  const unsigned int x, const unsigned int y,
2610  const unsigned int half_window_size) const
2611 {
2612 #if MRPT_HAS_OPENCV
2613  const IplImage* srcImg = this->getAs<IplImage>();
2614  ASSERT_(srcImg != nullptr)
2615  ASSERTMSG_(
2616  srcImg->nChannels == 1,
2617  "KLT_response only works with grayscale images.")
2618 
2619  const unsigned int img_w = srcImg->width;
2620  const unsigned int img_h = srcImg->height;
2621  const int widthStep = srcImg->widthStep;
2622 
2623  // If any of those predefined values worked, do the generic way:
2624  const unsigned int min_x = x - half_window_size;
2625  const unsigned int max_x = x + half_window_size;
2626  const unsigned int min_y = y - half_window_size;
2627  const unsigned int max_y = y + half_window_size;
2628 
2629  // Since min_* are "unsigned", checking "<" will detect negative numbers:
2630  ASSERTMSG_(
2631  min_x < img_w && max_x < img_w && min_y < img_h && max_y < img_h,
2632  "Window is out of image bounds")
2633 
2634  // Gradient sums: Use integers since they're much faster than
2635  // doubles/floats!!
2636  int32_t gxx = 0;
2637  int32_t gxy = 0;
2638  int32_t gyy = 0;
2639 
2640  const uint8_t* img_data = reinterpret_cast<const uint8_t*>(
2641  srcImg->imageData); //*VERY IMPORTANT*: Use unsigned
2642  switch (half_window_size)
2643  {
2644  case 2:
2645  image_KLT_response_template<2>(
2646  img_data, widthStep, x, y, gxx, gyy, gxy);
2647  break;
2648  case 3:
2649  image_KLT_response_template<3>(
2650  img_data, widthStep, x, y, gxx, gyy, gxy);
2651  break;
2652  case 4:
2653  image_KLT_response_template<4>(
2654  img_data, widthStep, x, y, gxx, gyy, gxy);
2655  break;
2656  case 5:
2657  image_KLT_response_template<5>(
2658  img_data, widthStep, x, y, gxx, gyy, gxy);
2659  break;
2660  case 6:
2661  image_KLT_response_template<6>(
2662  img_data, widthStep, x, y, gxx, gyy, gxy);
2663  break;
2664  case 7:
2665  image_KLT_response_template<7>(
2666  img_data, widthStep, x, y, gxx, gyy, gxy);
2667  break;
2668  case 8:
2669  image_KLT_response_template<8>(
2670  img_data, widthStep, x, y, gxx, gyy, gxy);
2671  break;
2672  case 9:
2673  image_KLT_response_template<9>(
2674  img_data, widthStep, x, y, gxx, gyy, gxy);
2675  break;
2676  case 10:
2677  image_KLT_response_template<10>(
2678  img_data, widthStep, x, y, gxx, gyy, gxy);
2679  break;
2680  case 11:
2681  image_KLT_response_template<11>(
2682  img_data, widthStep, x, y, gxx, gyy, gxy);
2683  break;
2684  case 12:
2685  image_KLT_response_template<12>(
2686  img_data, widthStep, x, y, gxx, gyy, gxy);
2687  break;
2688  case 13:
2689  image_KLT_response_template<13>(
2690  img_data, widthStep, x, y, gxx, gyy, gxy);
2691  break;
2692  case 14:
2693  image_KLT_response_template<14>(
2694  img_data, widthStep, x, y, gxx, gyy, gxy);
2695  break;
2696  case 15:
2697  image_KLT_response_template<15>(
2698  img_data, widthStep, x, y, gxx, gyy, gxy);
2699  break;
2700  case 16:
2701  image_KLT_response_template<16>(
2702  img_data, widthStep, x, y, gxx, gyy, gxy);
2703  break;
2704  case 32:
2705  image_KLT_response_template<32>(
2706  img_data, widthStep, x, y, gxx, gyy, gxy);
2707  break;
2708 
2709  default:
2710  for (unsigned int yy = min_y; yy <= max_y; yy++)
2711  {
2712  const uint8_t* ptr = img_data + widthStep * yy + min_x;
2713  for (unsigned int xx = min_x; xx <= max_x; xx++)
2714  {
2715  const int32_t dx = ptr[+1] - ptr[-1];
2716  const int32_t dy = ptr[+widthStep] - ptr[-widthStep];
2717  gxx += dx * dx;
2718  gxy += dx * dy;
2719  gyy += dy * dy;
2720  }
2721  }
2722  break;
2723  }
2724  // Convert to float's and normalize in the way:
2725  const float K = 0.5f / ((max_y - min_y + 1) * (max_x - min_x + 1));
2726  const float Gxx = gxx * K;
2727  const float Gxy = gxy * K;
2728  const float Gyy = gyy * K;
2729 
2730  // Return the minimum eigenvalue of:
2731  // ( gxx gxy )
2732  // ( gxy gyy )
2733  // See, for example: mrpt::math::detail::eigenVectorsMatrix_special_2x2():
2734  const float t = Gxx + Gyy; // Trace
2735  const float de = Gxx * Gyy - Gxy * Gxy; // Det
2736  // The smallest eigenvalue is:
2737  return 0.5f * (t - std::sqrt(t * t - 4.0f * de));
2738 #else
2739  return 0;
2740 #endif
2741 }
2742 
2743 /** Marks the channel ordering in a color image (this doesn't actually modify
2744  * the image data, just the format description)
2745  */
2747 {
2748 #if MRPT_HAS_OPENCV
2749  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2750  ASSERT_(img);
2751  strcpy(((IplImage*)img)->channelSeq, "RGB");
2752 #else
2753  THROW_EXCEPTION("MRPT compiled without OpenCV")
2754 #endif
2755 }
2756 
2758 {
2759 #if MRPT_HAS_OPENCV
2760  makeSureImageIsLoaded(); // For delayed loaded images stored externally
2761  ASSERT_(img);
2762  strcpy(((IplImage*)img)->channelSeq, "BGR");
2763 #else
2764  THROW_EXCEPTION("MRPT compiled without OpenCV")
2765 #endif
2766 }
2767 
2768 /** Loads the image from an XPM array, as #include'd from a ".xpm" file.
2769  * \sa loadFromFile
2770  * \return false on any error */
2771 bool CImage::loadFromXPM(const char** xpm_array, bool swap_rb)
2772 {
2773 #if MRPT_HAS_OPENCV && MRPT_HAS_WXWIDGETS
2774  try
2775  {
2776  const wxImage b(xpm_array);
2777 
2778  const size_t lx = b.GetWidth();
2779  const size_t ly = b.GetHeight();
2780 
2781  this->loadFromMemoryBuffer(lx, ly, true, b.GetData(), swap_rb);
2782  return true;
2783  }
2784  catch (std::exception& e)
2785  {
2786  std::cerr << "[CImage::loadFromXPM] " << e.what() << std::endl;
2787  return false;
2788  }
2789 #else
2790  MRPT_UNUSED_PARAM(xpm_array);
2791  MRPT_UNUSED_PARAM(swap_rb);
2792  return false;
2793 #endif // MRPT_HAS_OPENCV && MRPT_HAS_WXWIDGETS
2794 }
2795 
2796 // Load from TGA files. Used in loadFromFile()
2797 // Contains code from
2798 // https://github.com/tjohnman/Simple-Targa-Library/blob/master/src/simpleTGA.cpp
2799 // (FreeBSD license)
2801  const std::string& fileName, mrpt::utils::CImage& out_RGB,
2802  mrpt::utils::CImage& out_alpha)
2803 {
2804 #if MRPT_HAS_OPENCV
2805  std::fstream stream;
2806  stream.open(fileName.c_str(), std::fstream::in | std::fstream::binary);
2807  if (!stream.is_open())
2808  {
2809  std::cerr << "[CImage::loadTGA] Couldn't open file '" << fileName
2810  << "'.\n";
2811  return false;
2812  }
2813 
2814  stream.seekg(0, std::ios_base::end);
2815  // long length = stream.tellg();
2816  stream.seekg(0, std::ios_base::beg);
2817 
2818  // Simple uncompressed true-color image
2819  char dumpBuffer[12];
2820  char trueColorHeader[] = "\0\0\2\0\0\0\0\0\0\0\0\0";
2821  stream.read(dumpBuffer, 12);
2822  if (memcmp(dumpBuffer, trueColorHeader, 12) != 0)
2823  {
2824  std::cerr << "[CImage::loadTGA] Unsupported format or invalid file.\n";
2825  return false;
2826  }
2827 
2828  unsigned short width, height;
2829  unsigned char bpp;
2830 
2831  stream.read((char*)&width, 2);
2832  stream.read((char*)&height, 2);
2833  bpp = stream.get();
2834  if (bpp != 32)
2835  {
2836  std::cerr << "[CImage::loadTGA] Only 32 bpp format supported!\n";
2837  return false;
2838  }
2839 
2840  unsigned char desc;
2841  desc = stream.get();
2842  if (desc != 8 && desc != 32)
2843  {
2844  std::cerr << "[CImage::loadTGA] Unsupported format or invalid file.\n";
2845  return false;
2846  }
2847  const bool origin_is_low_corner = (desc == 8);
2848 
2849  // Data section
2850  std::vector<uint8_t> bytes(width * height * 4);
2851  stream.read((char*)&bytes[0], width * height * 4);
2852  stream.close();
2853 
2854  // Move data to images:
2855  out_RGB.resize(width, height, CH_RGB, true);
2856  out_alpha.resize(width, height, CH_GRAY, true);
2857 
2858  size_t idx = 0;
2859  for (unsigned int r = 0; r < height; r++)
2860  {
2861  unsigned int actual_row = origin_is_low_corner ? (height - 1 - r) : r;
2862  IplImage* ipl = ((IplImage*)out_RGB.img);
2863  unsigned char* data =
2864  (unsigned char*)&ipl->imageData[actual_row * ipl->widthStep];
2865 
2866  IplImage* ipl_alpha = ((IplImage*)out_alpha.img);
2867  unsigned char* data_alpha =
2868  (unsigned char*)&ipl->imageData[actual_row * ipl_alpha->widthStep];
2869 
2870  for (unsigned int c = 0; c < width; c++)
2871  {
2872  *data++ = bytes[idx++]; // R
2873  *data++ = bytes[idx++]; // G
2874  *data++ = bytes[idx++]; // B
2875  *data_alpha++ = bytes[idx++]; // A
2876  }
2877  }
2878 
2879  return true;
2880 #else
2881  return false;
2882 #endif // MRPT_HAS_OPENCV
2883 }
virtual void textOut(int x0, int y0, const std::string &str, const mrpt::utils::TColor color)
Renders 2D text using bitmap fonts.
Definition: CCanvas.cpp:371
bool is_aligned< 16 >(const void *ptr)
Definition: memory.h:126
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:953
void equalizeHistInPlace()
Equalize the image histogram, replacing the original image.
Definition: CImage.cpp:2532
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei imageSize
Definition: glext.h:3743
float correlate(const CImage &img2int, int width_init=0, int height_init=0) const
Computes the correlation coefficient (returned as val), between two images This function use grayscal...
Definition: CImage.cpp:1406
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
GLdouble GLdouble t
Definition: glext.h:3689
TImageChannels getChannelCount() const
Returns the number of channels, typically 1 (GRAY) or 3 (RGB)
Definition: CImage.cpp:925
static bool DISABLE_JPEG_COMPRESSION
By default, when storing images through the CSerializable interface, RGB images are JPEG-compressed t...
Definition: CImage.h:228
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
static int SERIALIZATION_JPEG_QUALITY
Unless DISABLE_JPEG_COMPRESSION=true, this sets the JPEG quality (range 1-100) of serialized RGB imag...
Definition: CImage.h:233
std::string m_externalFile
The file name of a external storage image.
Definition: CImage.h:1087
unsigned char red[10]
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:30
static bool loadTGA(const std::string &fileName, mrpt::utils::CImage &out_RGB, mrpt::utils::CImage &out_alpha)
Loads a TGA true-color RGBA image as two CImage objects, one for the RGB channels plus a separate gra...
Definition: CImage.cpp:2800
CImage scaleDouble() const
Returns a new image scaled up to double its original size.
Definition: CImage.h:365
The virtual base class which provides a unified interface for all persistent objects in MRPT...
Definition: CSerializable.h:44
bool m_imgIsReadOnly
Set to true only when using setFromIplImageReadOnly.
Definition: CImage.h:1081
A class for storing images as grayscale or RGB bitmaps.
Definition: CImage.h:118
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
void flipVertical(bool also_swapRB=false)
Flips the image vertically.
Definition: CImage.cpp:1996
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:6502
#define THROW_TYPED_EXCEPTION_FMT(exceptionClass, _FORMAT_STRING,...)
void rotateImage(double angle_radians, unsigned int center_x, unsigned int center_y, double scale=1.0)
Rotates the image by the given angle around the given center point, with an optional scale factor...
Definition: CImage.cpp:2294
uint64_t Seek(uint64_t Offset, CStream::TSeekOrigin Origin=sFromBeginning) override
Introduces a pure virtual method for moving to a specified position in the streamed resource...
void unload() const noexcept
For external storage image objects only, this method unloads the image from memory (or does nothing i...
Definition: CImage.cpp:1909
void image_SSSE3_bgr_to_gray_8u(const uint8_t *in, uint8_t *out, int w, int h)
Convert a RGB image (3cu8) into a GRAYSCALE (1c8u) image, using Y=77*R+150*G+29*B.
void rectifyImageInPlace(const mrpt::utils::TCamera &cameraParams)
Rectify (un-distort) the image according to a certain camera matrix and vector of distortion coeffici...
Definition: CImage.cpp:2062
void copyFastFrom(CImage &o)
Moves an image from another object, erasing the origin image in the process (this is much faster than...
Definition: CImage.cpp:173
#define THROW_EXCEPTION(msg)
void resize(unsigned int width, unsigned int height, TImageChannels nChannels, bool originTopLeft)
Changes the size of the image, erasing previous contents (does NOT scale its current content...
Definition: CImage.h:249
void getAsMatrix(mrpt::math::CMatrixFloat &outMatrix, bool doResize=true, int x_min=0, int y_min=0, int x_max=-1, int y_max=-1) const
Returns the image as a matrix with pixel grayscale values in the range [0,1].
Definition: CImage.cpp:1624
A pair (x,y) of pixel coordinates (integer resolution).
Definition: TPixelCoord.h:38
void rectifyImage(CImage &out_img, const mrpt::utils::TCamera &cameraParams) const
Rectify (un-distort) the image according to some camera parameters, and returns an output un-distorte...
Definition: CImage.cpp:2095
GLenum GLsizei n
Definition: glext.h:5074
const char * getChannelsOrder() const
Returns a string of the form "BGR","RGB" or "GRAY" indicating the channels ordering.
Definition: CImage.cpp:1188
float getMaxAsFloat() const
Return the maximum pixel value of the image, as a float value in the range [0,1]. ...
Definition: CImage.cpp:984
void WriteBuffer(const void *Buffer, size_t Count)
Writes a block of bytes to the stream from Buffer.
Definition: CStream.cpp:64
void filterMedian(CImage &out_img, int W=3) const
Filter the image with a Median filter with a window size WxW, returning the filtered image in out_img...
Definition: CImage.cpp:2131
void flipHorizontal()
Flips the image horizontally.
Definition: CImage.cpp:2006
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const override
Introduces a pure virtual method responsible for writing to a CStream.
Definition: CImage.cpp:512
for(ctr=DCTSIZE;ctr > 0;ctr--)
Definition: jidctflt.cpp:56
void colorImageInPlace()
Replaces this grayscale image with a RGB version of it.
Definition: CImage.cpp:2429
STL namespace.
void cross_correlation(const CImage &patch_img, size_t &u_max, size_t &v_max, double &max_val, int u_search_ini=-1, int v_search_ini=-1, int u_search_size=-1, int v_search_size=-1, CImage *out_corr_image=nullptr) const
Computes the correlation between this image and another one, encapsulating the openCV function cvMatc...
Definition: CImage.cpp:1462
bool loadFromFile(const std::string &fileName, int isColor=-1)
Load image from a file, whose format is determined from the extension (internally uses OpenCV)...
Definition: CImage.cpp:276
GLdouble s
Definition: glext.h:3676
GLuint src
Definition: glext.h:7278
int TImageChannels
For use in mrpt::utils::CImage.
Definition: CImage.h:41
void normalize()
Optimize the brightness range of an image without using histogram Only for one channel images...
Definition: CImage.cpp:1579
void loadFromIplImage(void *iplImage)
Reads the image from a OpenCV IplImage object (making a COPY).
Definition: CImage.cpp:326
GLenum GLsizei width
Definition: glext.h:3531
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:4178
const T * getAs() const
Returns a pointer to a const T* containing the image - the idea is to call like "img.getAs<IplImage>()" so we can avoid here including OpenCV&#39;s headers.
Definition: CImage.h:587
virtual ~CImage()
Destructor:
Definition: CImage.cpp:224
CImage & operator=(const CImage &o)
Copy operator (if the image is externally stored, the writen image will be such as well)...
Definition: CImage.cpp:110
T square(const T x)
Inline function for the square of a number.
Definition: bits.h:55
static std::string IMAGES_PATH_BASE(".")
unsigned char uint8_t
Definition: rptypes.h:41
void image_SSE2_scale_half_smooth_1c8u(const uint8_t *in, uint8_t *out, int w, int h)
Average each 2x2 pixels into 1x1 pixel (arithmetic average)
Definition: CImage_SSE2.cpp:76
GLuint color
Definition: glext.h:8300
void cross_correlation_FFT(const CImage &in_img, math::CMatrixFloat &out_corr, int u_search_ini=-1, int v_search_ini=-1, int u_search_size=-1, int v_search_size=-1, float biasThisImg=0, float biasInImg=0) const
Computes the correlation matrix between this image and another one.
Definition: CImage.cpp:1750
void image_SSSE3_scale_half_3c8u(const uint8_t *in, uint8_t *out, int w, int h)
Subsample each 2x2 pixel block into 1x1 pixel, taking the first pixel & ignoring the other 3...
Definition: CImage_SSE3.cpp:40
void getAsMatrixTiled(math::CMatrix &outMatrix) const
Returns the image as a matrix, where the image is "tiled" (repeated) the required number of times to ...
Definition: CImage.cpp:1843
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
size_t getWidth() const override
Returns the width of the image in pixels.
Definition: CImage.cpp:869
T round2up(T val)
Round up to the nearest power of two of a given number.
void loadFromMemoryBuffer(unsigned int width, unsigned int height, bool color, unsigned char *rawpixels, bool swapRedBlue=false)
Reads the image from raw pixels buffer in memory.
Definition: CImage.cpp:390
#define MRPT_END
float KLT_response(const unsigned int x, const unsigned int y, const unsigned int half_window_size) const
Compute the KLT response at a given pixel (x,y) - Only for grayscale images (for efficiency it avoids...
Definition: CImage.cpp:2608
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
This CStream derived class allow using a memory buffer as a CStream.
Definition: CMemoryStream.h:27
const GLubyte * c
Definition: glext.h:6313
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
GLint GLvoid * img
Definition: glext.h:3763
void image_KLT_response_template(const uint8_t *in, const int widthStep, int x, int y, int32_t &_gxx, int32_t &_gyy, int32_t &_gxy)
Definition: CImage.cpp:2576
#define CH_RGB
Definition: CImage.h:43
IplImage * ipl_to_grayscale(const IplImage *img_src)
Definition: CImage.cpp:1008
virtual void selectTextFont(const std::string &fontName)
Select the current font used when drawing text.
Definition: CCanvas.cpp:231
GLuint GLuint end
Definition: glext.h:3528
CImage grayscale() const
Returns a grayscale version of the image, or itself if it is already a grayscale image.
Definition: CImage.cpp:999
void scaleImage(unsigned int width, unsigned int height, TInterpolationMethod interp=IMG_INTERP_CUBIC)
Scales this image to a new size, interpolating as needed.
Definition: CImage.cpp:2231
size_t getHeight() const override
Returns the height of the image in pixels.
Definition: CImage.cpp:897
void releaseIpl(bool thisIsExternalImgUnload=false) noexcept
Release the internal IPL image, if not nullptr or read-only.
Definition: CImage.cpp:1919
A RGB color - 8bit.
Definition: TColor.h:25
int val
Definition: mrpt_jpeglib.h:955
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19
GLubyte GLubyte b
Definition: glext.h:6279
void setChannelsOrder_RGB()
Marks the channel ordering in a color image as "RGB" (this doesn&#39;t actually modify the image data...
Definition: CImage.cpp:2746
#define IMPLEMENTS_MEXPLUS_FROM(complete_type)
size_t getRowStride() const
Returns the row stride of the image: this is the number of bytes between two consecutive rows...
Definition: CImage.cpp:883
void saveToStreamAsJPEG(mrpt::utils::CStream &out, const int jpeg_quality=95) const
Save image to binary stream as a JPEG (.jpg) compressed format.
void swapRB()
Swaps red and blue channels.
Definition: CImage.cpp:2017
void setFromIplImage(void *iplImage)
Reads the image from a OpenCV IplImage object (WITHOUT making a copy).
Definition: CImage.cpp:368
void changeSize(unsigned int width, unsigned int height, TImageChannels nChannels, bool originTopLeft)
Resize the buffers in "img" to accomodate a new image size and/or format.
Definition: CImage.cpp:228
bool loadFromXPM(const char **xpm_array, bool swap_rb=true)
Loads the image from an XPM array, as #include&#39;d from a ".xpm" file.
Definition: CImage.cpp:2771
void setFromIplImageReadOnly(void *iplImage)
Reads the image from a OpenCV IplImage object (WITHOUT making a copy) and from now on the image canno...
Definition: CImage.cpp:345
static void setImagesPathBase(const std::string &path)
Definition: CImage.cpp:59
GLsizei const GLchar ** string
Definition: glext.h:4101
void swap(CImage &o)
Very efficient swap of two images (just swap the internal pointers)
Definition: CImage.cpp:138
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: glext.h:3600
mrpt::math::CMatrixDouble33 intrinsicParams
Matrix of intrinsic parameters (containing the focal length and principal point coordinates) ...
Definition: TCamera.h:57
void setExternalStorage(const std::string &fileName) noexcept
By using this method the image is marked as referenced to an external file, which will be loaded only...
Definition: CImage.cpp:1899
void idft2_complex(const CMatrixFloat &in_real, const CMatrixFloat &in_imag, CMatrixFloat &out_real, CMatrixFloat &out_imag)
Compute the 2D inverse Discrete Fourier Transform (DFT).
Definition: math.cpp:1581
void image_SSE2_scale_half_1c8u(const uint8_t *in, uint8_t *out, int w, int h)
Subsample each 2x2 pixel block into 1x1 pixel, taking the first pixel & ignoring the other 3...
Definition: CImage_SSE2.cpp:43
void copyFromForceLoad(const CImage &o)
Copies from another image, and, if that one is externally stored, the image file will be actually loa...
Definition: CImage.cpp:153
void setPixel(int x, int y, size_t color) override
Changes the value of the pixel (x,y).
Definition: CImage.cpp:1251
void * getRawBufferData()
Method for getting a pointer to the raw stored data.
void filterMedianInPlace(int W=3)
Filter the image with a Median filter with a window size WxH, replacing "this" image by the filtered ...
Definition: CImage.cpp:2157
TInterpolationMethod
Interpolation methods for images.
Definition: CImage.h:32
void setChannelsOrder_BGR()
Marks the channel ordering in a color image as "BGR" (this doesn&#39;t actually modify the image data...
Definition: CImage.cpp:2757
#define MRPT_START
__int32 int32_t
Definition: rptypes.h:46
void makeSureImageIsLoaded() const
Checks if the image is of type "external storage", and if so and not loaded yet, load it...
Definition: CImage.cpp:1940
const GLdouble * v
Definition: glext.h:3678
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void update_patch(const CImage &patch, const unsigned int col, const unsigned int row)
Update a part of this image with the "patch" given as argument.
Definition: CImage.cpp:1340
unsigned char * operator()(unsigned int col, unsigned int row, unsigned int channel=0) const
Returns a pointer to a given pixel information.
Definition: CImage.cpp:457
GLdouble GLdouble GLdouble r
Definition: glext.h:3705
CImage scaleHalfSmooth() const
Returns a new image scaled down to half its original size (averaging between every two rows) ...
Definition: CImage.h:351
mrpt::math::CArrayDouble< 5 > dist
[k1 k2 t1 t2 k3] -> k_i: parameters of radial distortion, t_i: parameters of tangential distortion (d...
Definition: TCamera.h:60
virtual mxArray * writeToMatlab() const
Introduces a pure virtual method responsible for writing to a mxArray Matlab object, typically a MATLAB struct whose contents are documented in each derived class.
Definition: CSerializable.h:89
GLclampf green
Definition: glext.h:3525
CImage scaleHalf() const
Returns a new image scaled down to half its original size.
Definition: CImage.h:336
void equalizeHist(CImage &outImg) const
Equalize the image histogram, saving the new image in the given output object.
Definition: CImage.cpp:2492
void filterGaussianInPlace(int W=3, int H=3)
Filter the image with a Gaussian filter with a window size WxH, returning the filtered image in out_i...
Definition: CImage.cpp:2207
GLenum GLenum GLvoid * row
Definition: glext.h:3576
CImage()
Default constructor: initialize an 1x1 RGB image.
Definition: CImage.cpp:86
void extract_patch(CImage &patch, const unsigned int col=0, const unsigned int row=0, const unsigned int width=1, const unsigned int height=1) const
Extract a patch from this image, saveing it into "patch" (its previous contents will be overwritten)...
Definition: CImage.cpp:1367
bool drawChessboardCorners(std::vector< TPixelCoordf > &cornerCoords, unsigned int check_size_x, unsigned int check_size_y, unsigned int lines_width=1, unsigned int circles_radius=4)
Draw onto this image the detected corners of a chessboard.
Definition: CImage.cpp:2341
#define CH_GRAY
Definition: CImage.h:42
GLuint in
Definition: glext.h:7274
bool isOriginTopLeft() const
Returns true if the coordinates origin is top-left, or false if it is bottom-left.
Definition: CImage.cpp:939
void changeSize(uint64_t newSize)
Change size.
#define ASSERT_(f)
A versatile "profiler" that logs the time spent within each pair of calls to enter(X)-leave(X), among other stats.
Definition: CTimeLogger.h:45
double leave(const char *func_name)
End of a named section.
Definition: CTimeLogger.h:123
static constexpr TColor blue()
Definition: TColor.h:65
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:25
bool saveToFile(const std::string &fileName, int jpeg_quality=95) const
Save the image to a file, whose format is determined from the extension (internally uses OpenCV)...
Definition: CImage.cpp:301
GLenum GLint GLint y
Definition: glext.h:3538
static bool DISABLE_ZIP_COMPRESSION
By default, when storing images through the CSerializable interface, grayscale images will be ZIP com...
Definition: CImage.h:221
bool m_imgIsExternalStorage
Set to true only when using setExternalStorage.
Definition: CImage.h:1085
bool isColor() const
Returns true if the image is RGB, false if it is grayscale.
Definition: CImage.cpp:911
void colorImage(CImage &ret) const
Returns a RGB version of the grayscale image, or itself if it is already a RGB image.
Definition: CImage.cpp:2405
void compress(void *inData, size_t inDataSize, std::vector< unsigned char > &outData)
Compress an array of bytes into another one.
Definition: zip.cpp:36
unsigned char * get_unsafe(unsigned int col, unsigned int row, unsigned int channel=0) const
Access to pixels without checking boundaries - Use normally the () operator better, which checks the coordinates.
Definition: CImage.cpp:496
GLuint interp
Definition: glext.h:7133
void drawCircle(int x, int y, int radius, const mrpt::utils::TColor &color=mrpt::utils::TColor(255, 255, 255), unsigned int width=1) override
Draws a circle of a given radius.
Definition: CImage.cpp:1323
GLclampf GLclampf blue
Definition: glext.h:3525
GLenum GLint x
Definition: glext.h:3538
bool isExternallyStored() const noexcept
See setExternalStorage().
Definition: CImage.h:780
uint64_t getTotalBytesCount() override
Returns the total size of the internal buffer.
char * strcpy(char *dest, size_t destSize, const char *source) noexcept
An OS-independent version of strcpy.
Definition: os.cpp:296
void decompress(void *inData, size_t inDataSize, std::vector< unsigned char > &outData, size_t outDataEstimatedSize)
Decompress an array of bytes into another one.
Definition: zip.cpp:137
This class is a "CSerializable" wrapper for "CMatrixFloat".
Definition: CMatrix.h:25
TPenStyle
Definition of pen styles.
Definition: CCanvas.h:57
GLenum GLsizei GLsizei height
Definition: glext.h:3554
void dft2_complex(const CMatrixFloat &in_real, const CMatrixFloat &in_imag, CMatrixFloat &out_real, CMatrixFloat &out_imag)
Compute the 2D Discrete Fourier Transform (DFT) of a complex matrix, returning the real and imaginary...
Definition: math.cpp:1476
void readFromStream(mrpt::utils::CStream &in, int version) override
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
Definition: CImage.cpp:639
void setOriginTopLeft(bool val)
Changes the property of the image stating if the top-left corner (vs.
Definition: CImage.cpp:1239
unsigned __int32 uint32_t
Definition: rptypes.h:47
void enter(const char *func_name)
Start of a named section.
Definition: CTimeLogger.h:117
static const std::string & getImagesPathBase()
By default, ".".
Definition: CImage.cpp:55
#define ASSERTMSG_(f, __ERROR_MSG)
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3546
Used in mrpt::utils::CImage.
Definition: exceptions.h:32
GLfloat GLfloat p
Definition: glext.h:6305
void line(int x0, int y0, int x1, int y1, const mrpt::utils::TColor color, unsigned int width=1, TPenStyle penStyle=psSolid) override
Draws a line.
Definition: CImage.cpp:1304
void * img
The internal IplImage pointer to the actual image content.
Definition: CImage.h:1077
void getExternalStorageFileAbsolutePath(std::string &out_path) const
Only if isExternallyStored() returns true.
Definition: CImage.cpp:1972
void grayscaleInPlace()
Replaces the image with a grayscale version of it.
Definition: CImage.cpp:1061
void joinImagesHorz(const CImage &im1, const CImage &im2)
Joins two images side-by-side horizontally.
Definition: CImage.cpp:2451
void filterGaussian(CImage &out_img, int W=3, int H=3) const
Filter the image with a Gaussian filter with a window size WxH, replacing "this" image by the filtere...
Definition: CImage.cpp:2181
TImageSize getSize() const
Return the size of the image.
Definition: CImage.h:649
struct mxArray_tag mxArray
Forward declaration for mxArray (avoid #including as much as possible to speed up compiling) ...
Definition: CSerializable.h:19
Structure to hold the parameters of a pinhole camera model.
Definition: TCamera.h:32
void getAsRGBMatrices(mrpt::math::CMatrixFloat &outMatrixR, mrpt::math::CMatrixFloat &outMatrixG, mrpt::math::CMatrixFloat &outMatrixB, bool doResize=true, int x_min=0, int y_min=0, int x_max=-1, int y_max=-1) const
Returns the image as RGB matrices with pixel values in the range [0,1].
Definition: CImage.cpp:1681
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
Definition: os.cpp:355
std::string getExternalStorageFileAbsolutePath() const
Only if isExternallyStored() returns true.
Definition: CImage.h:792
void loadFromStreamAsJPEG(CStream &in)
Reads the image from a binary stream containing a binary jpeg file.



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019