Visual Servoing Platform  version 3.5.1 under development (2023-03-14)
vpImage.h
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Image handling.
33  *
34  * Authors:
35  * Eric Marchand
36  *
37  *****************************************************************************/
38 
44 #ifndef vpImage_H
45 #define vpImage_H
46 
47 #include <visp3/core/vpConfig.h>
48 #include <visp3/core/vpDebug.h>
49 #include <visp3/core/vpEndian.h>
50 #include <visp3/core/vpException.h>
51 #include <visp3/core/vpImageException.h>
52 #include <visp3/core/vpImagePoint.h>
53 #include <visp3/core/vpRGBa.h>
54 #include <visp3/core/vpRGBf.h>
55 
56 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
57 #include <visp3/core/vpThread.h>
58 #endif
59 
60 #include <fstream>
61 #include <iomanip> // std::setw
62 #include <iostream>
63 #include <math.h>
64 #include <string.h>
65 
66 // Visual Studio 2010 or previous is missing inttypes.h
67 #if defined(_MSC_VER) && (_MSC_VER < 1700)
68 typedef long long int64_t;
69 typedef unsigned short uint16_t;
70 #else
71 #include <inttypes.h>
72 #endif
73 
74 class vpDisplay;
75 
126 // Ref: http://en.cppreference.com/w/cpp/language/friend#Template_friends
127 template <class Type> class vpImage; // forward declare to make function declaration possible
128 
129 // declarations
130 template <class Type> std::ostream &operator<<(std::ostream &, const vpImage<Type> &);
131 
132 std::ostream &operator<<(std::ostream &, const vpImage<unsigned char> &);
133 std::ostream &operator<<(std::ostream &, const vpImage<char> &);
134 std::ostream &operator<<(std::ostream &, const vpImage<float> &);
135 std::ostream &operator<<(std::ostream &, const vpImage<double> &);
136 
137 template <class Type> void swap(vpImage<Type> &first, vpImage<Type> &second);
138 
139 template <class Type> class vpImage
140 {
141  friend class vpImageConvert;
142 
143 public:
144  Type *bitmap;
146 
151 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
154 #endif
156  vpImage(unsigned int height, unsigned int width);
158  vpImage(unsigned int height, unsigned int width, Type value);
160  vpImage(Type *const array, unsigned int height, unsigned int width, bool copyData = false);
162  virtual ~vpImage();
163 
166 
167  // destructor
168  void destroy();
169 
170  // Returns a new image that's double size of the current image
172 
180  inline unsigned int getCols() const { return width; }
189  inline unsigned int getHeight() const { return height; }
190 
191  // Return the maximum value within the bitmap
192  Type getMaxValue(bool onlyFiniteVal = true) const;
193  // Return the mean value of the bitmap
194  Type getMeanValue() const;
195  // Return the minumum value within the bitmap
196  Type getMinValue(bool onlyFiniteVal = true) const;
197  // Look for the minumum and the maximum value within the bitmap
198  void getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal = true) const;
199  // Look for the minumum and the maximum value within the bitmap and get their location
200  void getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal = NULL, Type *maxVal = NULL) const;
201 
210  inline unsigned int getNumberOfPixel() const { return npixels; }
211 
219  inline unsigned int getRows() const { return height; }
220 
228  inline unsigned int getSize() const { return width * height; }
229 
230  // Gets the value of a pixel at a location.
231  Type getValue(unsigned int i, unsigned int j) const;
232  // Gets the value of a pixel at a location with bilinear interpolation.
233  Type getValue(double i, double j) const;
234  // Gets the value of a pixel at a location with bilinear interpolation.
235  Type getValue(const vpImagePoint &ip) const;
236 
237  // Get image pixels sum
238  double getSum() const;
239 
247  inline unsigned int getWidth() const { return width; }
248 
249  // Returns a new image that's half size of the current image
250  void halfSizeImage(vpImage<Type> &res) const;
251 
253  void init(unsigned int height, unsigned int width);
255  void init(unsigned int height, unsigned int width, Type value);
257  void init(Type *const array, unsigned int height, unsigned int width, bool copyData = false);
258  void insert(const vpImage<Type> &src, const vpImagePoint &topLeft);
259 
260  //------------------------------------------------------------------
261  // Acces to the image
262 
264  inline Type *operator[](unsigned int i) { return row[i]; }
265  inline Type *operator[](int i) { return row[i]; }
266 
268  inline const Type *operator[](unsigned int i) const { return row[i]; }
269  inline const Type *operator[](int i) const { return row[i]; }
270 
277  inline Type operator()(unsigned int i, unsigned int j) const { return bitmap[i * width + j]; }
278 
283  inline void operator()(unsigned int i, unsigned int j, const Type &v) { bitmap[i * width + j] = v; }
284 
295  inline Type operator()(const vpImagePoint &ip) const
296  {
297  unsigned int i = (unsigned int)ip.get_i();
298  unsigned int j = (unsigned int)ip.get_j();
299 
300  return bitmap[i * width + j];
301  }
302 
311  inline void operator()(const vpImagePoint &ip, const Type &v)
312  {
313  unsigned int i = (unsigned int)ip.get_i();
314  unsigned int j = (unsigned int)ip.get_j();
315 
316  bitmap[i * width + j] = v;
317  }
318 
320 
323 
324  vpImage<Type> &operator=(const Type &v);
325  bool operator==(const vpImage<Type> &I);
326  bool operator!=(const vpImage<Type> &I);
327  friend std::ostream &operator<< <>(std::ostream &s, const vpImage<Type> &I);
328  friend std::ostream &operator<<(std::ostream &s, const vpImage<unsigned char> &I);
329  friend std::ostream &operator<<(std::ostream &s, const vpImage<char> &I);
330  friend std::ostream &operator<<(std::ostream &s, const vpImage<float> &I);
331  friend std::ostream &operator<<(std::ostream &s, const vpImage<double> &I);
332 
333  // Perform a look-up table transformation
334  void performLut(const Type (&lut)[256], unsigned int nbThreads = 1);
335 
336  // Returns a new image that's a quarter size of the current image
337  void quarterSizeImage(vpImage<Type> &res) const;
338 
339  // set the size of the image without initializing it.
340  void resize(unsigned int h, unsigned int w);
341  // set the size of the image and initialize it.
342  void resize(unsigned int h, unsigned int w, const Type &val);
343 
344  void sub(const vpImage<Type> &B, vpImage<Type> &C);
345  void sub(const vpImage<Type> &A, const vpImage<Type> &B, vpImage<Type> &C);
346  void subsample(unsigned int v_scale, unsigned int h_scale, vpImage<Type> &sampled) const;
347 
348  friend void swap<>(vpImage<Type> &first, vpImage<Type> &second);
349 
351 
352 private:
353  unsigned int npixels;
354  unsigned int width;
355  unsigned int height;
356  Type **row;
357  bool hasOwnership;
358 };
359 
360 template <class Type> std::ostream &operator<<(std::ostream &s, const vpImage<Type> &I)
361 {
362  if (I.bitmap == NULL) {
363  return s;
364  }
365 
366  for (unsigned int i = 0; i < I.getHeight(); i++) {
367  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
368  s << I[i][j] << " ";
369  }
370 
371  // We don't add " " after the last column element
372  s << I[i][I.getWidth() - 1];
373 
374  // We don't add a \n character at the end of the last row line
375  if (i < I.getHeight() - 1) {
376  s << std::endl;
377  }
378  }
379 
380  return s;
381 }
382 
383 inline std::ostream &operator<<(std::ostream &s, const vpImage<unsigned char> &I)
384 {
385  if (I.bitmap == NULL) {
386  return s;
387  }
388 
389  std::ios_base::fmtflags original_flags = s.flags();
390 
391  for (unsigned int i = 0; i < I.getHeight(); i++) {
392  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
393  s << std::setw(3) << static_cast<unsigned>(I[i][j]) << " ";
394  }
395 
396  // We don't add " " after the last column element
397  s << std::setw(3) << static_cast<unsigned>(I[i][I.getWidth() - 1]);
398 
399  // We don't add a \n character at the end of the last row line
400  if (i < I.getHeight() - 1) {
401  s << std::endl;
402  }
403  }
404 
405  s.flags(original_flags); // restore s to standard state
406  return s;
407 }
408 
409 inline std::ostream &operator<<(std::ostream &s, const vpImage<char> &I)
410 {
411  if (I.bitmap == NULL) {
412  return s;
413  }
414 
415  std::ios_base::fmtflags original_flags = s.flags();
416 
417  for (unsigned int i = 0; i < I.getHeight(); i++) {
418  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
419  s << std::setw(4) << static_cast<int>(I[i][j]) << " ";
420  }
421 
422  // We don't add " " after the last column element
423  s << std::setw(4) << static_cast<int>(I[i][I.getWidth() - 1]);
424 
425  // We don't add a \n character at the end of the last row line
426  if (i < I.getHeight() - 1) {
427  s << std::endl;
428  }
429  }
430 
431  s.flags(original_flags); // restore s to standard state
432  return s;
433 }
434 
435 inline std::ostream &operator<<(std::ostream &s, const vpImage<float> &I)
436 {
437  if (I.bitmap == NULL) {
438  return s;
439  }
440 
441  std::ios_base::fmtflags original_flags = s.flags();
442  s.precision(9); // http://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
443 
444  for (unsigned int i = 0; i < I.getHeight(); i++) {
445  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
446  s << I[i][j] << " ";
447  }
448 
449  // We don't add " " after the last column element
450  s << I[i][I.getWidth() - 1];
451 
452  // We don't add a \n character at the end of the last row line
453  if (i < I.getHeight() - 1) {
454  s << std::endl;
455  }
456  }
457 
458  s.flags(original_flags); // restore s to standard state
459  return s;
460 }
461 
462 inline std::ostream &operator<<(std::ostream &s, const vpImage<double> &I)
463 {
464  if (I.bitmap == NULL) {
465  return s;
466  }
467 
468  std::ios_base::fmtflags original_flags = s.flags();
469  s.precision(17); // http://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
470 
471  for (unsigned int i = 0; i < I.getHeight(); i++) {
472  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
473  s << I[i][j] << " ";
474  }
475 
476  // We don't add " " after the last column element
477  s << I[i][I.getWidth() - 1];
478 
479  // We don't add a \n character at the end of the last row line
480  if (i < I.getHeight() - 1) {
481  s << std::endl;
482  }
483  }
484 
485  s.flags(original_flags); // restore s to standard state
486  return s;
487 }
488 
489 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
490 namespace
491 {
492 struct ImageLut_Param_t {
493  unsigned int m_start_index;
494  unsigned int m_end_index;
495 
496  unsigned char m_lut[256];
497  unsigned char *m_bitmap;
498 
499  ImageLut_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(NULL) {}
500 
501  ImageLut_Param_t(unsigned int start_index, unsigned int end_index, unsigned char *bitmap)
502  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
503  {
504  }
505 };
506 
507 vpThread::Return performLutThread(vpThread::Args args)
508 {
509  ImageLut_Param_t *imageLut_param = static_cast<ImageLut_Param_t *>(args);
510  unsigned int start_index = imageLut_param->m_start_index;
511  unsigned int end_index = imageLut_param->m_end_index;
512 
513  unsigned char *bitmap = imageLut_param->m_bitmap;
514 
515  unsigned char *ptrStart = bitmap + start_index;
516  unsigned char *ptrEnd = bitmap + end_index;
517  unsigned char *ptrCurrent = ptrStart;
518 
519  // while(ptrCurrent != ptrEnd) {
520  // *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
521  // ++ptrCurrent;
522  // }
523 
524  if (end_index - start_index >= 8) {
525  // Unroll loop version
526  for (; ptrCurrent <= ptrEnd - 8;) {
527  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
528  ++ptrCurrent;
529 
530  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
531  ++ptrCurrent;
532 
533  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
534  ++ptrCurrent;
535 
536  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
537  ++ptrCurrent;
538 
539  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
540  ++ptrCurrent;
541 
542  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
543  ++ptrCurrent;
544 
545  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
546  ++ptrCurrent;
547 
548  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
549  ++ptrCurrent;
550  }
551  }
552 
553  for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
554  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
555  }
556 
557  return 0;
558 }
559 
560 struct ImageLutRGBa_Param_t {
561  unsigned int m_start_index;
562  unsigned int m_end_index;
563 
564  vpRGBa m_lut[256];
565  unsigned char *m_bitmap;
566 
567  ImageLutRGBa_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(NULL) {}
568 
569  ImageLutRGBa_Param_t(unsigned int start_index, unsigned int end_index, unsigned char *bitmap)
570  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
571  {
572  }
573 };
574 
575 vpThread::Return performLutRGBaThread(vpThread::Args args)
576 {
577  ImageLutRGBa_Param_t *imageLut_param = static_cast<ImageLutRGBa_Param_t *>(args);
578  unsigned int start_index = imageLut_param->m_start_index;
579  unsigned int end_index = imageLut_param->m_end_index;
580 
581  unsigned char *bitmap = imageLut_param->m_bitmap;
582 
583  unsigned char *ptrStart = bitmap + start_index * 4;
584  unsigned char *ptrEnd = bitmap + end_index * 4;
585  unsigned char *ptrCurrent = ptrStart;
586 
587  if (end_index - start_index >= 4 * 2) {
588  // Unroll loop version
589  for (; ptrCurrent <= ptrEnd - 4 * 2;) {
590  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
591  ptrCurrent++;
592  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
593  ptrCurrent++;
594  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
595  ptrCurrent++;
596  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
597  ptrCurrent++;
598 
599  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
600  ptrCurrent++;
601  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
602  ptrCurrent++;
603  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
604  ptrCurrent++;
605  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
606  ptrCurrent++;
607  }
608  }
609 
610  while (ptrCurrent != ptrEnd) {
611  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
612  ptrCurrent++;
613 
614  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
615  ptrCurrent++;
616 
617  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
618  ptrCurrent++;
619 
620  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
621  ptrCurrent++;
622  }
623 
624  return 0;
625 }
626 } // namespace
627 #endif
628 
632 template <class Type> void vpImage<Type>::init(unsigned int h, unsigned int w, Type value)
633 {
634  init(h, w);
635 
636  // for (unsigned int i = 0; i < npixels; i++)
637  // bitmap[i] = value;
638  std::fill(bitmap, bitmap + npixels, value);
639 }
640 
644 template <class Type> void vpImage<Type>::init(unsigned int h, unsigned int w)
645 {
646  if (h != this->height) {
647  if (row != NULL) {
648  vpDEBUG_TRACE(10, "Destruction row[]");
649  delete[] row;
650  row = NULL;
651  }
652  }
653 
654  if ((h != this->height) || (w != this->width)) {
655  if (bitmap != NULL) {
656  vpDEBUG_TRACE(10, "Destruction bitmap[]");
657  if (hasOwnership) {
658  delete[] bitmap;
659  }
660  bitmap = NULL;
661  }
662  }
663 
664  this->width = w;
665  this->height = h;
666 
667  npixels = width * height;
668 
669  if (bitmap == NULL) {
670  bitmap = new Type[npixels];
671  hasOwnership = true;
672  }
673 
674  if (bitmap == NULL) {
675  throw(vpException(vpException::memoryAllocationError, "cannot allocate bitmap "));
676  }
677 
678  if (row == NULL)
679  row = new Type *[height];
680  if (row == NULL) {
681  throw(vpException(vpException::memoryAllocationError, "cannot allocate row "));
682  }
683 
684  for (unsigned int i = 0; i < height; i++)
685  row[i] = bitmap + i * width;
686 }
687 
691 template <class Type> void vpImage<Type>::init(Type *const array, unsigned int h, unsigned int w, bool copyData)
692 {
693  if (h != this->height) {
694  if (row != NULL) {
695  delete[] row;
696  row = NULL;
697  }
698  }
699 
700  // Delete bitmap if copyData==false, otherwise only if the dimension differs
701  if ((copyData && ((h != this->height) || (w != this->width))) || !copyData) {
702  if (bitmap != NULL) {
703  if (hasOwnership) {
704  delete[] bitmap;
705  }
706  bitmap = NULL;
707  }
708  }
709 
710  hasOwnership = copyData;
711  this->width = w;
712  this->height = h;
713 
714  npixels = width * height;
715 
716  if (copyData) {
717  if (bitmap == NULL)
718  bitmap = new Type[npixels];
719 
720  if (bitmap == NULL) {
721  throw(vpException(vpException::memoryAllocationError, "cannot allocate bitmap "));
722  }
723 
724  // Copy the image data
725  memcpy(static_cast<void *>(bitmap), static_cast<void *>(array), (size_t)(npixels * sizeof(Type)));
726  } else {
727  // Copy the address of the array in the bitmap
728  bitmap = array;
729  }
730 
731  if (row == NULL)
732  row = new Type *[height];
733  if (row == NULL) {
734  throw(vpException(vpException::memoryAllocationError, "cannot allocate row "));
735  }
736 
737  for (unsigned int i = 0; i < height; i++) {
738  row[i] = bitmap + i * width;
739  }
740 }
741 
745 template <class Type>
746 vpImage<Type>::vpImage(unsigned int h, unsigned int w)
747  : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
748 {
749  init(h, w, 0);
750 }
751 
755 template <class Type>
756 vpImage<Type>::vpImage(unsigned int h, unsigned int w, Type value)
757  : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
758 {
759  init(h, w, value);
760 }
761 
765 template <class Type>
766 vpImage<Type>::vpImage(Type *const array, unsigned int h, unsigned int w, bool copyData)
767  : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
768 {
769  init(array, h, w, copyData);
770 }
771 
775 template <class Type>
776 vpImage<Type>::vpImage() : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
777 {
778 }
779 
800 template <class Type> void vpImage<Type>::resize(unsigned int h, unsigned int w) { init(h, w); }
801 
821 template <class Type> void vpImage<Type>::resize(unsigned int h, unsigned int w, const Type &val) { init(h, w, val); }
822 
829 template <class Type> void vpImage<Type>::destroy()
830 {
831  // vpERROR_TRACE("Deallocate ");
832 
833  if (bitmap != NULL) {
834  // vpERROR_TRACE("Deallocate bitmap memory %p",bitmap);
835  // vpDEBUG_TRACE(20,"Deallocate bitmap memory %p",bitmap);
836  if (hasOwnership) {
837  delete[] bitmap;
838  }
839  bitmap = NULL;
840  }
841 
842  if (row != NULL) {
843  // vpERROR_TRACE("Deallocate row memory %p",row);
844  // vpDEBUG_TRACE(20,"Deallocate row memory %p",row);
845  delete[] row;
846  row = NULL;
847  }
848 }
849 
856 template <class Type> vpImage<Type>::~vpImage() { destroy(); }
857 
861 template <class Type>
863  : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
864 {
865  resize(I.getHeight(), I.getWidth());
866  memcpy(static_cast<void *>(bitmap), static_cast<void *>(I.bitmap), I.npixels * sizeof(Type));
867 }
868 
869 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
873 template <class Type>
875  : bitmap(I.bitmap), display(I.display), npixels(I.npixels), width(I.width), height(I.height), row(I.row),
876  hasOwnership(I.hasOwnership)
877 {
878  I.bitmap = NULL;
879  I.display = NULL;
880  I.npixels = 0;
881  I.width = 0;
882  I.height = 0;
883  I.row = NULL;
884  I.hasOwnership = false;
885 }
886 #endif
887 
895 template <class Type> Type vpImage<Type>::getMaxValue(bool onlyFiniteVal) const
896 {
897  if (npixels == 0)
898  throw(vpException(vpException::fatalError, "Cannot compute maximum value of an empty image"));
899  Type m = bitmap[0];
900  for (unsigned int i = 0; i < npixels; i++) {
901  if (bitmap[i] > m) {
902  m = bitmap[i];
903  }
904  }
905  (void)onlyFiniteVal;
906  return m;
907 }
908 
917 template <> inline double vpImage<double>::getMaxValue(bool onlyFiniteVal) const
918 {
919  if (npixels == 0)
920  throw(vpException(vpException::fatalError, "Cannot compute maximum value of an empty image"));
921  double m = bitmap[0];
922  if (onlyFiniteVal) {
923  for (unsigned int i = 0; i < npixels; i++) {
924  if (bitmap[i] > m && vpMath::isFinite(bitmap[i]))
925  m = bitmap[i];
926  }
927  } else {
928  for (unsigned int i = 0; i < npixels; i++) {
929  if (bitmap[i] > m)
930  m = bitmap[i];
931  }
932  }
933  return m;
934 }
935 
944 template <> inline float vpImage<float>::getMaxValue(bool onlyFiniteVal) const
945 {
946  if (npixels == 0)
947  throw(vpException(vpException::fatalError, "Cannot compute maximum value of an empty image"));
948  float m = bitmap[0];
949  if (onlyFiniteVal) {
950  for (unsigned int i = 0; i < npixels; i++) {
951  if (bitmap[i] > m && vpMath::isFinite(bitmap[i]))
952  m = bitmap[i];
953  }
954  } else {
955  for (unsigned int i = 0; i < npixels; i++) {
956  if (bitmap[i] > m)
957  m = bitmap[i];
958  }
959  }
960  return m;
961 }
962 
966 template <class Type> Type vpImage<Type>::getMeanValue() const
967 {
968  if ((height == 0) || (width == 0))
969  return 0.0;
970 
971  return getSum() / (height * width);
972 }
973 
981 template <class Type> Type vpImage<Type>::getMinValue(bool onlyFiniteVal) const
982 {
983  if (npixels == 0)
984  throw(vpException(vpException::fatalError, "Cannot compute minimum value of an empty image"));
985  Type m = bitmap[0];
986  for (unsigned int i = 0; i < npixels; i++) {
987  if (bitmap[i] < m) {
988  m = bitmap[i];
989  }
990  }
991  (void)onlyFiniteVal;
992  return m;
993 }
994 
1003 template <> inline double vpImage<double>::getMinValue(bool onlyFiniteVal) const
1004 {
1005  if (npixels == 0)
1006  throw(vpException(vpException::fatalError, "Cannot compute minimum value of an empty image"));
1007  double m = bitmap[0];
1008  if (onlyFiniteVal) {
1009  for (unsigned int i = 0; i < npixels; i++)
1010  if (bitmap[i] < m && vpMath::isFinite(bitmap[i]))
1011  m = bitmap[i];
1012  } else {
1013  for (unsigned int i = 0; i < npixels; i++)
1014  if (bitmap[i] < m)
1015  m = bitmap[i];
1016  }
1017  return m;
1018 }
1019 
1028 template <> inline float vpImage<float>::getMinValue(bool onlyFiniteVal) const
1029 {
1030  if (npixels == 0)
1031  throw(vpException(vpException::fatalError, "Cannot compute minimum value of an empty image"));
1032  float m = bitmap[0];
1033  if (onlyFiniteVal) {
1034  for (unsigned int i = 0; i < npixels; i++)
1035  if (bitmap[i] < m && vpMath::isFinite(bitmap[i]))
1036  m = bitmap[i];
1037  } else {
1038  for (unsigned int i = 0; i < npixels; i++)
1039  if (bitmap[i] < m)
1040  m = bitmap[i];
1041  }
1042  return m;
1043 }
1044 
1055 template <class Type> void vpImage<Type>::getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal) const
1056 {
1057  if (npixels == 0)
1058  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1059 
1060  min = max = bitmap[0];
1061  for (unsigned int i = 0; i < npixels; i++) {
1062  if (bitmap[i] < min)
1063  min = bitmap[i];
1064  if (bitmap[i] > max)
1065  max = bitmap[i];
1066  }
1067  (void)onlyFiniteVal;
1068 }
1069 
1081 template <> inline void vpImage<double>::getMinMaxValue(double &min, double &max, bool onlyFiniteVal) const
1082 {
1083  if (npixels == 0)
1084  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1085 
1086  min = max = bitmap[0];
1087  if (onlyFiniteVal) {
1088  for (unsigned int i = 0; i < npixels; i++) {
1089  if (vpMath::isFinite(bitmap[i])) {
1090  if (bitmap[i] < min)
1091  min = bitmap[i];
1092  if (bitmap[i] > max)
1093  max = bitmap[i];
1094  }
1095  }
1096  } else {
1097  for (unsigned int i = 0; i < npixels; i++) {
1098  if (bitmap[i] < min)
1099  min = bitmap[i];
1100  if (bitmap[i] > max)
1101  max = bitmap[i];
1102  }
1103  }
1104 }
1105 
1117 template <> inline void vpImage<float>::getMinMaxValue(float &min, float &max, bool onlyFiniteVal) const
1118 {
1119  if (npixels == 0)
1120  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1121 
1122  min = max = bitmap[0];
1123  if (onlyFiniteVal) {
1124  for (unsigned int i = 0; i < npixels; i++) {
1125  if (vpMath::isFinite(bitmap[i])) {
1126  if (bitmap[i] < min)
1127  min = bitmap[i];
1128  if (bitmap[i] > max)
1129  max = bitmap[i];
1130  }
1131  }
1132  } else {
1133  for (unsigned int i = 0; i < npixels; i++) {
1134  if (bitmap[i] < min)
1135  min = bitmap[i];
1136  if (bitmap[i] > max)
1137  max = bitmap[i];
1138  }
1139  }
1140 }
1141 
1152 template <> inline void vpImage<vpRGBf>::getMinMaxValue(vpRGBf &min, vpRGBf &max, bool onlyFiniteVal) const
1153 {
1154  if (npixels == 0)
1155  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1156 
1157  min = max = bitmap[0];
1158  if (onlyFiniteVal) {
1159  for (unsigned int i = 0; i < npixels; i++) {
1160  if (vpMath::isFinite(bitmap[i].R)) {
1161  if (bitmap[i].R < min.R)
1162  min.R = bitmap[i].R;
1163  if (bitmap[i].R > max.R)
1164  max.R = bitmap[i].R;
1165  }
1166  if (vpMath::isFinite(bitmap[i].G)) {
1167  if (bitmap[i].G < min.G)
1168  min.G = bitmap[i].G;
1169  if (bitmap[i].G > max.G)
1170  max.G = bitmap[i].G;
1171  }
1172  if (vpMath::isFinite(bitmap[i].B)) {
1173  if (bitmap[i].B < min.B)
1174  min.B = bitmap[i].B;
1175  if (bitmap[i].B > max.B)
1176  max.B = bitmap[i].B;
1177  }
1178  }
1179  } else {
1180  for (unsigned int i = 0; i < npixels; i++) {
1181  if (bitmap[i].R < min.R)
1182  min.R = bitmap[i].R;
1183  if (bitmap[i].R > max.R)
1184  max.R = bitmap[i].R;
1185 
1186  if (bitmap[i].G < min.G)
1187  min.G = bitmap[i].G;
1188  if (bitmap[i].G > max.G)
1189  max.G = bitmap[i].G;
1190 
1191  if (bitmap[i].B < min.B)
1192  min.B = bitmap[i].B;
1193  if (bitmap[i].B > max.B)
1194  max.B = bitmap[i].B;
1195  }
1196  }
1197 }
1198 
1220 template <class Type>
1221 void vpImage<Type>::getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal, Type *maxVal) const
1222 {
1223  if (npixels == 0)
1224  throw(vpException(vpException::fatalError, "Cannot get location of minimum/maximum "
1225  "values of an empty image"));
1226 
1227  Type min = bitmap[0], max = bitmap[0];
1228  vpImagePoint minLoc_, maxLoc_;
1229  for (unsigned int i = 0; i < height; i++) {
1230  for (unsigned int j = 0; j < width; j++) {
1231  if (row[i][j] < min) {
1232  min = row[i][j];
1233  minLoc_.set_ij(i, j);
1234  }
1235 
1236  if (row[i][j] > max) {
1237  max = row[i][j];
1238  maxLoc_.set_ij(i, j);
1239  }
1240  }
1241  }
1242 
1243  if (minLoc != NULL)
1244  *minLoc = minLoc_;
1245 
1246  if (maxLoc != NULL)
1247  *maxLoc = maxLoc_;
1248 
1249  if (minVal != NULL)
1250  *minVal = min;
1251 
1252  if (maxVal != NULL)
1253  *maxVal = max;
1254 }
1255 
1260 {
1261  swap(*this, other);
1262  // Swap back display pointer if it was not null
1263  // vpImage<unsigned char> I2(480, 640);
1264  // vpDisplayX d(I2);
1265  // I2 = I1; //copy only the data
1266  if (other.display != NULL)
1267  display = other.display;
1268 
1269  return *this;
1270 }
1271 
1278 template <class Type> vpImage<Type> &vpImage<Type>::operator=(const Type &v)
1279 {
1280  for (unsigned int i = 0; i < npixels; i++)
1281  bitmap[i] = v;
1282 
1283  return *this;
1284 }
1285 
1291 template <class Type> bool vpImage<Type>::operator==(const vpImage<Type> &I)
1292 {
1293  if (this->width != I.getWidth())
1294  return false;
1295  if (this->height != I.getHeight())
1296  return false;
1297 
1298  // printf("wxh: %dx%d bitmap: %p I.bitmap %p\n", width, height, bitmap,
1299  // I.bitmap);
1300  for (unsigned int i = 0; i < npixels; i++) {
1301  if (bitmap[i] != I.bitmap[i]) {
1302  // std::cout << "differ for pixel " << i << " (" << i%this->height
1303  // << ", " << i - i%this->height << ")" << std::endl;
1304  return false;
1305  }
1306  }
1307  return true;
1308 }
1314 template <class Type> bool vpImage<Type>::operator!=(const vpImage<Type> &I) { return !(*this == I); }
1315 
1342 {
1343  vpImage<Type> C;
1344  sub(*this, B, C);
1345  return C;
1346 }
1347 
1359 template <class Type> void vpImage<Type>::insert(const vpImage<Type> &src, const vpImagePoint &topLeft)
1360 {
1361  int itl = (int)topLeft.get_i();
1362  int jtl = (int)topLeft.get_j();
1363 
1364  int dest_ibegin = 0;
1365  int dest_jbegin = 0;
1366  int src_ibegin = 0;
1367  int src_jbegin = 0;
1368  int dest_w = (int)this->getWidth();
1369  int dest_h = (int)this->getHeight();
1370  int src_w = (int)src.getWidth();
1371  int src_h = (int)src.getHeight();
1372  int wsize = (int)src.getWidth();
1373  int hsize = (int)src.getHeight();
1374 
1375  if (itl >= dest_h || jtl >= dest_w)
1376  return;
1377 
1378  if (itl < 0)
1379  src_ibegin = -itl;
1380  else
1381  dest_ibegin = itl;
1382 
1383  if (jtl < 0)
1384  src_jbegin = -jtl;
1385  else
1386  dest_jbegin = jtl;
1387 
1388  if (src_w - src_jbegin > dest_w - dest_jbegin)
1389  wsize = dest_w - dest_jbegin;
1390  else
1391  wsize = src_w - src_jbegin;
1392 
1393  if (src_h - src_ibegin > dest_h - dest_ibegin)
1394  hsize = dest_h - dest_ibegin;
1395  else
1396  hsize = src_h - src_ibegin;
1397 
1398  for (int i = 0; i < hsize; i++) {
1399  Type *srcBitmap = src.bitmap + ((src_ibegin + i) * src_w + src_jbegin);
1400  Type *destBitmap = this->bitmap + ((dest_ibegin + i) * dest_w + dest_jbegin);
1401 
1402  memcpy(static_cast<void *>(destBitmap), static_cast<void *>(srcBitmap), (size_t)wsize * sizeof(Type));
1403  }
1404 }
1405 
1436 template <class Type> void vpImage<Type>::halfSizeImage(vpImage<Type> &res) const
1437 {
1438  unsigned int h = height / 2;
1439  unsigned int w = width / 2;
1440  res.resize(h, w);
1441  for (unsigned int i = 0; i < h; i++)
1442  for (unsigned int j = 0; j < w; j++)
1443  res[i][j] = (*this)[i << 1][j << 1];
1444 }
1445 
1463 template <class Type>
1464 void vpImage<Type>::subsample(unsigned int v_scale, unsigned int h_scale, vpImage<Type> &sampled) const
1465 {
1466  if (v_scale == 1 && h_scale == 1) {
1467  sampled = (*this);
1468  return;
1469  }
1470  unsigned int h = height / v_scale;
1471  unsigned int w = width / h_scale;
1472  sampled.resize(h, w);
1473  for (unsigned int i = 0; i < h; i++)
1474  for (unsigned int j = 0; j < w; j++)
1475  sampled[i][j] = (*this)[i * v_scale][j * h_scale];
1476 }
1477 
1500 template <class Type> void vpImage<Type>::quarterSizeImage(vpImage<Type> &res) const
1501 {
1502  unsigned int h = height / 4;
1503  unsigned int w = width / 4;
1504  res.resize(h, w);
1505  for (unsigned int i = 0; i < h; i++)
1506  for (unsigned int j = 0; j < w; j++)
1507  res[i][j] = (*this)[i << 2][j << 2];
1508 }
1509 
1542 template <class Type> void vpImage<Type>::doubleSizeImage(vpImage<Type> &res)
1543 {
1544  int h = height * 2;
1545  int w = width * 2;
1546 
1547  res.resize(h, w);
1548 
1549  for (int i = 0; i < h; i++)
1550  for (int j = 0; j < w; j++)
1551  res[i][j] = (*this)[i >> 1][j >> 1];
1552 
1553  /*
1554  A B C
1555  E F G
1556  H I J
1557  A C H J are pixels from original image
1558  B E G I are interpolated pixels
1559  */
1560 
1561  // interpolate pixels B and I
1562  for (int i = 0; i < h; i += 2)
1563  for (int j = 1; j < w - 1; j += 2)
1564  res[i][j] = (Type)(0.5 * ((*this)[i >> 1][j >> 1] + (*this)[i >> 1][(j >> 1) + 1]));
1565 
1566  // interpolate pixels E and G
1567  for (int i = 1; i < h - 1; i += 2)
1568  for (int j = 0; j < w; j += 2)
1569  res[i][j] = (Type)(0.5 * ((*this)[i >> 1][j >> 1] + (*this)[(i >> 1) + 1][j >> 1]));
1570 
1571  // interpolate pixel F
1572  for (int i = 1; i < h - 1; i += 2)
1573  for (int j = 1; j < w - 1; j += 2)
1574  res[i][j] = (Type)(0.25 * ((*this)[i >> 1][j >> 1] + (*this)[i >> 1][(j >> 1) + 1] +
1575  (*this)[(i >> 1) + 1][j >> 1] + (*this)[(i >> 1) + 1][(j >> 1) + 1]));
1576 }
1577 
1590 template <class Type> inline Type vpImage<Type>::getValue(unsigned int i, unsigned int j) const
1591 {
1592  if (i >= height || j >= width) {
1593  throw(vpException(vpImageException::notInTheImage, "Pixel outside the image"));
1594  }
1595 
1596  return row[i][j];
1597 }
1598 
1615 template <class Type> Type vpImage<Type>::getValue(double i, double j) const
1616 {
1617  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1618  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1619  }
1620  if (height * width == 0) {
1621  throw vpException(vpImageException::notInitializedError, "Empty image!");
1622  }
1623 
1624  unsigned int iround = static_cast<unsigned int>(floor(i));
1625  unsigned int jround = static_cast<unsigned int>(floor(j));
1626 
1627  double rratio = i - static_cast<double>(iround);
1628  double cratio = j - static_cast<double>(jround);
1629 
1630  double rfrac = 1.0 - rratio;
1631  double cfrac = 1.0 - cratio;
1632 
1633  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1634  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1635 
1636  double value =
1637  (static_cast<double>(row[iround][jround]) * rfrac + static_cast<double>(row[iround_1][jround]) * rratio) * cfrac +
1638  (static_cast<double>(row[iround][jround_1]) * rfrac + static_cast<double>(row[iround_1][jround_1]) * rratio) *
1639  cratio;
1640 
1641  return static_cast<Type>(vpMath::round(value));
1642 }
1643 
1647 template <> inline double vpImage<double>::getValue(double i, double j) const
1648 {
1649  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1650  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1651  }
1652  if (height * width == 0) {
1653  throw vpException(vpImageException::notInitializedError, "Empty image!");
1654  }
1655 
1656  unsigned int iround = static_cast<unsigned int>(floor(i));
1657  unsigned int jround = static_cast<unsigned int>(floor(j));
1658 
1659  double rratio = i - static_cast<double>(iround);
1660  double cratio = j - static_cast<double>(jround);
1661 
1662  double rfrac = 1.0 - rratio;
1663  double cfrac = 1.0 - cratio;
1664 
1665  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1666  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1667 
1668  return (row[iround][jround] * rfrac + row[iround_1][jround] * rratio) * cfrac +
1669  (row[iround][jround_1] * rfrac + row[iround_1][jround_1] * rratio) * cratio;
1670 }
1671 
1675 template <> inline unsigned char vpImage<unsigned char>::getValue(double i, double j) const
1676 {
1677  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1678  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1679  }
1680  if (height * width == 0) {
1681  throw vpException(vpImageException::notInitializedError, "Empty image!");
1682  }
1683 
1684  // alpha architecture is bi-endianness. The following optimization makes testImageGetValue failing
1685 #if (defined(VISP_LITTLE_ENDIAN) || defined(VISP_BIG_ENDIAN)) && !(defined(__alpha__) || defined(_M_ALPHA))
1686  // Fixed-point arithmetic
1687  const int32_t precision = 1 << 16;
1688  int64_t y = static_cast<int64_t>(i * precision);
1689  int64_t x = static_cast<int64_t>(j * precision);
1690 
1691  int64_t iround = y & (~0xFFFF);
1692  int64_t jround = x & (~0xFFFF);
1693 
1694  int64_t rratio = y - iround;
1695  int64_t cratio = x - jround;
1696 
1697  int64_t rfrac = precision - rratio;
1698  int64_t cfrac = precision - cratio;
1699 
1700  int64_t x_ = x >> 16;
1701  int64_t y_ = y >> 16;
1702 
1703  if (y_ + 1 < height && x_ + 1 < width) {
1704  uint16_t up = vpEndian::reinterpret_cast_uchar_to_uint16_LE(bitmap + y_ * width + x_);
1705  uint16_t down = vpEndian::reinterpret_cast_uchar_to_uint16_LE(bitmap + (y_ + 1) * width + x_);
1706 
1707  return static_cast<unsigned char>((((up & 0x00FF) * rfrac + (down & 0x00FF) * rratio) * cfrac +
1708  ((up >> 8) * rfrac + (down >> 8) * rratio) * cratio) >>
1709  32);
1710  } else if (y_ + 1 < height) {
1711  return static_cast<unsigned char>(((row[y_][x_] * rfrac + row[y_ + 1][x_] * rratio)) >> 16);
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  } else {
1716  return row[y_][x_];
1717  }
1718 #else
1719  unsigned int iround = static_cast<unsigned int>(floor(i));
1720  unsigned int jround = static_cast<unsigned int>(floor(j));
1721 
1722  if (iround >= height || jround >= width) {
1723  vpERROR_TRACE("Pixel outside the image");
1724  throw(vpException(vpImageException::notInTheImage, "Pixel outside the image"));
1725  }
1726 
1727  double rratio = i - static_cast<double>(iround);
1728  double cratio = j - static_cast<double>(jround);
1729 
1730  double rfrac = 1.0 - rratio;
1731  double cfrac = 1.0 - cratio;
1732 
1733  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1734  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1735 
1736  double value =
1737  (static_cast<double>(row[iround][jround]) * rfrac + static_cast<double>(row[iround_1][jround]) * rratio) * cfrac +
1738  (static_cast<double>(row[iround][jround_1]) * rfrac + static_cast<double>(row[iround_1][jround_1]) * rratio) *
1739  cratio;
1740  return static_cast<unsigned char>(vpMath::round(value));
1741 #endif
1742 }
1743 
1747 template <> inline vpRGBa vpImage<vpRGBa>::getValue(double i, double j) const
1748 {
1749  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1750  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1751  }
1752  if (height * width == 0) {
1753  throw vpException(vpImageException::notInitializedError, "Empty image!");
1754  }
1755 
1756  unsigned int iround = static_cast<unsigned int>(floor(i));
1757  unsigned int jround = static_cast<unsigned int>(floor(j));
1758 
1759  double rratio = i - static_cast<double>(iround);
1760  double cratio = j - static_cast<double>(jround);
1761 
1762  double rfrac = 1.0 - rratio;
1763  double cfrac = 1.0 - cratio;
1764 
1765  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1766  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1767 
1768  double valueR =
1769  (static_cast<double>(row[iround][jround].R) * rfrac + static_cast<double>(row[iround_1][jround].R) * rratio) *
1770  cfrac +
1771  (static_cast<double>(row[iround][jround_1].R) * rfrac + static_cast<double>(row[iround_1][jround_1].R) * rratio) *
1772  cratio;
1773  double valueG =
1774  (static_cast<double>(row[iround][jround].G) * rfrac + static_cast<double>(row[iround_1][jround].G) * rratio) *
1775  cfrac +
1776  (static_cast<double>(row[iround][jround_1].G) * rfrac + static_cast<double>(row[iround_1][jround_1].G) * rratio) *
1777  cratio;
1778  double valueB =
1779  (static_cast<double>(row[iround][jround].B) * rfrac + static_cast<double>(row[iround_1][jround].B) * rratio) *
1780  cfrac +
1781  (static_cast<double>(row[iround][jround_1].B) * rfrac + static_cast<double>(row[iround_1][jround_1].B) * rratio) *
1782  cratio;
1783 
1784  return vpRGBa(static_cast<unsigned char>(vpMath::round(valueR)), static_cast<unsigned char>(vpMath::round(valueG)),
1785  static_cast<unsigned char>(vpMath::round(valueB)));
1786 }
1787 
1804 template <class Type> inline Type vpImage<Type>::getValue(const vpImagePoint &ip) const
1805 {
1806  return getValue(ip.get_i(), ip.get_j());
1807 }
1808 
1812 template <> inline double vpImage<double>::getValue(const vpImagePoint &ip) const
1813 {
1814  return getValue(ip.get_i(), ip.get_j());
1815 }
1816 
1820 template <> inline unsigned char vpImage<unsigned char>::getValue(const vpImagePoint &ip) const
1821 {
1822  return getValue(ip.get_i(), ip.get_j());
1823 }
1824 
1828 template <> inline vpRGBa vpImage<vpRGBa>::getValue(const vpImagePoint &ip) const
1829 {
1830  return getValue(ip.get_i(), ip.get_j());
1831 }
1832 
1837 template <class Type> inline double vpImage<Type>::getSum() const
1838 {
1839  if ((height == 0) || (width == 0))
1840  return 0.0;
1841 
1842  double res = 0.0;
1843  for (unsigned int i = 0; i < height * width; ++i) {
1844  res += static_cast<double>(bitmap[i]);
1845  }
1846  return res;
1847 }
1848 
1852 template <> inline double vpImage<vpRGBa>::getSum() const
1853 {
1854  if ((height == 0) || (width == 0))
1855  return 0.0;
1856 
1857  double res = 0.0;
1858  for (unsigned int i = 0; i < height * width; ++i) {
1859  res += static_cast<double>(bitmap[i].R) + static_cast<double>(bitmap[i].G) + static_cast<double>(bitmap[i].B);
1860  }
1861  return res;
1862 }
1863 
1893 template <class Type> void vpImage<Type>::sub(const vpImage<Type> &B, vpImage<Type> &C)
1894 {
1895 
1896  try {
1897  if ((this->getHeight() != C.getHeight()) || (this->getWidth() != C.getWidth()))
1898  C.resize(this->getHeight(), this->getWidth());
1899  } catch (const vpException &me) {
1900  std::cout << me << std::endl;
1901  throw;
1902  }
1903 
1904  if ((this->getWidth() != B.getWidth()) || (this->getHeight() != B.getHeight())) {
1905  throw(vpException(vpException::memoryAllocationError, "vpImage mismatch in vpImage/vpImage subtraction"));
1906  }
1907 
1908  for (unsigned int i = 0; i < this->getWidth() * this->getHeight(); i++) {
1909  *(C.bitmap + i) = *(bitmap + i) - *(B.bitmap + i);
1910  }
1911 }
1912 
1924 template <class Type> void vpImage<Type>::sub(const vpImage<Type> &A, const vpImage<Type> &B, vpImage<Type> &C)
1925 {
1926 
1927  try {
1928  if ((A.getHeight() != C.getHeight()) || (A.getWidth() != C.getWidth()))
1929  C.resize(A.getHeight(), A.getWidth());
1930  } catch (const vpException &me) {
1931  std::cout << me << std::endl;
1932  throw;
1933  }
1934 
1935  if ((A.getWidth() != B.getWidth()) || (A.getHeight() != B.getHeight())) {
1936  throw(vpException(vpException::memoryAllocationError, "vpImage mismatch in vpImage/vpImage subtraction "));
1937  }
1938 
1939  for (unsigned int i = 0; i < A.getWidth() * A.getHeight(); i++) {
1940  *(C.bitmap + i) = *(A.bitmap + i) - *(B.bitmap + i);
1941  }
1942 }
1943 
1952 template <class Type> void vpImage<Type>::performLut(const Type (&)[256], unsigned int)
1953 {
1954  std::cerr << "Not implemented !" << std::endl;
1955 }
1956 
1967 template <> inline void vpImage<unsigned char>::performLut(const unsigned char (&lut)[256], unsigned int nbThreads)
1968 {
1969  unsigned int size = getWidth() * getHeight();
1970  unsigned char *ptrStart = (unsigned char *)bitmap;
1971  unsigned char *ptrEnd = ptrStart + size;
1972  unsigned char *ptrCurrent = ptrStart;
1973 
1974  bool use_single_thread = (nbThreads == 0 || nbThreads == 1);
1975 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
1976  use_single_thread = true;
1977 #endif
1978 
1979  if (!use_single_thread && getSize() <= nbThreads) {
1980  use_single_thread = true;
1981  }
1982 
1983  if (use_single_thread) {
1984  // Single thread
1985 
1986  while (ptrCurrent != ptrEnd) {
1987  *ptrCurrent = lut[*ptrCurrent];
1988  ++ptrCurrent;
1989  }
1990  } else {
1991 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
1992  // Multi-threads
1993 
1994  std::vector<vpThread *> threadpool;
1995  std::vector<ImageLut_Param_t *> imageLutParams;
1996 
1997  unsigned int image_size = getSize();
1998  unsigned int step = image_size / nbThreads;
1999  unsigned int last_step = image_size - step * (nbThreads - 1);
2000 
2001  for (unsigned int index = 0; index < nbThreads; index++) {
2002  unsigned int start_index = index * step;
2003  unsigned int end_index = (index + 1) * step;
2004 
2005  if (index == nbThreads - 1) {
2006  end_index = start_index + last_step;
2007  }
2008 
2009  ImageLut_Param_t *imageLut_param = new ImageLut_Param_t(start_index, end_index, bitmap);
2010  memcpy(imageLut_param->m_lut, lut, 256 * sizeof(unsigned char));
2011 
2012  imageLutParams.push_back(imageLut_param);
2013 
2014  // Start the threads
2015  vpThread *imageLut_thread = new vpThread((vpThread::Fn)performLutThread, (vpThread::Args)imageLut_param);
2016  threadpool.push_back(imageLut_thread);
2017  }
2018 
2019  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2020  // Wait until thread ends up
2021  threadpool[cpt]->join();
2022  }
2023 
2024  // Delete
2025  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2026  delete threadpool[cpt];
2027  }
2028 
2029  for (size_t cpt = 0; cpt < imageLutParams.size(); cpt++) {
2030  delete imageLutParams[cpt];
2031  }
2032 #endif
2033  }
2034 }
2035 
2046 template <> inline void vpImage<vpRGBa>::performLut(const vpRGBa (&lut)[256], unsigned int nbThreads)
2047 {
2048  unsigned int size = getWidth() * getHeight();
2049  unsigned char *ptrStart = (unsigned char *)bitmap;
2050  unsigned char *ptrEnd = ptrStart + size * 4;
2051  unsigned char *ptrCurrent = ptrStart;
2052 
2053  bool use_single_thread = (nbThreads == 0 || nbThreads == 1);
2054 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
2055  use_single_thread = true;
2056 #endif
2057 
2058  if (!use_single_thread && getSize() <= nbThreads) {
2059  use_single_thread = true;
2060  }
2061 
2062  if (use_single_thread) {
2063  // Single thread
2064  while (ptrCurrent != ptrEnd) {
2065  *ptrCurrent = lut[*ptrCurrent].R;
2066  ++ptrCurrent;
2067 
2068  *ptrCurrent = lut[*ptrCurrent].G;
2069  ++ptrCurrent;
2070 
2071  *ptrCurrent = lut[*ptrCurrent].B;
2072  ++ptrCurrent;
2073 
2074  *ptrCurrent = lut[*ptrCurrent].A;
2075  ++ptrCurrent;
2076  }
2077  } else {
2078 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
2079  // Multi-threads
2080  std::vector<vpThread *> threadpool;
2081  std::vector<ImageLutRGBa_Param_t *> imageLutParams;
2082 
2083  unsigned int image_size = getSize();
2084  unsigned int step = image_size / nbThreads;
2085  unsigned int last_step = image_size - step * (nbThreads - 1);
2086 
2087  for (unsigned int index = 0; index < nbThreads; index++) {
2088  unsigned int start_index = index * step;
2089  unsigned int end_index = (index + 1) * step;
2090 
2091  if (index == nbThreads - 1) {
2092  end_index = start_index + last_step;
2093  }
2094 
2095  ImageLutRGBa_Param_t *imageLut_param = new ImageLutRGBa_Param_t(start_index, end_index, (unsigned char *)bitmap);
2096  memcpy(static_cast<void *>(imageLut_param->m_lut), lut, 256 * sizeof(vpRGBa));
2097 
2098  imageLutParams.push_back(imageLut_param);
2099 
2100  // Start the threads
2101  vpThread *imageLut_thread = new vpThread((vpThread::Fn)performLutRGBaThread, (vpThread::Args)imageLut_param);
2102  threadpool.push_back(imageLut_thread);
2103  }
2104 
2105  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2106  // Wait until thread ends up
2107  threadpool[cpt]->join();
2108  }
2109 
2110  // Delete
2111  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2112  delete threadpool[cpt];
2113  }
2114 
2115  for (size_t cpt = 0; cpt < imageLutParams.size(); cpt++) {
2116  delete imageLutParams[cpt];
2117  }
2118 #endif
2119  }
2120 }
2121 
2122 template <class Type> void swap(vpImage<Type> &first, vpImage<Type> &second)
2123 {
2124  using std::swap;
2125  swap(first.bitmap, second.bitmap);
2126  swap(first.display, second.display);
2127  swap(first.npixels, second.npixels);
2128  swap(first.width, second.width);
2129  swap(first.height, second.height);
2130  swap(first.row, second.row);
2131 }
2132 
2133 #endif
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
Definition: vpArray2D.h:491
Class that defines generic functionnalities for display.
Definition: vpDisplay.h:178
error that can be emited by ViSP classes.
Definition: vpException.h:72
@ memoryAllocationError
Memory allocation error.
Definition: vpException.h:88
@ fatalError
Fatal error.
Definition: vpException.h:96
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:89
double get_j() const
Definition: vpImagePoint.h:132
void set_ij(double ii, double jj)
Definition: vpImagePoint.h:320
double get_i() const
Definition: vpImagePoint.h:121
Definition of the vpImage class member functions.
Definition: vpImage.h:74
Type operator()(const vpImagePoint &ip) const
Definition: vpImage.h:295
void destroy()
Destructor : Memory de-allocation.
Definition: vpImage.h:829
bool operator==(const vpImage< Type > &I)
Definition: vpImage.h:1291
void subsample(unsigned int v_scale, unsigned int h_scale, vpImage< Type > &sampled) const
Definition: vpImage.h:1464
void halfSizeImage(vpImage< Type > &res) const
Definition: vpImage.h:1436
vpImage< Type > & operator=(vpImage< Type > other)
Copy operator.
Definition: vpImage.h:1259
Type * operator[](int i)
Definition: vpImage.h:265
Type getMeanValue() const
Return the mean value of the bitmap.
Definition: vpImage.h:966
Type getMinValue(bool onlyFiniteVal=true) const
Return the minimum value within the bitmap.
Definition: vpImage.h:981
void getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal=NULL, Type *maxVal=NULL) const
Get the position of the minimum and/or the maximum pixel value within the bitmap and the correspondin...
Definition: vpImage.h:1221
void quarterSizeImage(vpImage< Type > &res) const
Definition: vpImage.h:1500
void init(unsigned int height, unsigned int width)
Set the size of the image.
Definition: vpImage.h:644
Type * operator[](unsigned int i)
operator[] allows operation like I[i] = x.
Definition: vpImage.h:264
void resize(unsigned int h, unsigned int w, const Type &val)
resize the image : Image initialization
Definition: vpImage.h:821
unsigned int getWidth() const
Definition: vpImage.h:247
friend std::ostream & operator<<(std::ostream &s, const vpImage< unsigned char > &I)
Definition: vpImage.h:383
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
unsigned int getNumberOfPixel() const
Definition: vpImage.h:210
Type getValue(double i, double j) const
Definition: vpImage.h:1615
void doubleSizeImage(vpImage< Type > &res)
Definition: vpImage.h:1542
void sub(const vpImage< Type > &B, vpImage< Type > &C)
Definition: vpImage.h:1893
vpImage(unsigned int height, unsigned int width, Type value)
constructor set the size of the image and init all the pixel
Definition: vpImage.h:756
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage.h:1952
const Type * operator[](int i) const
Definition: vpImage.h:269
friend std::ostream & operator<<(std::ostream &s, const vpImage< float > &I)
Definition: vpImage.h:435
vpImage< Type > operator-(const vpImage< Type > &B)
Definition: vpImage.h:1341
void insert(const vpImage< Type > &src, const vpImagePoint &topLeft)
Definition: vpImage.h:1359
Type getValue(unsigned int i, unsigned int j) const
Definition: vpImage.h:1590
double getSum() const
Definition: vpImage.h:1837
void init(unsigned int height, unsigned int width, Type value)
Set the size of the image.
Definition: vpImage.h:632
unsigned int getSize() const
Definition: vpImage.h:228
friend void swap(vpImage< Type > &first, vpImage< Type > &second)
Definition: vpImage.h:2122
unsigned int getCols() const
Definition: vpImage.h:180
Type * bitmap
points toward the bitmap
Definition: vpImage.h:144
const Type * operator[](unsigned int i) const
operator[] allows operation like x = I[i]
Definition: vpImage.h:268
void sub(const vpImage< Type > &A, const vpImage< Type > &B, vpImage< Type > &C)
Definition: vpImage.h:1924
Type getValue(const vpImagePoint &ip) const
Definition: vpImage.h:1804
bool operator!=(const vpImage< Type > &I)
Definition: vpImage.h:1314
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:766
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:691
Type getMaxValue(bool onlyFiniteVal=true) const
Return the maximum value within the bitmap.
Definition: vpImage.h:895
virtual ~vpImage()
destructor
Definition: vpImage.h:856
unsigned int getHeight() const
Definition: vpImage.h:189
unsigned int getRows() const
Definition: vpImage.h:219
friend std::ostream & operator<<(std::ostream &s, const vpImage< double > &I)
Definition: vpImage.h:462
void getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal=true) const
Look for the minimum and the maximum value within the bitmap.
Definition: vpImage.h:1055
vpImage< Type > & operator=(const Type &v)
= operator : Set all the element of the bitmap to a given value v.
Definition: vpImage.h:1278
vpDisplay * display
Definition: vpImage.h:145
vpImage()
constructor
Definition: vpImage.h:776
friend std::ostream & operator<<(std::ostream &s, const vpImage< char > &I)
Definition: vpImage.h:409
void operator()(const vpImagePoint &ip, const Type &v)
Definition: vpImage.h:311
Type operator()(unsigned int i, unsigned int j) const
Definition: vpImage.h:277
vpImage(vpImage< Type > &&)
move constructor
Definition: vpImage.h:874
void init(unsigned int h, unsigned int w, Type value)
Definition: vpImage.h:632
double getValue(double i, double j) const
Definition: vpImage.h:1647
vpImage(const vpImage< Type > &)
copy constructor
Definition: vpImage.h:862
vpImage(unsigned int height, unsigned int width)
constructor set the size of the image
Definition: vpImage.h:746
void operator()(unsigned int i, unsigned int j, const Type &v)
Definition: vpImage.h:283
static int round(double x)
Definition: vpMath.h:326
static bool isFinite(double value)
Definition: vpMath.cpp:175
Definition: vpRGBa.h:67
Definition: vpRGBf.h:59
float B
Blue component.
Definition: vpRGBf.h:129
float G
Green component.
Definition: vpRGBf.h:128
float R
Red component.
Definition: vpRGBf.h:127
void *(* Fn)(Args)
Definition: vpThread.h:79
void * Return
Definition: vpThread.h:78
void * Args
Definition: vpThread.h:77
#define vpDEBUG_TRACE
Definition: vpDebug.h:487
#define vpERROR_TRACE
Definition: vpDebug.h:393
VISP_EXPORT uint16_t reinterpret_cast_uchar_to_uint16_LE(unsigned char *const ptr)
Definition: vpEndian.cpp:108