Visual Servoing Platform  version 3.6.1 under development (2023-12-01)
vpImage.h
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Image handling.
32  */
33 
39 #ifndef vpImage_H
40 #define vpImage_H
41 
42 #include <visp3/core/vpConfig.h>
43 #include <visp3/core/vpDebug.h>
44 #include <visp3/core/vpEndian.h>
45 #include <visp3/core/vpException.h>
46 #include <visp3/core/vpImageException.h>
47 #include <visp3/core/vpImagePoint.h>
48 #include <visp3/core/vpRGBa.h>
49 #include <visp3/core/vpRGBf.h>
50 
51 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
52 #include <visp3/core/vpThread.h>
53 #endif
54 
55 #include <fstream>
56 #include <iomanip> // std::setw
57 #include <iostream>
58 #include <math.h>
59 #include <string.h>
60 
61 // Visual Studio 2010 or previous is missing inttypes.h
62 #if defined(_MSC_VER) && (_MSC_VER < 1700)
63 typedef long long int64_t;
64 typedef unsigned short uint16_t;
65 #else
66 #include <inttypes.h>
67 #endif
68 
69 class vpDisplay;
70 
121 // Ref: http://en.cppreference.com/w/cpp/language/friend#Template_friends
122 template <class Type> class vpImage; // forward declare to make function declaration possible
123 
124 // declarations
125 template <class Type> std::ostream &operator<<(std::ostream &, const vpImage<Type> &);
126 
127 std::ostream &operator<<(std::ostream &, const vpImage<unsigned char> &);
128 std::ostream &operator<<(std::ostream &, const vpImage<char> &);
129 std::ostream &operator<<(std::ostream &, const vpImage<float> &);
130 std::ostream &operator<<(std::ostream &, const vpImage<double> &);
131 
132 template <class Type> void swap(vpImage<Type> &first, vpImage<Type> &second);
133 
134 template <class Type> class vpImage
135 {
136  friend class vpImageConvert;
137 
138 public:
139  Type *bitmap;
141 
149  vpImage(unsigned int height, unsigned int width);
151  vpImage(unsigned int height, unsigned int width, Type value);
153  vpImage(Type *const array, unsigned int height, unsigned int width, bool copyData = false);
155  virtual ~vpImage();
156 
159 
160  // destructor
161  void destroy();
162 
163  // Returns a new image that's double size of the current image
165 
173  inline unsigned int getCols() const { return width; }
182  inline unsigned int getHeight() const { return height; }
183 
184  // Return the maximum value within the bitmap
185  Type getMaxValue(bool onlyFiniteVal = true) const;
186  // Return the mean value of the bitmap
187  Type getMeanValue() const;
188  // Return the minumum value within the bitmap
189  Type getMinValue(bool onlyFiniteVal = true) const;
190  // Look for the minumum and the maximum value within the bitmap
191  void getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal = true) const;
192  // Look for the minumum and the maximum value within the bitmap and get their location
193  void getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal = nullptr, Type *maxVal = nullptr) const;
194 
203  inline unsigned int getNumberOfPixel() const { return npixels; }
204 
212  inline unsigned int getRows() const { return height; }
213 
221  inline unsigned int getSize() const { return width * height; }
222 
223  // Gets the value of a pixel at a location.
224  Type getValue(unsigned int i, unsigned int j) const;
225  // Gets the value of a pixel at a location with bilinear interpolation.
226  Type getValue(double i, double j) const;
227  // Gets the value of a pixel at a location with bilinear interpolation.
228  Type getValue(const vpImagePoint &ip) const;
229 
230  // Get image pixels sum
231  double getSum() const;
232 
240  inline unsigned int getWidth() const { return width; }
241 
242  // Returns a new image that's half size of the current image
243  void halfSizeImage(vpImage<Type> &res) const;
244 
246  void init(unsigned int height, unsigned int width);
248  void init(unsigned int height, unsigned int width, Type value);
250  void init(Type *const array, unsigned int height, unsigned int width, bool copyData = false);
251  void insert(const vpImage<Type> &src, const vpImagePoint &topLeft);
252 
253  //------------------------------------------------------------------
254  // Access to the image
255 
257  inline Type *operator[](unsigned int i) { return row[i]; }
258  inline Type *operator[](int i) { return row[i]; }
259 
261  inline const Type *operator[](unsigned int i) const { return row[i]; }
262  inline const Type *operator[](int i) const { return row[i]; }
263 
270  inline Type operator()(unsigned int i, unsigned int j) const { return bitmap[i * width + j]; }
271 
276  inline void operator()(unsigned int i, unsigned int j, const Type &v) { bitmap[i * width + j] = v; }
277 
288  inline Type operator()(const vpImagePoint &ip) const
289  {
290  unsigned int i = (unsigned int)ip.get_i();
291  unsigned int j = (unsigned int)ip.get_j();
292 
293  return bitmap[i * width + j];
294  }
295 
304  inline void operator()(const vpImagePoint &ip, const Type &v)
305  {
306  unsigned int i = (unsigned int)ip.get_i();
307  unsigned int j = (unsigned int)ip.get_j();
308 
309  bitmap[i * width + j] = v;
310  }
311 
313 
316 
317  vpImage<Type> &operator=(const Type &v);
318  bool operator==(const vpImage<Type> &I) const;
319  bool operator!=(const vpImage<Type> &I) const;
320  friend std::ostream &operator<< <>(std::ostream &s, const vpImage<Type> &I);
321  friend std::ostream &operator<<(std::ostream &s, const vpImage<unsigned char> &I);
322  friend std::ostream &operator<<(std::ostream &s, const vpImage<char> &I);
323  friend std::ostream &operator<<(std::ostream &s, const vpImage<float> &I);
324  friend std::ostream &operator<<(std::ostream &s, const vpImage<double> &I);
325 
326  // Perform a look-up table transformation
327  void performLut(const Type(&lut)[256], unsigned int nbThreads = 1);
328 
329  // Returns a new image that's a quarter size of the current image
330  void quarterSizeImage(vpImage<Type> &res) const;
331 
332  // set the size of the image without initializing it.
333  void resize(unsigned int h, unsigned int w);
334  // set the size of the image and initialize it.
335  void resize(unsigned int h, unsigned int w, const Type &val);
336 
337  void sub(const vpImage<Type> &B, vpImage<Type> &C) const;
338  void sub(const vpImage<Type> &A, const vpImage<Type> &B, vpImage<Type> &C) const;
339  void subsample(unsigned int v_scale, unsigned int h_scale, vpImage<Type> &sampled) const;
340 
341  friend void swap<>(vpImage<Type> &first, vpImage<Type> &second);
342 
344 
345 private:
346  unsigned int npixels;
347  unsigned int width;
348  unsigned int height;
349  Type **row;
350  bool hasOwnership;
351 };
352 
353 template <class Type> std::ostream &operator<<(std::ostream &s, const vpImage<Type> &I)
354 {
355  if (I.bitmap == nullptr) {
356  return s;
357  }
358 
359  for (unsigned int i = 0; i < I.getHeight(); i++) {
360  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
361  s << I[i][j] << " ";
362  }
363 
364  // We don't add " " after the last column element
365  s << I[i][I.getWidth() - 1];
366 
367  // We don't add a \n character at the end of the last row line
368  if (i < I.getHeight() - 1) {
369  s << std::endl;
370  }
371  }
372 
373  return s;
374 }
375 
376 inline std::ostream &operator<<(std::ostream &s, const vpImage<unsigned char> &I)
377 {
378  if (I.bitmap == nullptr) {
379  return s;
380  }
381 
382  std::ios_base::fmtflags original_flags = s.flags();
383 
384  for (unsigned int i = 0; i < I.getHeight(); i++) {
385  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
386  s << std::setw(3) << static_cast<unsigned>(I[i][j]) << " ";
387  }
388 
389  // We don't add " " after the last column element
390  s << std::setw(3) << static_cast<unsigned>(I[i][I.getWidth() - 1]);
391 
392  // We don't add a \n character at the end of the last row line
393  if (i < I.getHeight() - 1) {
394  s << std::endl;
395  }
396  }
397 
398  s.flags(original_flags); // restore s to standard state
399  return s;
400 }
401 
402 inline std::ostream &operator<<(std::ostream &s, const vpImage<char> &I)
403 {
404  if (I.bitmap == nullptr) {
405  return s;
406  }
407 
408  std::ios_base::fmtflags original_flags = s.flags();
409 
410  for (unsigned int i = 0; i < I.getHeight(); i++) {
411  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
412  s << std::setw(4) << static_cast<int>(I[i][j]) << " ";
413  }
414 
415  // We don't add " " after the last column element
416  s << std::setw(4) << static_cast<int>(I[i][I.getWidth() - 1]);
417 
418  // We don't add a \n character at the end of the last row line
419  if (i < I.getHeight() - 1) {
420  s << std::endl;
421  }
422  }
423 
424  s.flags(original_flags); // restore s to standard state
425  return s;
426 }
427 
428 inline std::ostream &operator<<(std::ostream &s, const vpImage<float> &I)
429 {
430  if (I.bitmap == nullptr) {
431  return s;
432  }
433 
434  std::ios_base::fmtflags original_flags = s.flags();
435  s.precision(9); // http://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
436 
437  for (unsigned int i = 0; i < I.getHeight(); i++) {
438  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
439  s << I[i][j] << " ";
440  }
441 
442  // We don't add " " after the last column element
443  s << I[i][I.getWidth() - 1];
444 
445  // We don't add a \n character at the end of the last row line
446  if (i < I.getHeight() - 1) {
447  s << std::endl;
448  }
449  }
450 
451  s.flags(original_flags); // restore s to standard state
452  return s;
453 }
454 
455 inline std::ostream &operator<<(std::ostream &s, const vpImage<double> &I)
456 {
457  if (I.bitmap == nullptr) {
458  return s;
459  }
460 
461  std::ios_base::fmtflags original_flags = s.flags();
462  s.precision(17); // http://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
463 
464  for (unsigned int i = 0; i < I.getHeight(); i++) {
465  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
466  s << I[i][j] << " ";
467  }
468 
469  // We don't add " " after the last column element
470  s << I[i][I.getWidth() - 1];
471 
472  // We don't add a \n character at the end of the last row line
473  if (i < I.getHeight() - 1) {
474  s << std::endl;
475  }
476  }
477 
478  s.flags(original_flags); // restore s to standard state
479  return s;
480 }
481 
482 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
483 namespace
484 {
485 struct vpImageLut_Param_t
486 {
487  unsigned int m_start_index;
488  unsigned int m_end_index;
489 
490  unsigned char m_lut[256];
491  unsigned char *m_bitmap;
492 
493  vpImageLut_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(nullptr) { }
494 
495  vpImageLut_Param_t(unsigned int start_index, unsigned int end_index, unsigned char *bitmap)
496  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
497  { }
498 };
499 
500 vpThread::Return performLutThread(vpThread::Args args)
501 {
502  vpImageLut_Param_t *imageLut_param = static_cast<vpImageLut_Param_t *>(args);
503  unsigned int start_index = imageLut_param->m_start_index;
504  unsigned int end_index = imageLut_param->m_end_index;
505 
506  unsigned char *bitmap = imageLut_param->m_bitmap;
507 
508  unsigned char *ptrStart = bitmap + start_index;
509  unsigned char *ptrEnd = bitmap + end_index;
510  unsigned char *ptrCurrent = ptrStart;
511 
512  // while(ptrCurrent != ptrEnd) {
513  // *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
514  // ++ptrCurrent;
515  // }
516 
517  if (end_index - start_index >= 8) {
518  // Unroll loop version
519  for (; ptrCurrent <= ptrEnd - 8;) {
520  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
521  ++ptrCurrent;
522 
523  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
524  ++ptrCurrent;
525 
526  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
527  ++ptrCurrent;
528 
529  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
530  ++ptrCurrent;
531 
532  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
533  ++ptrCurrent;
534 
535  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
536  ++ptrCurrent;
537 
538  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
539  ++ptrCurrent;
540 
541  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
542  ++ptrCurrent;
543  }
544  }
545 
546  for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
547  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
548  }
549 
550  return 0;
551 }
552 
553 struct vpImageLutRGBa_Param_t
554 {
555  unsigned int m_start_index;
556  unsigned int m_end_index;
557 
558  vpRGBa m_lut[256];
559  unsigned char *m_bitmap;
560 
561  vpImageLutRGBa_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(nullptr) { }
562 
563  vpImageLutRGBa_Param_t(unsigned int start_index, unsigned int end_index, unsigned char *bitmap)
564  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
565  { }
566 };
567 
568 vpThread::Return performLutRGBaThread(vpThread::Args args)
569 {
570  vpImageLutRGBa_Param_t *imageLut_param = static_cast<vpImageLutRGBa_Param_t *>(args);
571  unsigned int start_index = imageLut_param->m_start_index;
572  unsigned int end_index = imageLut_param->m_end_index;
573 
574  unsigned char *bitmap = imageLut_param->m_bitmap;
575 
576  unsigned char *ptrStart = bitmap + start_index * 4;
577  unsigned char *ptrEnd = bitmap + end_index * 4;
578  unsigned char *ptrCurrent = ptrStart;
579 
580  if (end_index - start_index >= 4 * 2) {
581  // Unroll loop version
582  for (; ptrCurrent <= ptrEnd - 4 * 2;) {
583  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
584  ptrCurrent++;
585  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
586  ptrCurrent++;
587  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
588  ptrCurrent++;
589  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
590  ptrCurrent++;
591 
592  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
593  ptrCurrent++;
594  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
595  ptrCurrent++;
596  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
597  ptrCurrent++;
598  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
599  ptrCurrent++;
600  }
601  }
602 
603  while (ptrCurrent != ptrEnd) {
604  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
605  ptrCurrent++;
606 
607  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
608  ptrCurrent++;
609 
610  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
611  ptrCurrent++;
612 
613  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
614  ptrCurrent++;
615  }
616 
617  return 0;
618 }
619 } // namespace
620 #endif
621 
625 template <class Type> void vpImage<Type>::init(unsigned int h, unsigned int w, Type value)
626 {
627  init(h, w);
628 
629  // for (unsigned int i = 0; i < npixels; i++)
630  // bitmap[i] = value;
631  std::fill(bitmap, bitmap + npixels, value);
632 }
633 
637 template <class Type> void vpImage<Type>::init(unsigned int h, unsigned int w)
638 {
639  if (h != this->height) {
640  if (row != nullptr) {
641  vpDEBUG_TRACE(10, "Destruction row[]");
642  delete[] row;
643  row = nullptr;
644  }
645  }
646 
647  if ((h != this->height) || (w != this->width)) {
648  if (bitmap != nullptr) {
649  vpDEBUG_TRACE(10, "Destruction bitmap[]");
650  if (hasOwnership) {
651  delete[] bitmap;
652  }
653  bitmap = nullptr;
654  }
655  }
656 
657  this->width = w;
658  this->height = h;
659 
660  npixels = width * height;
661 
662  if (bitmap == nullptr) {
663  bitmap = new Type[npixels];
664  hasOwnership = true;
665  }
666 
667  if (bitmap == nullptr) {
668  throw(vpException(vpException::memoryAllocationError, "cannot allocate bitmap "));
669  }
670 
671  if (row == nullptr)
672  row = new Type *[height];
673  if (row == nullptr) {
674  throw(vpException(vpException::memoryAllocationError, "cannot allocate row "));
675  }
676 
677  for (unsigned int i = 0; i < height; i++)
678  row[i] = bitmap + i * width;
679 }
680 
684 template <class Type> void vpImage<Type>::init(Type *const array, unsigned int h, unsigned int w, bool copyData)
685 {
686  if (h != this->height) {
687  if (row != nullptr) {
688  delete[] row;
689  row = nullptr;
690  }
691  }
692 
693  // Delete bitmap if copyData==false, otherwise only if the dimension differs
694  if ((copyData && ((h != this->height) || (w != this->width))) || !copyData) {
695  if (bitmap != nullptr) {
696  if (hasOwnership) {
697  delete[] bitmap;
698  }
699  bitmap = nullptr;
700  }
701  }
702 
703  hasOwnership = copyData;
704  this->width = w;
705  this->height = h;
706 
707  npixels = width * height;
708 
709  if (copyData) {
710  if (bitmap == nullptr)
711  bitmap = new Type[npixels];
712 
713  if (bitmap == nullptr) {
714  throw(vpException(vpException::memoryAllocationError, "cannot allocate bitmap "));
715  }
716 
717  // Copy the image data
718  memcpy(static_cast<void *>(bitmap), static_cast<void *>(array), (size_t)(npixels * sizeof(Type)));
719  }
720  else {
721  // Copy the address of the array in the bitmap
722  bitmap = array;
723  }
724 
725  if (row == nullptr)
726  row = new Type *[height];
727  if (row == nullptr) {
728  throw(vpException(vpException::memoryAllocationError, "cannot allocate row "));
729  }
730 
731  for (unsigned int i = 0; i < height; i++) {
732  row[i] = bitmap + i * width;
733  }
734 }
735 
739 template <class Type>
740 vpImage<Type>::vpImage(unsigned int h, unsigned int w)
741  : bitmap(nullptr), display(nullptr), npixels(0), width(0), height(0), row(nullptr), hasOwnership(true)
742 {
743  init(h, w, 0);
744 }
745 
749 template <class Type>
750 vpImage<Type>::vpImage(unsigned int h, unsigned int w, Type value)
751  : bitmap(nullptr), display(nullptr), npixels(0), width(0), height(0), row(nullptr), hasOwnership(true)
752 {
753  init(h, w, value);
754 }
755 
759 template <class Type>
760 vpImage<Type>::vpImage(Type *const array, unsigned int h, unsigned int w, bool copyData)
761  : bitmap(nullptr), display(nullptr), npixels(0), width(0), height(0), row(nullptr), hasOwnership(true)
762 {
763  init(array, h, w, copyData);
764 }
765 
769 template <class Type>
770 vpImage<Type>::vpImage() : bitmap(nullptr), display(nullptr), npixels(0), width(0), height(0), row(nullptr), hasOwnership(true)
771 { }
772 
793 template <class Type> void vpImage<Type>::resize(unsigned int h, unsigned int w) { init(h, w); }
794 
814 template <class Type> void vpImage<Type>::resize(unsigned int h, unsigned int w, const Type &val) { init(h, w, val); }
815 
822 template <class Type> void vpImage<Type>::destroy()
823 {
824  // vpERROR_TRACE("Deallocate ");
825 
826  if (bitmap != nullptr) {
827  // vpERROR_TRACE("Deallocate bitmap memory %p",bitmap);
828  // vpDEBUG_TRACE(20,"Deallocate bitmap memory %p",bitmap);
829  if (hasOwnership) {
830  delete[] bitmap;
831  }
832  bitmap = nullptr;
833  }
834 
835  if (row != nullptr) {
836  // vpERROR_TRACE("Deallocate row memory %p",row);
837  // vpDEBUG_TRACE(20,"Deallocate row memory %p",row);
838  delete[] row;
839  row = nullptr;
840  }
841 }
842 
849 template <class Type> vpImage<Type>::~vpImage() { destroy(); }
850 
854 template <class Type>
856  : bitmap(nullptr), display(nullptr), npixels(0), width(0), height(0), row(nullptr), hasOwnership(true)
857 {
858  resize(I.getHeight(), I.getWidth());
859  memcpy(static_cast<void *>(bitmap), static_cast<void *>(I.bitmap), I.npixels * sizeof(Type));
860 }
861 
865 template <class Type>
867  : bitmap(I.bitmap), display(I.display), npixels(I.npixels), width(I.width), height(I.height), row(I.row),
868  hasOwnership(I.hasOwnership)
869 {
870  I.bitmap = nullptr;
871  I.display = nullptr;
872  I.npixels = 0;
873  I.width = 0;
874  I.height = 0;
875  I.row = nullptr;
876  I.hasOwnership = false;
877 }
878 
886 template <class Type> Type vpImage<Type>::getMaxValue(bool onlyFiniteVal) const
887 {
888  if (npixels == 0)
889  throw(vpException(vpException::fatalError, "Cannot compute maximum value of an empty image"));
890  Type m = bitmap[0];
891  for (unsigned int i = 0; i < npixels; i++) {
892  if (bitmap[i] > m) {
893  m = bitmap[i];
894  }
895  }
896  (void)onlyFiniteVal;
897  return m;
898 }
899 
908 template <> inline double vpImage<double>::getMaxValue(bool onlyFiniteVal) const
909 {
910  if (npixels == 0)
911  throw(vpException(vpException::fatalError, "Cannot compute maximum value of an empty image"));
912  double m = bitmap[0];
913  if (onlyFiniteVal) {
914  for (unsigned int i = 0; i < npixels; i++) {
915  if (bitmap[i] > m && vpMath::isFinite(bitmap[i]))
916  m = bitmap[i];
917  }
918  }
919  else {
920  for (unsigned int i = 0; i < npixels; i++) {
921  if (bitmap[i] > m)
922  m = bitmap[i];
923  }
924  }
925  return m;
926 }
927 
936 template <> inline float vpImage<float>::getMaxValue(bool onlyFiniteVal) const
937 {
938  if (npixels == 0)
939  throw(vpException(vpException::fatalError, "Cannot compute maximum value of an empty image"));
940  float m = bitmap[0];
941  if (onlyFiniteVal) {
942  for (unsigned int i = 0; i < npixels; i++) {
943  if (bitmap[i] > m && vpMath::isFinite(bitmap[i]))
944  m = bitmap[i];
945  }
946  }
947  else {
948  for (unsigned int i = 0; i < npixels; i++) {
949  if (bitmap[i] > m)
950  m = bitmap[i];
951  }
952  }
953  return m;
954 }
955 
959 template <class Type> Type vpImage<Type>::getMeanValue() const
960 {
961  if ((height == 0) || (width == 0))
962  return 0.0;
963 
964  return getSum() / (height * width);
965 }
966 
974 template <class Type> Type vpImage<Type>::getMinValue(bool onlyFiniteVal) const
975 {
976  if (npixels == 0)
977  throw(vpException(vpException::fatalError, "Cannot compute minimum value of an empty image"));
978  Type m = bitmap[0];
979  for (unsigned int i = 0; i < npixels; i++) {
980  if (bitmap[i] < m) {
981  m = bitmap[i];
982  }
983  }
984  (void)onlyFiniteVal;
985  return m;
986 }
987 
996 template <> inline double vpImage<double>::getMinValue(bool onlyFiniteVal) const
997 {
998  if (npixels == 0)
999  throw(vpException(vpException::fatalError, "Cannot compute minimum value of an empty image"));
1000  double m = bitmap[0];
1001  if (onlyFiniteVal) {
1002  for (unsigned int i = 0; i < npixels; i++)
1003  if (bitmap[i] < m && vpMath::isFinite(bitmap[i]))
1004  m = bitmap[i];
1005  }
1006  else {
1007  for (unsigned int i = 0; i < npixels; i++)
1008  if (bitmap[i] < m)
1009  m = bitmap[i];
1010  }
1011  return m;
1012 }
1013 
1022 template <> inline float vpImage<float>::getMinValue(bool onlyFiniteVal) const
1023 {
1024  if (npixels == 0)
1025  throw(vpException(vpException::fatalError, "Cannot compute minimum value of an empty image"));
1026  float m = bitmap[0];
1027  if (onlyFiniteVal) {
1028  for (unsigned int i = 0; i < npixels; i++)
1029  if (bitmap[i] < m && vpMath::isFinite(bitmap[i]))
1030  m = bitmap[i];
1031  }
1032  else {
1033  for (unsigned int i = 0; i < npixels; i++)
1034  if (bitmap[i] < m)
1035  m = bitmap[i];
1036  }
1037  return m;
1038 }
1039 
1050 template <class Type> void vpImage<Type>::getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal) const
1051 {
1052  if (npixels == 0)
1053  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1054 
1055  min = max = bitmap[0];
1056  for (unsigned int i = 0; i < npixels; i++) {
1057  if (bitmap[i] < min)
1058  min = bitmap[i];
1059  if (bitmap[i] > max)
1060  max = bitmap[i];
1061  }
1062  (void)onlyFiniteVal;
1063 }
1064 
1076 template <> inline void vpImage<double>::getMinMaxValue(double &min, double &max, bool onlyFiniteVal) const
1077 {
1078  if (npixels == 0)
1079  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1080 
1081  min = max = bitmap[0];
1082  if (onlyFiniteVal) {
1083  for (unsigned int i = 0; i < npixels; i++) {
1084  if (vpMath::isFinite(bitmap[i])) {
1085  if (bitmap[i] < min)
1086  min = bitmap[i];
1087  if (bitmap[i] > max)
1088  max = bitmap[i];
1089  }
1090  }
1091  }
1092  else {
1093  for (unsigned int i = 0; i < npixels; i++) {
1094  if (bitmap[i] < min)
1095  min = bitmap[i];
1096  if (bitmap[i] > max)
1097  max = bitmap[i];
1098  }
1099  }
1100 }
1101 
1113 template <> inline void vpImage<float>::getMinMaxValue(float &min, float &max, bool onlyFiniteVal) const
1114 {
1115  if (npixels == 0)
1116  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1117 
1118  min = max = bitmap[0];
1119  if (onlyFiniteVal) {
1120  for (unsigned int i = 0; i < npixels; i++) {
1121  if (vpMath::isFinite(bitmap[i])) {
1122  if (bitmap[i] < min)
1123  min = bitmap[i];
1124  if (bitmap[i] > max)
1125  max = bitmap[i];
1126  }
1127  }
1128  }
1129  else {
1130  for (unsigned int i = 0; i < npixels; i++) {
1131  if (bitmap[i] < min)
1132  min = bitmap[i];
1133  if (bitmap[i] > max)
1134  max = bitmap[i];
1135  }
1136  }
1137 }
1138 
1149 template <> inline void vpImage<vpRGBf>::getMinMaxValue(vpRGBf &min, vpRGBf &max, bool onlyFiniteVal) const
1150 {
1151  if (npixels == 0)
1152  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1153 
1154  min = max = bitmap[0];
1155  if (onlyFiniteVal) {
1156  for (unsigned int i = 0; i < npixels; i++) {
1157  if (vpMath::isFinite(bitmap[i].R)) {
1158  if (bitmap[i].R < min.R)
1159  min.R = bitmap[i].R;
1160  if (bitmap[i].R > max.R)
1161  max.R = bitmap[i].R;
1162  }
1163  if (vpMath::isFinite(bitmap[i].G)) {
1164  if (bitmap[i].G < min.G)
1165  min.G = bitmap[i].G;
1166  if (bitmap[i].G > max.G)
1167  max.G = bitmap[i].G;
1168  }
1169  if (vpMath::isFinite(bitmap[i].B)) {
1170  if (bitmap[i].B < min.B)
1171  min.B = bitmap[i].B;
1172  if (bitmap[i].B > max.B)
1173  max.B = bitmap[i].B;
1174  }
1175  }
1176  }
1177  else {
1178  for (unsigned int i = 0; i < npixels; i++) {
1179  if (bitmap[i].R < min.R)
1180  min.R = bitmap[i].R;
1181  if (bitmap[i].R > max.R)
1182  max.R = bitmap[i].R;
1183 
1184  if (bitmap[i].G < min.G)
1185  min.G = bitmap[i].G;
1186  if (bitmap[i].G > max.G)
1187  max.G = bitmap[i].G;
1188 
1189  if (bitmap[i].B < min.B)
1190  min.B = bitmap[i].B;
1191  if (bitmap[i].B > max.B)
1192  max.B = bitmap[i].B;
1193  }
1194  }
1195 }
1196 
1218 template <class Type>
1219 void vpImage<Type>::getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal, Type *maxVal) const
1220 {
1221  if (npixels == 0)
1222  throw(vpException(vpException::fatalError, "Cannot get location of minimum/maximum "
1223  "values of an empty image"));
1224 
1225  Type min = bitmap[0], max = bitmap[0];
1226  vpImagePoint minLoc_, maxLoc_;
1227  for (unsigned int i = 0; i < height; i++) {
1228  for (unsigned int j = 0; j < width; j++) {
1229  if (row[i][j] < min) {
1230  min = row[i][j];
1231  minLoc_.set_ij(i, j);
1232  }
1233 
1234  if (row[i][j] > max) {
1235  max = row[i][j];
1236  maxLoc_.set_ij(i, j);
1237  }
1238  }
1239  }
1240 
1241  if (minLoc != nullptr)
1242  *minLoc = minLoc_;
1243 
1244  if (maxLoc != nullptr)
1245  *maxLoc = maxLoc_;
1246 
1247  if (minVal != nullptr)
1248  *minVal = min;
1249 
1250  if (maxVal != nullptr)
1251  *maxVal = max;
1252 }
1253 
1258 {
1259  swap(*this, other);
1260  // Swap back display pointer if it was not null
1261  // vpImage<unsigned char> I2(480, 640);
1262  // vpDisplayX d(I2);
1263  // I2 = I1; //copy only the data
1264  if (other.display != nullptr)
1265  display = other.display;
1266 
1267  return *this;
1268 }
1269 
1276 template <class Type> vpImage<Type> &vpImage<Type>::operator=(const Type &v)
1277 {
1278  for (unsigned int i = 0; i < npixels; i++)
1279  bitmap[i] = v;
1280 
1281  return *this;
1282 }
1283 
1289 template <class Type> bool vpImage<Type>::operator==(const vpImage<Type> &I) const
1290 {
1291  if (this->width != I.getWidth())
1292  return false;
1293  if (this->height != I.getHeight())
1294  return false;
1295 
1296  // printf("wxh: %dx%d bitmap: %p I.bitmap %p\n", width, height, bitmap,
1297  // I.bitmap);
1298  for (unsigned int i = 0; i < npixels; i++) {
1299  if (bitmap[i] != I.bitmap[i]) {
1300  // std::cout << "differ for pixel " << i << " (" << i%this->height
1301  // << ", " << i - i%this->height << ")" << std::endl;
1302  return false;
1303  }
1304  }
1305  return true;
1306 }
1312 template <class Type> bool vpImage<Type>::operator!=(const vpImage<Type> &I) const { return !(*this == I); }
1313 
1339 template <class Type> vpImage<Type> vpImage<Type>::operator-(const vpImage<Type> &B) const
1340 {
1341  vpImage<Type> C;
1342  sub(*this, B, C);
1343  return C;
1344 }
1345 
1357 template <class Type> void vpImage<Type>::insert(const vpImage<Type> &src, const vpImagePoint &topLeft)
1358 {
1359  int itl = (int)topLeft.get_i();
1360  int jtl = (int)topLeft.get_j();
1361 
1362  int dest_ibegin = 0;
1363  int dest_jbegin = 0;
1364  int src_ibegin = 0;
1365  int src_jbegin = 0;
1366  int dest_w = (int)this->getWidth();
1367  int dest_h = (int)this->getHeight();
1368  int src_w = (int)src.getWidth();
1369  int src_h = (int)src.getHeight();
1370  int wsize = (int)src.getWidth();
1371  int hsize = (int)src.getHeight();
1372 
1373  if (itl >= dest_h || jtl >= dest_w)
1374  return;
1375 
1376  if (itl < 0)
1377  src_ibegin = -itl;
1378  else
1379  dest_ibegin = itl;
1380 
1381  if (jtl < 0)
1382  src_jbegin = -jtl;
1383  else
1384  dest_jbegin = jtl;
1385 
1386  if (src_w - src_jbegin > dest_w - dest_jbegin)
1387  wsize = dest_w - dest_jbegin;
1388  else
1389  wsize = src_w - src_jbegin;
1390 
1391  if (src_h - src_ibegin > dest_h - dest_ibegin)
1392  hsize = dest_h - dest_ibegin;
1393  else
1394  hsize = src_h - src_ibegin;
1395 
1396  for (int i = 0; i < hsize; i++) {
1397  Type *srcBitmap = src.bitmap + ((src_ibegin + i) * src_w + src_jbegin);
1398  Type *destBitmap = this->bitmap + ((dest_ibegin + i) * dest_w + dest_jbegin);
1399 
1400  memcpy(static_cast<void *>(destBitmap), static_cast<void *>(srcBitmap), (size_t)wsize * sizeof(Type));
1401  }
1402 }
1403 
1434 template <class Type> void vpImage<Type>::halfSizeImage(vpImage<Type> &res) const
1435 {
1436  unsigned int h = height / 2;
1437  unsigned int w = width / 2;
1438  res.resize(h, w);
1439  for (unsigned int i = 0; i < h; i++)
1440  for (unsigned int j = 0; j < w; j++)
1441  res[i][j] = (*this)[i << 1][j << 1];
1442 }
1443 
1461 template <class Type>
1462 void vpImage<Type>::subsample(unsigned int v_scale, unsigned int h_scale, vpImage<Type> &sampled) const
1463 {
1464  if (v_scale == 1 && h_scale == 1) {
1465  sampled = (*this);
1466  return;
1467  }
1468  unsigned int h = height / v_scale;
1469  unsigned int w = width / h_scale;
1470  sampled.resize(h, w);
1471  for (unsigned int i = 0; i < h; i++)
1472  for (unsigned int j = 0; j < w; j++)
1473  sampled[i][j] = (*this)[i * v_scale][j * h_scale];
1474 }
1475 
1498 template <class Type> void vpImage<Type>::quarterSizeImage(vpImage<Type> &res) const
1499 {
1500  unsigned int h = height / 4;
1501  unsigned int w = width / 4;
1502  res.resize(h, w);
1503  for (unsigned int i = 0; i < h; i++)
1504  for (unsigned int j = 0; j < w; j++)
1505  res[i][j] = (*this)[i << 2][j << 2];
1506 }
1507 
1540 template <class Type> void vpImage<Type>::doubleSizeImage(vpImage<Type> &res)
1541 {
1542  int h = height * 2;
1543  int w = width * 2;
1544 
1545  res.resize(h, w);
1546 
1547  for (int i = 0; i < h; i++)
1548  for (int j = 0; j < w; j++)
1549  res[i][j] = (*this)[i >> 1][j >> 1];
1550 
1551  /*
1552  A B C
1553  E F G
1554  H I J
1555  A C H J are pixels from original image
1556  B E G I are interpolated pixels
1557  */
1558 
1559  // interpolate pixels B and I
1560  for (int i = 0; i < h; i += 2)
1561  for (int j = 1; j < w - 1; j += 2)
1562  res[i][j] = (Type)(0.5 * ((*this)[i >> 1][j >> 1] + (*this)[i >> 1][(j >> 1) + 1]));
1563 
1564  // interpolate pixels E and G
1565  for (int i = 1; i < h - 1; i += 2)
1566  for (int j = 0; j < w; j += 2)
1567  res[i][j] = (Type)(0.5 * ((*this)[i >> 1][j >> 1] + (*this)[(i >> 1) + 1][j >> 1]));
1568 
1569  // interpolate pixel F
1570  for (int i = 1; i < h - 1; i += 2)
1571  for (int j = 1; j < w - 1; j += 2)
1572  res[i][j] = (Type)(0.25 * ((*this)[i >> 1][j >> 1] + (*this)[i >> 1][(j >> 1) + 1] +
1573  (*this)[(i >> 1) + 1][j >> 1] + (*this)[(i >> 1) + 1][(j >> 1) + 1]));
1574 }
1575 
1588 template <class Type> inline Type vpImage<Type>::getValue(unsigned int i, unsigned int j) const
1589 {
1590  if (i >= height || j >= width) {
1591  throw(vpException(vpImageException::notInTheImage, "Pixel outside the image"));
1592  }
1593 
1594  return row[i][j];
1595 }
1596 
1613 template <class Type> Type vpImage<Type>::getValue(double i, double j) const
1614 {
1615  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1616  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1617  }
1618  if (height * width == 0) {
1619  throw vpException(vpImageException::notInitializedError, "Empty image!");
1620  }
1621 
1622  unsigned int iround = static_cast<unsigned int>(floor(i));
1623  unsigned int jround = static_cast<unsigned int>(floor(j));
1624 
1625  double rratio = i - static_cast<double>(iround);
1626  double cratio = j - static_cast<double>(jround);
1627 
1628  double rfrac = 1.0 - rratio;
1629  double cfrac = 1.0 - cratio;
1630 
1631  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1632  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1633 
1634  double value =
1635  (static_cast<double>(row[iround][jround]) * rfrac + static_cast<double>(row[iround_1][jround]) * rratio) * cfrac +
1636  (static_cast<double>(row[iround][jround_1]) * rfrac + static_cast<double>(row[iround_1][jround_1]) * rratio) *
1637  cratio;
1638 
1639  return static_cast<Type>(vpMath::round(value));
1640 }
1641 
1645 template <> inline double vpImage<double>::getValue(double i, double j) const
1646 {
1647  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1648  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1649  }
1650  if (height * width == 0) {
1651  throw vpException(vpImageException::notInitializedError, "Empty image!");
1652  }
1653 
1654  unsigned int iround = static_cast<unsigned int>(floor(i));
1655  unsigned int jround = static_cast<unsigned int>(floor(j));
1656 
1657  double rratio = i - static_cast<double>(iround);
1658  double cratio = j - static_cast<double>(jround);
1659 
1660  double rfrac = 1.0 - rratio;
1661  double cfrac = 1.0 - cratio;
1662 
1663  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1664  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1665 
1666  return (row[iround][jround] * rfrac + row[iround_1][jround] * rratio) * cfrac +
1667  (row[iround][jround_1] * rfrac + row[iround_1][jround_1] * rratio) * cratio;
1668 }
1669 
1673 template <> inline unsigned char vpImage<unsigned char>::getValue(double i, double j) const
1674 {
1675  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1676  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1677  }
1678  if (height * width == 0) {
1679  throw vpException(vpImageException::notInitializedError, "Empty image!");
1680  }
1681 
1682  // alpha architecture is bi-endianness. The following optimization makes testImageGetValue failing
1683 #if (defined(VISP_LITTLE_ENDIAN) || defined(VISP_BIG_ENDIAN)) && !(defined(__alpha__) || defined(_M_ALPHA))
1684  // Fixed-point arithmetic
1685  const int32_t precision = 1 << 16;
1686  int64_t y = static_cast<int64_t>(i * precision);
1687  int64_t x = static_cast<int64_t>(j * precision);
1688 
1689  int64_t iround = y & (~0xFFFF);
1690  int64_t jround = x & (~0xFFFF);
1691 
1692  int64_t rratio = y - iround;
1693  int64_t cratio = x - jround;
1694 
1695  int64_t rfrac = precision - rratio;
1696  int64_t cfrac = precision - cratio;
1697 
1698  int64_t x_ = x >> 16;
1699  int64_t y_ = y >> 16;
1700 
1701  if (y_ + 1 < height && x_ + 1 < width) {
1702  uint16_t up = vpEndian::reinterpret_cast_uchar_to_uint16_LE(bitmap + y_ * width + x_);
1703  uint16_t down = vpEndian::reinterpret_cast_uchar_to_uint16_LE(bitmap + (y_ + 1) * width + x_);
1704 
1705  return static_cast<unsigned char>((((up & 0x00FF) * rfrac + (down & 0x00FF) * rratio) * cfrac +
1706  ((up >> 8) * rfrac + (down >> 8) * rratio) * cratio) >>
1707  32);
1708  }
1709  else if (y_ + 1 < height) {
1710  return static_cast<unsigned char>(((row[y_][x_] * rfrac + row[y_ + 1][x_] * rratio)) >> 16);
1711  }
1712  else if (x_ + 1 < width) {
1713  uint16_t up = vpEndian::reinterpret_cast_uchar_to_uint16_LE(bitmap + y_ * width + x_);
1714  return static_cast<unsigned char>(((up & 0x00FF) * cfrac + (up >> 8) * cratio) >> 16);
1715  }
1716  else {
1717  return row[y_][x_];
1718  }
1719 #else
1720  unsigned int iround = static_cast<unsigned int>(floor(i));
1721  unsigned int jround = static_cast<unsigned int>(floor(j));
1722 
1723  if (iround >= height || jround >= width) {
1724  vpERROR_TRACE("Pixel outside the image");
1725  throw(vpException(vpImageException::notInTheImage, "Pixel outside the image"));
1726  }
1727 
1728  double rratio = i - static_cast<double>(iround);
1729  double cratio = j - static_cast<double>(jround);
1730 
1731  double rfrac = 1.0 - rratio;
1732  double cfrac = 1.0 - cratio;
1733 
1734  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1735  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1736 
1737  double value =
1738  (static_cast<double>(row[iround][jround]) * rfrac + static_cast<double>(row[iround_1][jround]) * rratio) * cfrac +
1739  (static_cast<double>(row[iround][jround_1]) * rfrac + static_cast<double>(row[iround_1][jround_1]) * rratio) *
1740  cratio;
1741  return static_cast<unsigned char>(vpMath::round(value));
1742 #endif
1743 }
1744 
1748 template <> inline vpRGBa vpImage<vpRGBa>::getValue(double i, double j) const
1749 {
1750  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1751  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1752  }
1753  if (height * width == 0) {
1754  throw vpException(vpImageException::notInitializedError, "Empty image!");
1755  }
1756 
1757  unsigned int iround = static_cast<unsigned int>(floor(i));
1758  unsigned int jround = static_cast<unsigned int>(floor(j));
1759 
1760  double rratio = i - static_cast<double>(iround);
1761  double cratio = j - static_cast<double>(jround);
1762 
1763  double rfrac = 1.0 - rratio;
1764  double cfrac = 1.0 - cratio;
1765 
1766  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1767  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1768 
1769  double valueR =
1770  (static_cast<double>(row[iround][jround].R) * rfrac + static_cast<double>(row[iround_1][jround].R) * rratio) *
1771  cfrac +
1772  (static_cast<double>(row[iround][jround_1].R) * rfrac + static_cast<double>(row[iround_1][jround_1].R) * rratio) *
1773  cratio;
1774  double valueG =
1775  (static_cast<double>(row[iround][jround].G) * rfrac + static_cast<double>(row[iround_1][jround].G) * rratio) *
1776  cfrac +
1777  (static_cast<double>(row[iround][jround_1].G) * rfrac + static_cast<double>(row[iround_1][jround_1].G) * rratio) *
1778  cratio;
1779  double valueB =
1780  (static_cast<double>(row[iround][jround].B) * rfrac + static_cast<double>(row[iround_1][jround].B) * rratio) *
1781  cfrac +
1782  (static_cast<double>(row[iround][jround_1].B) * rfrac + static_cast<double>(row[iround_1][jround_1].B) * rratio) *
1783  cratio;
1784 
1785  return vpRGBa(static_cast<unsigned char>(vpMath::round(valueR)), static_cast<unsigned char>(vpMath::round(valueG)),
1786  static_cast<unsigned char>(vpMath::round(valueB)));
1787 }
1788 
1792 template <> inline vpRGBf vpImage<vpRGBf>::getValue(double i, double j) const
1793 {
1794  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1795  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1796  }
1797  if (height * width == 0) {
1798  throw vpException(vpImageException::notInitializedError, "Empty image!");
1799  }
1800 
1801  unsigned int iround = static_cast<unsigned int>(floor(i));
1802  unsigned int jround = static_cast<unsigned int>(floor(j));
1803 
1804  double rratio = i - static_cast<double>(iround);
1805  double cratio = j - static_cast<double>(jround);
1806 
1807  double rfrac = 1.0 - rratio;
1808  double cfrac = 1.0 - cratio;
1809 
1810  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1811  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1812 
1813  double valueR =
1814  (static_cast<double>(row[iround][jround].R) * rfrac + static_cast<double>(row[iround_1][jround].R) * rratio) *
1815  cfrac +
1816  (static_cast<double>(row[iround][jround_1].R) * rfrac + static_cast<double>(row[iround_1][jround_1].R) * rratio) *
1817  cratio;
1818  double valueG =
1819  (static_cast<double>(row[iround][jround].G) * rfrac + static_cast<double>(row[iround_1][jround].G) * rratio) *
1820  cfrac +
1821  (static_cast<double>(row[iround][jround_1].G) * rfrac + static_cast<double>(row[iround_1][jround_1].G) * rratio) *
1822  cratio;
1823  double valueB =
1824  (static_cast<double>(row[iround][jround].B) * rfrac + static_cast<double>(row[iround_1][jround].B) * rratio) *
1825  cfrac +
1826  (static_cast<double>(row[iround][jround_1].B) * rfrac + static_cast<double>(row[iround_1][jround_1].B) * rratio) *
1827  cratio;
1828 
1829  return vpRGBf(static_cast<float>(valueR), static_cast<float>(valueG), static_cast<float>(valueB));
1830 }
1831 
1848 template <class Type> inline Type vpImage<Type>::getValue(const vpImagePoint &ip) const
1849 {
1850  return getValue(ip.get_i(), ip.get_j());
1851 }
1852 
1856 template <> inline double vpImage<double>::getValue(const vpImagePoint &ip) const
1857 {
1858  return getValue(ip.get_i(), ip.get_j());
1859 }
1860 
1864 template <> inline unsigned char vpImage<unsigned char>::getValue(const vpImagePoint &ip) const
1865 {
1866  return getValue(ip.get_i(), ip.get_j());
1867 }
1868 
1872 template <> inline vpRGBa vpImage<vpRGBa>::getValue(const vpImagePoint &ip) const
1873 {
1874  return getValue(ip.get_i(), ip.get_j());
1875 }
1876 
1881 template <class Type> inline double vpImage<Type>::getSum() const
1882 {
1883  if ((height == 0) || (width == 0))
1884  return 0.0;
1885 
1886  double res = 0.0;
1887  for (unsigned int i = 0; i < height * width; ++i) {
1888  res += static_cast<double>(bitmap[i]);
1889  }
1890  return res;
1891 }
1892 
1896 template <> inline double vpImage<vpRGBa>::getSum() const
1897 {
1898  if ((height == 0) || (width == 0))
1899  return 0.0;
1900 
1901  double res = 0.0;
1902  for (unsigned int i = 0; i < height * width; ++i) {
1903  res += static_cast<double>(bitmap[i].R) + static_cast<double>(bitmap[i].G) + static_cast<double>(bitmap[i].B);
1904  }
1905  return res;
1906 }
1907 
1911 template <> inline double vpImage<vpRGBf>::getSum() const
1912 {
1913  if ((height == 0) || (width == 0))
1914  return 0.0;
1915 
1916  double res = 0.0;
1917  for (unsigned int i = 0; i < height * width; ++i) {
1918  res += static_cast<double>(bitmap[i].R) + static_cast<double>(bitmap[i].G) + static_cast<double>(bitmap[i].B);
1919  }
1920  return res;
1921 }
1922 
1952 template <class Type> void vpImage<Type>::sub(const vpImage<Type> &B, vpImage<Type> &C) const
1953 {
1954 
1955  try {
1956  if ((this->getHeight() != C.getHeight()) || (this->getWidth() != C.getWidth()))
1957  C.resize(this->getHeight(), this->getWidth());
1958  }
1959  catch (const vpException &me) {
1960  std::cout << me << std::endl;
1961  throw;
1962  }
1963 
1964  if ((this->getWidth() != B.getWidth()) || (this->getHeight() != B.getHeight())) {
1965  throw(vpException(vpException::memoryAllocationError, "vpImage mismatch in vpImage/vpImage subtraction"));
1966  }
1967 
1968  for (unsigned int i = 0; i < this->getWidth() * this->getHeight(); i++) {
1969  *(C.bitmap + i) = *(bitmap + i) - *(B.bitmap + i);
1970  }
1971 }
1972 
1984 template <class Type> void vpImage<Type>::sub(const vpImage<Type> &A, const vpImage<Type> &B, vpImage<Type> &C) const
1985 {
1986 
1987  try {
1988  if ((A.getHeight() != C.getHeight()) || (A.getWidth() != C.getWidth()))
1989  C.resize(A.getHeight(), A.getWidth());
1990  }
1991  catch (const vpException &me) {
1992  std::cout << me << std::endl;
1993  throw;
1994  }
1995 
1996  if ((A.getWidth() != B.getWidth()) || (A.getHeight() != B.getHeight())) {
1997  throw(vpException(vpException::memoryAllocationError, "vpImage mismatch in vpImage/vpImage subtraction "));
1998  }
1999 
2000  for (unsigned int i = 0; i < A.getWidth() * A.getHeight(); i++) {
2001  *(C.bitmap + i) = *(A.bitmap + i) - *(B.bitmap + i);
2002  }
2003 }
2004 
2013 template <class Type> void vpImage<Type>::performLut(const Type(&)[256], unsigned int)
2014 {
2015  std::cerr << "Not implemented !" << std::endl;
2016 }
2017 
2028 template <> inline void vpImage<unsigned char>::performLut(const unsigned char(&lut)[256], unsigned int nbThreads)
2029 {
2030  unsigned int size = getWidth() * getHeight();
2031  unsigned char *ptrStart = (unsigned char *)bitmap;
2032  unsigned char *ptrEnd = ptrStart + size;
2033  unsigned char *ptrCurrent = ptrStart;
2034 
2035  bool use_single_thread = (nbThreads == 0 || nbThreads == 1);
2036 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
2037  use_single_thread = true;
2038 #endif
2039 
2040  if (!use_single_thread && getSize() <= nbThreads) {
2041  use_single_thread = true;
2042  }
2043 
2044  if (use_single_thread) {
2045  // Single thread
2046 
2047  while (ptrCurrent != ptrEnd) {
2048  *ptrCurrent = lut[*ptrCurrent];
2049  ++ptrCurrent;
2050  }
2051  }
2052  else {
2053 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
2054  // Multi-threads
2055 
2056  std::vector<vpThread *> threadpool;
2057  std::vector<vpImageLut_Param_t *> imageLutParams;
2058 
2059  unsigned int image_size = getSize();
2060  unsigned int step = image_size / nbThreads;
2061  unsigned int last_step = image_size - step * (nbThreads - 1);
2062 
2063  for (unsigned int index = 0; index < nbThreads; index++) {
2064  unsigned int start_index = index * step;
2065  unsigned int end_index = (index + 1) * step;
2066 
2067  if (index == nbThreads - 1) {
2068  end_index = start_index + last_step;
2069  }
2070 
2071  vpImageLut_Param_t *imageLut_param = new vpImageLut_Param_t(start_index, end_index, bitmap);
2072  memcpy(imageLut_param->m_lut, lut, 256 * sizeof(unsigned char));
2073 
2074  imageLutParams.push_back(imageLut_param);
2075 
2076  // Start the threads
2077  vpThread *imageLut_thread = new vpThread((vpThread::Fn)performLutThread, (vpThread::Args)imageLut_param);
2078  threadpool.push_back(imageLut_thread);
2079  }
2080 
2081  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2082  // Wait until thread ends up
2083  threadpool[cpt]->join();
2084  }
2085 
2086  // Delete
2087  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2088  delete threadpool[cpt];
2089  }
2090 
2091  for (size_t cpt = 0; cpt < imageLutParams.size(); cpt++) {
2092  delete imageLutParams[cpt];
2093  }
2094 #endif
2095  }
2096 }
2097 
2108 template <> inline void vpImage<vpRGBa>::performLut(const vpRGBa(&lut)[256], unsigned int nbThreads)
2109 {
2110  unsigned int size = getWidth() * getHeight();
2111  unsigned char *ptrStart = (unsigned char *)bitmap;
2112  unsigned char *ptrEnd = ptrStart + size * 4;
2113  unsigned char *ptrCurrent = ptrStart;
2114 
2115  bool use_single_thread = (nbThreads == 0 || nbThreads == 1);
2116 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
2117  use_single_thread = true;
2118 #endif
2119 
2120  if (!use_single_thread && getSize() <= nbThreads) {
2121  use_single_thread = true;
2122  }
2123 
2124  if (use_single_thread) {
2125  // Single thread
2126  while (ptrCurrent != ptrEnd) {
2127  *ptrCurrent = lut[*ptrCurrent].R;
2128  ++ptrCurrent;
2129 
2130  *ptrCurrent = lut[*ptrCurrent].G;
2131  ++ptrCurrent;
2132 
2133  *ptrCurrent = lut[*ptrCurrent].B;
2134  ++ptrCurrent;
2135 
2136  *ptrCurrent = lut[*ptrCurrent].A;
2137  ++ptrCurrent;
2138  }
2139  }
2140  else {
2141 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
2142  // Multi-threads
2143  std::vector<vpThread *> threadpool;
2144  std::vector<vpImageLutRGBa_Param_t *> imageLutParams;
2145 
2146  unsigned int image_size = getSize();
2147  unsigned int step = image_size / nbThreads;
2148  unsigned int last_step = image_size - step * (nbThreads - 1);
2149 
2150  for (unsigned int index = 0; index < nbThreads; index++) {
2151  unsigned int start_index = index * step;
2152  unsigned int end_index = (index + 1) * step;
2153 
2154  if (index == nbThreads - 1) {
2155  end_index = start_index + last_step;
2156  }
2157 
2158  vpImageLutRGBa_Param_t *imageLut_param = new vpImageLutRGBa_Param_t(start_index, end_index, (unsigned char *)bitmap);
2159  memcpy(static_cast<void *>(imageLut_param->m_lut), lut, 256 * sizeof(vpRGBa));
2160 
2161  imageLutParams.push_back(imageLut_param);
2162 
2163  // Start the threads
2164  vpThread *imageLut_thread = new vpThread((vpThread::Fn)performLutRGBaThread, (vpThread::Args)imageLut_param);
2165  threadpool.push_back(imageLut_thread);
2166  }
2167 
2168  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2169  // Wait until thread ends up
2170  threadpool[cpt]->join();
2171  }
2172 
2173  // Delete
2174  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2175  delete threadpool[cpt];
2176  }
2177 
2178  for (size_t cpt = 0; cpt < imageLutParams.size(); cpt++) {
2179  delete imageLutParams[cpt];
2180  }
2181 #endif
2182  }
2183 }
2184 
2185 template <class Type> void swap(vpImage<Type> &first, vpImage<Type> &second)
2186 {
2187  using std::swap;
2188  swap(first.bitmap, second.bitmap);
2189  swap(first.display, second.display);
2190  swap(first.npixels, second.npixels);
2191  swap(first.width, second.width);
2192  swap(first.height, second.height);
2193  swap(first.row, second.row);
2194 }
2195 
2196 #endif
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
Definition: vpArray2D.h:504
Class that defines generic functionalities for display.
Definition: vpDisplay.h:173
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ memoryAllocationError
Memory allocation error.
Definition: vpException.h:76
@ fatalError
Fatal error.
Definition: vpException.h:84
@ notInitializedError
Image not initialized.
@ notInTheImage
Pixel not in the image.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
double get_j() const
Definition: vpImagePoint.h:125
void set_ij(double ii, double jj)
Definition: vpImagePoint.h:305
double get_i() const
Definition: vpImagePoint.h:114
Definition of the vpImage class member functions.
Definition: vpImage.h:69
Type operator()(const vpImagePoint &ip) const
Definition: vpImage.h:288
void destroy()
Destructor : Memory de-allocation.
Definition: vpImage.h:822
void subsample(unsigned int v_scale, unsigned int h_scale, vpImage< Type > &sampled) const
Definition: vpImage.h:1462
void halfSizeImage(vpImage< Type > &res) const
Definition: vpImage.h:1434
vpImage< Type > & operator=(vpImage< Type > other)
Copy operator.
Definition: vpImage.h:1257
Type * operator[](int i)
Definition: vpImage.h:258
Type getMeanValue() const
Return the mean value of the bitmap.
Definition: vpImage.h:959
Type getMinValue(bool onlyFiniteVal=true) const
Return the minimum value within the bitmap.
Definition: vpImage.h:974
void quarterSizeImage(vpImage< Type > &res) const
Definition: vpImage.h:1498
void getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal=nullptr, Type *maxVal=nullptr) const
Get the position of the minimum and/or the maximum pixel value within the bitmap and the correspondin...
Definition: vpImage.h:1219
void init(unsigned int height, unsigned int width)
Set the size of the image.
Definition: vpImage.h:637
Type * operator[](unsigned int i)
operator[] allows operation like I[i] = x.
Definition: vpImage.h:257
void resize(unsigned int h, unsigned int w, const Type &val)
resize the image : Image initialization
Definition: vpImage.h:814
unsigned int getWidth() const
Definition: vpImage.h:240
friend std::ostream & operator<<(std::ostream &s, const vpImage< unsigned char > &I)
Definition: vpImage.h:376
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:793
unsigned int getNumberOfPixel() const
Definition: vpImage.h:203
Type getValue(double i, double j) const
Definition: vpImage.h:1613
void doubleSizeImage(vpImage< Type > &res)
Definition: vpImage.h:1540
vpImage(unsigned int height, unsigned int width, Type value)
constructor set the size of the image and init all the pixel
Definition: vpImage.h:750
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage.h:2013
const Type * operator[](int i) const
Definition: vpImage.h:262
friend std::ostream & operator<<(std::ostream &s, const vpImage< float > &I)
Definition: vpImage.h:428
bool operator==(const vpImage< Type > &I) const
Definition: vpImage.h:1289
void insert(const vpImage< Type > &src, const vpImagePoint &topLeft)
Definition: vpImage.h:1357
void sub(const vpImage< Type > &A, const vpImage< Type > &B, vpImage< Type > &C) const
Definition: vpImage.h:1984
Type getValue(unsigned int i, unsigned int j) const
Definition: vpImage.h:1588
double getValue(double i, double j) const
Definition: vpImage.h:1645
double getSum() const
Definition: vpImage.h:1881
vpImage< Type > operator-(const vpImage< Type > &B) const
Definition: vpImage.h:1339
void init(unsigned int height, unsigned int width, Type value)
Set the size of the image.
Definition: vpImage.h:625
unsigned int getSize() const
Definition: vpImage.h:221
friend void swap(vpImage< Type > &first, vpImage< Type > &second)
Definition: vpImage.h:2185
unsigned int getCols() const
Definition: vpImage.h:173
Type * bitmap
points toward the bitmap
Definition: vpImage.h:139
const Type * operator[](unsigned int i) const
operator[] allows operation like x = I[i]
Definition: vpImage.h:261
Type getValue(const vpImagePoint &ip) const
Definition: vpImage.h:1848
void sub(const vpImage< Type > &B, vpImage< Type > &C) const
Definition: vpImage.h:1952
vpImage(Type *const array, unsigned int height, unsigned int width, bool copyData=false)
constructor from an image stored as a continuous array in memory
Definition: vpImage.h:760
void init(Type *const array, unsigned int height, unsigned int width, bool copyData=false)
init from an image stored as a continuous array in memory
Definition: vpImage.h:684
Type getMaxValue(bool onlyFiniteVal=true) const
Return the maximum value within the bitmap.
Definition: vpImage.h:886
virtual ~vpImage()
destructor
Definition: vpImage.h:849
unsigned int getHeight() const
Definition: vpImage.h:182
unsigned int getRows() const
Definition: vpImage.h:212
friend std::ostream & operator<<(std::ostream &s, const vpImage< double > &I)
Definition: vpImage.h:455
void getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal=true) const
Look for the minimum and the maximum value within the bitmap.
Definition: vpImage.h:1050
vpImage< Type > & operator=(const Type &v)
= operator : Set all the element of the bitmap to a given value v.
Definition: vpImage.h:1276
vpDisplay * display
Definition: vpImage.h:140
vpImage()
constructor
Definition: vpImage.h:770
friend std::ostream & operator<<(std::ostream &s, const vpImage< char > &I)
Definition: vpImage.h:402
void operator()(const vpImagePoint &ip, const Type &v)
Definition: vpImage.h:304
Type operator()(unsigned int i, unsigned int j) const
Definition: vpImage.h:270
bool operator!=(const vpImage< Type > &I) const
Definition: vpImage.h:1312
vpImage(vpImage< Type > &&)
move constructor
Definition: vpImage.h:866
void init(unsigned int h, unsigned int w, Type value)
Definition: vpImage.h:625
vpImage(const vpImage< Type > &)
copy constructor
Definition: vpImage.h:855
vpImage(unsigned int height, unsigned int width)
constructor set the size of the image
Definition: vpImage.h:740
void operator()(unsigned int i, unsigned int j, const Type &v)
Definition: vpImage.h:276
static int round(double x)
Definition: vpMath.h:403
static bool isFinite(double value)
Definition: vpMath.cpp:178
Definition: vpRGBa.h:61
Definition: vpRGBf.h:57
float B
Blue component.
Definition: vpRGBf.h:124
float G
Green component.
Definition: vpRGBf.h:123
float R
Red component.
Definition: vpRGBf.h:122
void *(* Fn)(Args)
Definition: vpThread.h:74
void * Return
Definition: vpThread.h:73
void * Args
Definition: vpThread.h:72
#define vpDEBUG_TRACE
Definition: vpDebug.h:482
#define vpERROR_TRACE
Definition: vpDebug.h:388
VISP_EXPORT uint16_t reinterpret_cast_uchar_to_uint16_LE(unsigned char *const ptr)
Definition: vpEndian.cpp:108