Visual Servoing Platform  version 3.5.1 under development (2023-09-22)
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 
146 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
149 #endif
151  vpImage(unsigned int height, unsigned int width);
153  vpImage(unsigned int height, unsigned int width, Type value);
155  vpImage(Type *const array, unsigned int height, unsigned int width, bool copyData = false);
157  virtual ~vpImage();
158 
161 
162  // destructor
163  void destroy();
164 
165  // Returns a new image that's double size of the current image
167 
175  inline unsigned int getCols() const { return width; }
184  inline unsigned int getHeight() const { return height; }
185 
186  // Return the maximum value within the bitmap
187  Type getMaxValue(bool onlyFiniteVal = true) const;
188  // Return the mean value of the bitmap
189  Type getMeanValue() const;
190  // Return the minumum value within the bitmap
191  Type getMinValue(bool onlyFiniteVal = true) const;
192  // Look for the minumum and the maximum value within the bitmap
193  void getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal = true) const;
194  // Look for the minumum and the maximum value within the bitmap and get their location
195  void getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal = NULL, Type *maxVal = NULL) const;
196 
205  inline unsigned int getNumberOfPixel() const { return npixels; }
206 
214  inline unsigned int getRows() const { return height; }
215 
223  inline unsigned int getSize() const { return width * height; }
224 
225  // Gets the value of a pixel at a location.
226  Type getValue(unsigned int i, unsigned int j) const;
227  // Gets the value of a pixel at a location with bilinear interpolation.
228  Type getValue(double i, double j) const;
229  // Gets the value of a pixel at a location with bilinear interpolation.
230  Type getValue(const vpImagePoint &ip) const;
231 
232  // Get image pixels sum
233  double getSum() const;
234 
242  inline unsigned int getWidth() const { return width; }
243 
244  // Returns a new image that's half size of the current image
245  void halfSizeImage(vpImage<Type> &res) const;
246 
248  void init(unsigned int height, unsigned int width);
250  void init(unsigned int height, unsigned int width, Type value);
252  void init(Type *const array, unsigned int height, unsigned int width, bool copyData = false);
253  void insert(const vpImage<Type> &src, const vpImagePoint &topLeft);
254 
255  //------------------------------------------------------------------
256  // Access to the image
257 
259  inline Type *operator[](unsigned int i) { return row[i]; }
260  inline Type *operator[](int i) { return row[i]; }
261 
263  inline const Type *operator[](unsigned int i) const { return row[i]; }
264  inline const Type *operator[](int i) const { return row[i]; }
265 
272  inline Type operator()(unsigned int i, unsigned int j) const { return bitmap[i * width + j]; }
273 
278  inline void operator()(unsigned int i, unsigned int j, const Type &v) { bitmap[i * width + j] = v; }
279 
290  inline Type operator()(const vpImagePoint &ip) const
291  {
292  unsigned int i = (unsigned int)ip.get_i();
293  unsigned int j = (unsigned int)ip.get_j();
294 
295  return bitmap[i * width + j];
296  }
297 
306  inline void operator()(const vpImagePoint &ip, const Type &v)
307  {
308  unsigned int i = (unsigned int)ip.get_i();
309  unsigned int j = (unsigned int)ip.get_j();
310 
311  bitmap[i * width + j] = v;
312  }
313 
315 
318 
319  vpImage<Type> &operator=(const Type &v);
320  bool operator==(const vpImage<Type> &I) const;
321  bool operator!=(const vpImage<Type> &I) const;
322  friend std::ostream &operator<< <>(std::ostream &s, const vpImage<Type> &I);
323  friend std::ostream &operator<<(std::ostream &s, const vpImage<unsigned char> &I);
324  friend std::ostream &operator<<(std::ostream &s, const vpImage<char> &I);
325  friend std::ostream &operator<<(std::ostream &s, const vpImage<float> &I);
326  friend std::ostream &operator<<(std::ostream &s, const vpImage<double> &I);
327 
328  // Perform a look-up table transformation
329  void performLut(const Type(&lut)[256], unsigned int nbThreads = 1);
330 
331  // Returns a new image that's a quarter size of the current image
332  void quarterSizeImage(vpImage<Type> &res) const;
333 
334  // set the size of the image without initializing it.
335  void resize(unsigned int h, unsigned int w);
336  // set the size of the image and initialize it.
337  void resize(unsigned int h, unsigned int w, const Type &val);
338 
339  void sub(const vpImage<Type> &B, vpImage<Type> &C) const;
340  void sub(const vpImage<Type> &A, const vpImage<Type> &B, vpImage<Type> &C) const;
341  void subsample(unsigned int v_scale, unsigned int h_scale, vpImage<Type> &sampled) const;
342 
343  friend void swap<>(vpImage<Type> &first, vpImage<Type> &second);
344 
346 
347 private:
348  unsigned int npixels;
349  unsigned int width;
350  unsigned int height;
351  Type **row;
352  bool hasOwnership;
353 };
354 
355 template <class Type> std::ostream &operator<<(std::ostream &s, const vpImage<Type> &I)
356 {
357  if (I.bitmap == NULL) {
358  return s;
359  }
360 
361  for (unsigned int i = 0; i < I.getHeight(); i++) {
362  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
363  s << I[i][j] << " ";
364  }
365 
366  // We don't add " " after the last column element
367  s << I[i][I.getWidth() - 1];
368 
369  // We don't add a \n character at the end of the last row line
370  if (i < I.getHeight() - 1) {
371  s << std::endl;
372  }
373  }
374 
375  return s;
376 }
377 
378 inline std::ostream &operator<<(std::ostream &s, const vpImage<unsigned char> &I)
379 {
380  if (I.bitmap == NULL) {
381  return s;
382  }
383 
384  std::ios_base::fmtflags original_flags = s.flags();
385 
386  for (unsigned int i = 0; i < I.getHeight(); i++) {
387  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
388  s << std::setw(3) << static_cast<unsigned>(I[i][j]) << " ";
389  }
390 
391  // We don't add " " after the last column element
392  s << std::setw(3) << static_cast<unsigned>(I[i][I.getWidth() - 1]);
393 
394  // We don't add a \n character at the end of the last row line
395  if (i < I.getHeight() - 1) {
396  s << std::endl;
397  }
398  }
399 
400  s.flags(original_flags); // restore s to standard state
401  return s;
402 }
403 
404 inline std::ostream &operator<<(std::ostream &s, const vpImage<char> &I)
405 {
406  if (I.bitmap == NULL) {
407  return s;
408  }
409 
410  std::ios_base::fmtflags original_flags = s.flags();
411 
412  for (unsigned int i = 0; i < I.getHeight(); i++) {
413  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
414  s << std::setw(4) << static_cast<int>(I[i][j]) << " ";
415  }
416 
417  // We don't add " " after the last column element
418  s << std::setw(4) << static_cast<int>(I[i][I.getWidth() - 1]);
419 
420  // We don't add a \n character at the end of the last row line
421  if (i < I.getHeight() - 1) {
422  s << std::endl;
423  }
424  }
425 
426  s.flags(original_flags); // restore s to standard state
427  return s;
428 }
429 
430 inline std::ostream &operator<<(std::ostream &s, const vpImage<float> &I)
431 {
432  if (I.bitmap == NULL) {
433  return s;
434  }
435 
436  std::ios_base::fmtflags original_flags = s.flags();
437  s.precision(9); // http://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
438 
439  for (unsigned int i = 0; i < I.getHeight(); i++) {
440  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
441  s << I[i][j] << " ";
442  }
443 
444  // We don't add " " after the last column element
445  s << I[i][I.getWidth() - 1];
446 
447  // We don't add a \n character at the end of the last row line
448  if (i < I.getHeight() - 1) {
449  s << std::endl;
450  }
451  }
452 
453  s.flags(original_flags); // restore s to standard state
454  return s;
455 }
456 
457 inline std::ostream &operator<<(std::ostream &s, const vpImage<double> &I)
458 {
459  if (I.bitmap == NULL) {
460  return s;
461  }
462 
463  std::ios_base::fmtflags original_flags = s.flags();
464  s.precision(17); // http://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
465 
466  for (unsigned int i = 0; i < I.getHeight(); i++) {
467  for (unsigned int j = 0; j < I.getWidth() - 1; j++) {
468  s << I[i][j] << " ";
469  }
470 
471  // We don't add " " after the last column element
472  s << I[i][I.getWidth() - 1];
473 
474  // We don't add a \n character at the end of the last row line
475  if (i < I.getHeight() - 1) {
476  s << std::endl;
477  }
478  }
479 
480  s.flags(original_flags); // restore s to standard state
481  return s;
482 }
483 
484 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
485 namespace
486 {
487 struct vpImageLut_Param_t
488 {
489  unsigned int m_start_index;
490  unsigned int m_end_index;
491 
492  unsigned char m_lut[256];
493  unsigned char *m_bitmap;
494 
495  vpImageLut_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(NULL) { }
496 
497  vpImageLut_Param_t(unsigned int start_index, unsigned int end_index, unsigned char *bitmap)
498  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
499  { }
500 };
501 
502 vpThread::Return performLutThread(vpThread::Args args)
503 {
504  vpImageLut_Param_t *imageLut_param = static_cast<vpImageLut_Param_t *>(args);
505  unsigned int start_index = imageLut_param->m_start_index;
506  unsigned int end_index = imageLut_param->m_end_index;
507 
508  unsigned char *bitmap = imageLut_param->m_bitmap;
509 
510  unsigned char *ptrStart = bitmap + start_index;
511  unsigned char *ptrEnd = bitmap + end_index;
512  unsigned char *ptrCurrent = ptrStart;
513 
514  // while(ptrCurrent != ptrEnd) {
515  // *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
516  // ++ptrCurrent;
517  // }
518 
519  if (end_index - start_index >= 8) {
520  // Unroll loop version
521  for (; ptrCurrent <= ptrEnd - 8;) {
522  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
523  ++ptrCurrent;
524 
525  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
526  ++ptrCurrent;
527 
528  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
529  ++ptrCurrent;
530 
531  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
532  ++ptrCurrent;
533 
534  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
535  ++ptrCurrent;
536 
537  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
538  ++ptrCurrent;
539 
540  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
541  ++ptrCurrent;
542 
543  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
544  ++ptrCurrent;
545  }
546  }
547 
548  for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
549  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
550  }
551 
552  return 0;
553 }
554 
555 struct vpImageLutRGBa_Param_t
556 {
557  unsigned int m_start_index;
558  unsigned int m_end_index;
559 
560  vpRGBa m_lut[256];
561  unsigned char *m_bitmap;
562 
563  vpImageLutRGBa_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(NULL) { }
564 
565  vpImageLutRGBa_Param_t(unsigned int start_index, unsigned int end_index, unsigned char *bitmap)
566  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
567  { }
568 };
569 
570 vpThread::Return performLutRGBaThread(vpThread::Args args)
571 {
572  vpImageLutRGBa_Param_t *imageLut_param = static_cast<vpImageLutRGBa_Param_t *>(args);
573  unsigned int start_index = imageLut_param->m_start_index;
574  unsigned int end_index = imageLut_param->m_end_index;
575 
576  unsigned char *bitmap = imageLut_param->m_bitmap;
577 
578  unsigned char *ptrStart = bitmap + start_index * 4;
579  unsigned char *ptrEnd = bitmap + end_index * 4;
580  unsigned char *ptrCurrent = ptrStart;
581 
582  if (end_index - start_index >= 4 * 2) {
583  // Unroll loop version
584  for (; ptrCurrent <= ptrEnd - 4 * 2;) {
585  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
586  ptrCurrent++;
587  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
588  ptrCurrent++;
589  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
590  ptrCurrent++;
591  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
592  ptrCurrent++;
593 
594  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
595  ptrCurrent++;
596  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
597  ptrCurrent++;
598  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
599  ptrCurrent++;
600  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
601  ptrCurrent++;
602  }
603  }
604 
605  while (ptrCurrent != ptrEnd) {
606  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
607  ptrCurrent++;
608 
609  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
610  ptrCurrent++;
611 
612  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
613  ptrCurrent++;
614 
615  *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
616  ptrCurrent++;
617  }
618 
619  return 0;
620 }
621 } // namespace
622 #endif
623 
627 template <class Type> void vpImage<Type>::init(unsigned int h, unsigned int w, Type value)
628 {
629  init(h, w);
630 
631  // for (unsigned int i = 0; i < npixels; i++)
632  // bitmap[i] = value;
633  std::fill(bitmap, bitmap + npixels, value);
634 }
635 
639 template <class Type> void vpImage<Type>::init(unsigned int h, unsigned int w)
640 {
641  if (h != this->height) {
642  if (row != NULL) {
643  vpDEBUG_TRACE(10, "Destruction row[]");
644  delete[] row;
645  row = NULL;
646  }
647  }
648 
649  if ((h != this->height) || (w != this->width)) {
650  if (bitmap != NULL) {
651  vpDEBUG_TRACE(10, "Destruction bitmap[]");
652  if (hasOwnership) {
653  delete[] bitmap;
654  }
655  bitmap = NULL;
656  }
657  }
658 
659  this->width = w;
660  this->height = h;
661 
662  npixels = width * height;
663 
664  if (bitmap == NULL) {
665  bitmap = new Type[npixels];
666  hasOwnership = true;
667  }
668 
669  if (bitmap == NULL) {
670  throw(vpException(vpException::memoryAllocationError, "cannot allocate bitmap "));
671  }
672 
673  if (row == NULL)
674  row = new Type *[height];
675  if (row == NULL) {
676  throw(vpException(vpException::memoryAllocationError, "cannot allocate row "));
677  }
678 
679  for (unsigned int i = 0; i < height; i++)
680  row[i] = bitmap + i * width;
681 }
682 
686 template <class Type> void vpImage<Type>::init(Type *const array, unsigned int h, unsigned int w, bool copyData)
687 {
688  if (h != this->height) {
689  if (row != NULL) {
690  delete[] row;
691  row = NULL;
692  }
693  }
694 
695  // Delete bitmap if copyData==false, otherwise only if the dimension differs
696  if ((copyData && ((h != this->height) || (w != this->width))) || !copyData) {
697  if (bitmap != NULL) {
698  if (hasOwnership) {
699  delete[] bitmap;
700  }
701  bitmap = NULL;
702  }
703  }
704 
705  hasOwnership = copyData;
706  this->width = w;
707  this->height = h;
708 
709  npixels = width * height;
710 
711  if (copyData) {
712  if (bitmap == NULL)
713  bitmap = new Type[npixels];
714 
715  if (bitmap == NULL) {
716  throw(vpException(vpException::memoryAllocationError, "cannot allocate bitmap "));
717  }
718 
719  // Copy the image data
720  memcpy(static_cast<void *>(bitmap), static_cast<void *>(array), (size_t)(npixels * sizeof(Type)));
721  }
722  else {
723  // Copy the address of the array in the bitmap
724  bitmap = array;
725  }
726 
727  if (row == NULL)
728  row = new Type *[height];
729  if (row == NULL) {
730  throw(vpException(vpException::memoryAllocationError, "cannot allocate row "));
731  }
732 
733  for (unsigned int i = 0; i < height; i++) {
734  row[i] = bitmap + i * width;
735  }
736 }
737 
741 template <class Type>
742 vpImage<Type>::vpImage(unsigned int h, unsigned int w)
743  : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
744 {
745  init(h, w, 0);
746 }
747 
751 template <class Type>
752 vpImage<Type>::vpImage(unsigned int h, unsigned int w, Type value)
753  : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
754 {
755  init(h, w, value);
756 }
757 
761 template <class Type>
762 vpImage<Type>::vpImage(Type *const array, unsigned int h, unsigned int w, bool copyData)
763  : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
764 {
765  init(array, h, w, copyData);
766 }
767 
771 template <class Type>
772 vpImage<Type>::vpImage() : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
773 { }
774 
795 template <class Type> void vpImage<Type>::resize(unsigned int h, unsigned int w) { init(h, w); }
796 
816 template <class Type> void vpImage<Type>::resize(unsigned int h, unsigned int w, const Type &val) { init(h, w, val); }
817 
824 template <class Type> void vpImage<Type>::destroy()
825 {
826  // vpERROR_TRACE("Deallocate ");
827 
828  if (bitmap != NULL) {
829  // vpERROR_TRACE("Deallocate bitmap memory %p",bitmap);
830  // vpDEBUG_TRACE(20,"Deallocate bitmap memory %p",bitmap);
831  if (hasOwnership) {
832  delete[] bitmap;
833  }
834  bitmap = NULL;
835  }
836 
837  if (row != NULL) {
838  // vpERROR_TRACE("Deallocate row memory %p",row);
839  // vpDEBUG_TRACE(20,"Deallocate row memory %p",row);
840  delete[] row;
841  row = NULL;
842  }
843 }
844 
851 template <class Type> vpImage<Type>::~vpImage() { destroy(); }
852 
856 template <class Type>
858  : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
859 {
860  resize(I.getHeight(), I.getWidth());
861  memcpy(static_cast<void *>(bitmap), static_cast<void *>(I.bitmap), I.npixels * sizeof(Type));
862 }
863 
864 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
868 template <class Type>
870  : bitmap(I.bitmap), display(I.display), npixels(I.npixels), width(I.width), height(I.height), row(I.row),
871  hasOwnership(I.hasOwnership)
872 {
873  I.bitmap = NULL;
874  I.display = NULL;
875  I.npixels = 0;
876  I.width = 0;
877  I.height = 0;
878  I.row = NULL;
879  I.hasOwnership = false;
880 }
881 #endif
882 
890 template <class Type> Type vpImage<Type>::getMaxValue(bool onlyFiniteVal) const
891 {
892  if (npixels == 0)
893  throw(vpException(vpException::fatalError, "Cannot compute maximum value of an empty image"));
894  Type m = bitmap[0];
895  for (unsigned int i = 0; i < npixels; i++) {
896  if (bitmap[i] > m) {
897  m = bitmap[i];
898  }
899  }
900  (void)onlyFiniteVal;
901  return m;
902 }
903 
912 template <> inline double vpImage<double>::getMaxValue(bool onlyFiniteVal) const
913 {
914  if (npixels == 0)
915  throw(vpException(vpException::fatalError, "Cannot compute maximum value of an empty image"));
916  double m = bitmap[0];
917  if (onlyFiniteVal) {
918  for (unsigned int i = 0; i < npixels; i++) {
919  if (bitmap[i] > m && vpMath::isFinite(bitmap[i]))
920  m = bitmap[i];
921  }
922  }
923  else {
924  for (unsigned int i = 0; i < npixels; i++) {
925  if (bitmap[i] > m)
926  m = bitmap[i];
927  }
928  }
929  return m;
930 }
931 
940 template <> inline float vpImage<float>::getMaxValue(bool onlyFiniteVal) const
941 {
942  if (npixels == 0)
943  throw(vpException(vpException::fatalError, "Cannot compute maximum value of an empty image"));
944  float m = bitmap[0];
945  if (onlyFiniteVal) {
946  for (unsigned int i = 0; i < npixels; i++) {
947  if (bitmap[i] > m && vpMath::isFinite(bitmap[i]))
948  m = bitmap[i];
949  }
950  }
951  else {
952  for (unsigned int i = 0; i < npixels; i++) {
953  if (bitmap[i] > m)
954  m = bitmap[i];
955  }
956  }
957  return m;
958 }
959 
963 template <class Type> Type vpImage<Type>::getMeanValue() const
964 {
965  if ((height == 0) || (width == 0))
966  return 0.0;
967 
968  return getSum() / (height * width);
969 }
970 
978 template <class Type> Type vpImage<Type>::getMinValue(bool onlyFiniteVal) const
979 {
980  if (npixels == 0)
981  throw(vpException(vpException::fatalError, "Cannot compute minimum value of an empty image"));
982  Type m = bitmap[0];
983  for (unsigned int i = 0; i < npixels; i++) {
984  if (bitmap[i] < m) {
985  m = bitmap[i];
986  }
987  }
988  (void)onlyFiniteVal;
989  return m;
990 }
991 
1000 template <> inline double vpImage<double>::getMinValue(bool onlyFiniteVal) const
1001 {
1002  if (npixels == 0)
1003  throw(vpException(vpException::fatalError, "Cannot compute minimum value of an empty image"));
1004  double m = bitmap[0];
1005  if (onlyFiniteVal) {
1006  for (unsigned int i = 0; i < npixels; i++)
1007  if (bitmap[i] < m && vpMath::isFinite(bitmap[i]))
1008  m = bitmap[i];
1009  }
1010  else {
1011  for (unsigned int i = 0; i < npixels; i++)
1012  if (bitmap[i] < m)
1013  m = bitmap[i];
1014  }
1015  return m;
1016 }
1017 
1026 template <> inline float vpImage<float>::getMinValue(bool onlyFiniteVal) const
1027 {
1028  if (npixels == 0)
1029  throw(vpException(vpException::fatalError, "Cannot compute minimum value of an empty image"));
1030  float m = bitmap[0];
1031  if (onlyFiniteVal) {
1032  for (unsigned int i = 0; i < npixels; i++)
1033  if (bitmap[i] < m && vpMath::isFinite(bitmap[i]))
1034  m = bitmap[i];
1035  }
1036  else {
1037  for (unsigned int i = 0; i < npixels; i++)
1038  if (bitmap[i] < m)
1039  m = bitmap[i];
1040  }
1041  return m;
1042 }
1043 
1054 template <class Type> void vpImage<Type>::getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal) const
1055 {
1056  if (npixels == 0)
1057  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1058 
1059  min = max = bitmap[0];
1060  for (unsigned int i = 0; i < npixels; i++) {
1061  if (bitmap[i] < min)
1062  min = bitmap[i];
1063  if (bitmap[i] > max)
1064  max = bitmap[i];
1065  }
1066  (void)onlyFiniteVal;
1067 }
1068 
1080 template <> inline void vpImage<double>::getMinMaxValue(double &min, double &max, bool onlyFiniteVal) const
1081 {
1082  if (npixels == 0)
1083  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1084 
1085  min = max = bitmap[0];
1086  if (onlyFiniteVal) {
1087  for (unsigned int i = 0; i < npixels; i++) {
1088  if (vpMath::isFinite(bitmap[i])) {
1089  if (bitmap[i] < min)
1090  min = bitmap[i];
1091  if (bitmap[i] > max)
1092  max = bitmap[i];
1093  }
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  }
1133  else {
1134  for (unsigned int i = 0; i < npixels; i++) {
1135  if (bitmap[i] < min)
1136  min = bitmap[i];
1137  if (bitmap[i] > max)
1138  max = bitmap[i];
1139  }
1140  }
1141 }
1142 
1153 template <> inline void vpImage<vpRGBf>::getMinMaxValue(vpRGBf &min, vpRGBf &max, bool onlyFiniteVal) const
1154 {
1155  if (npixels == 0)
1156  throw(vpException(vpException::fatalError, "Cannot get minimum/maximum values of an empty image"));
1157 
1158  min = max = bitmap[0];
1159  if (onlyFiniteVal) {
1160  for (unsigned int i = 0; i < npixels; i++) {
1161  if (vpMath::isFinite(bitmap[i].R)) {
1162  if (bitmap[i].R < min.R)
1163  min.R = bitmap[i].R;
1164  if (bitmap[i].R > max.R)
1165  max.R = bitmap[i].R;
1166  }
1167  if (vpMath::isFinite(bitmap[i].G)) {
1168  if (bitmap[i].G < min.G)
1169  min.G = bitmap[i].G;
1170  if (bitmap[i].G > max.G)
1171  max.G = bitmap[i].G;
1172  }
1173  if (vpMath::isFinite(bitmap[i].B)) {
1174  if (bitmap[i].B < min.B)
1175  min.B = bitmap[i].B;
1176  if (bitmap[i].B > max.B)
1177  max.B = bitmap[i].B;
1178  }
1179  }
1180  }
1181  else {
1182  for (unsigned int i = 0; i < npixels; i++) {
1183  if (bitmap[i].R < min.R)
1184  min.R = bitmap[i].R;
1185  if (bitmap[i].R > max.R)
1186  max.R = bitmap[i].R;
1187 
1188  if (bitmap[i].G < min.G)
1189  min.G = bitmap[i].G;
1190  if (bitmap[i].G > max.G)
1191  max.G = bitmap[i].G;
1192 
1193  if (bitmap[i].B < min.B)
1194  min.B = bitmap[i].B;
1195  if (bitmap[i].B > max.B)
1196  max.B = bitmap[i].B;
1197  }
1198  }
1199 }
1200 
1222 template <class Type>
1223 void vpImage<Type>::getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal, Type *maxVal) const
1224 {
1225  if (npixels == 0)
1226  throw(vpException(vpException::fatalError, "Cannot get location of minimum/maximum "
1227  "values of an empty image"));
1228 
1229  Type min = bitmap[0], max = bitmap[0];
1230  vpImagePoint minLoc_, maxLoc_;
1231  for (unsigned int i = 0; i < height; i++) {
1232  for (unsigned int j = 0; j < width; j++) {
1233  if (row[i][j] < min) {
1234  min = row[i][j];
1235  minLoc_.set_ij(i, j);
1236  }
1237 
1238  if (row[i][j] > max) {
1239  max = row[i][j];
1240  maxLoc_.set_ij(i, j);
1241  }
1242  }
1243  }
1244 
1245  if (minLoc != NULL)
1246  *minLoc = minLoc_;
1247 
1248  if (maxLoc != NULL)
1249  *maxLoc = maxLoc_;
1250 
1251  if (minVal != NULL)
1252  *minVal = min;
1253 
1254  if (maxVal != NULL)
1255  *maxVal = max;
1256 }
1257 
1262 {
1263  swap(*this, other);
1264  // Swap back display pointer if it was not null
1265  // vpImage<unsigned char> I2(480, 640);
1266  // vpDisplayX d(I2);
1267  // I2 = I1; //copy only the data
1268  if (other.display != NULL)
1269  display = other.display;
1270 
1271  return *this;
1272 }
1273 
1280 template <class Type> vpImage<Type> &vpImage<Type>::operator=(const Type &v)
1281 {
1282  for (unsigned int i = 0; i < npixels; i++)
1283  bitmap[i] = v;
1284 
1285  return *this;
1286 }
1287 
1293 template <class Type> bool vpImage<Type>::operator==(const vpImage<Type> &I) const
1294 {
1295  if (this->width != I.getWidth())
1296  return false;
1297  if (this->height != I.getHeight())
1298  return false;
1299 
1300  // printf("wxh: %dx%d bitmap: %p I.bitmap %p\n", width, height, bitmap,
1301  // I.bitmap);
1302  for (unsigned int i = 0; i < npixels; i++) {
1303  if (bitmap[i] != I.bitmap[i]) {
1304  // std::cout << "differ for pixel " << i << " (" << i%this->height
1305  // << ", " << i - i%this->height << ")" << std::endl;
1306  return false;
1307  }
1308  }
1309  return true;
1310 }
1316 template <class Type> bool vpImage<Type>::operator!=(const vpImage<Type> &I) const { return !(*this == I); }
1317 
1343 template <class Type> vpImage<Type> vpImage<Type>::operator-(const vpImage<Type> &B) const
1344 {
1345  vpImage<Type> C;
1346  sub(*this, B, C);
1347  return C;
1348 }
1349 
1361 template <class Type> void vpImage<Type>::insert(const vpImage<Type> &src, const vpImagePoint &topLeft)
1362 {
1363  int itl = (int)topLeft.get_i();
1364  int jtl = (int)topLeft.get_j();
1365 
1366  int dest_ibegin = 0;
1367  int dest_jbegin = 0;
1368  int src_ibegin = 0;
1369  int src_jbegin = 0;
1370  int dest_w = (int)this->getWidth();
1371  int dest_h = (int)this->getHeight();
1372  int src_w = (int)src.getWidth();
1373  int src_h = (int)src.getHeight();
1374  int wsize = (int)src.getWidth();
1375  int hsize = (int)src.getHeight();
1376 
1377  if (itl >= dest_h || jtl >= dest_w)
1378  return;
1379 
1380  if (itl < 0)
1381  src_ibegin = -itl;
1382  else
1383  dest_ibegin = itl;
1384 
1385  if (jtl < 0)
1386  src_jbegin = -jtl;
1387  else
1388  dest_jbegin = jtl;
1389 
1390  if (src_w - src_jbegin > dest_w - dest_jbegin)
1391  wsize = dest_w - dest_jbegin;
1392  else
1393  wsize = src_w - src_jbegin;
1394 
1395  if (src_h - src_ibegin > dest_h - dest_ibegin)
1396  hsize = dest_h - dest_ibegin;
1397  else
1398  hsize = src_h - src_ibegin;
1399 
1400  for (int i = 0; i < hsize; i++) {
1401  Type *srcBitmap = src.bitmap + ((src_ibegin + i) * src_w + src_jbegin);
1402  Type *destBitmap = this->bitmap + ((dest_ibegin + i) * dest_w + dest_jbegin);
1403 
1404  memcpy(static_cast<void *>(destBitmap), static_cast<void *>(srcBitmap), (size_t)wsize * sizeof(Type));
1405  }
1406 }
1407 
1438 template <class Type> void vpImage<Type>::halfSizeImage(vpImage<Type> &res) const
1439 {
1440  unsigned int h = height / 2;
1441  unsigned int w = width / 2;
1442  res.resize(h, w);
1443  for (unsigned int i = 0; i < h; i++)
1444  for (unsigned int j = 0; j < w; j++)
1445  res[i][j] = (*this)[i << 1][j << 1];
1446 }
1447 
1465 template <class Type>
1466 void vpImage<Type>::subsample(unsigned int v_scale, unsigned int h_scale, vpImage<Type> &sampled) const
1467 {
1468  if (v_scale == 1 && h_scale == 1) {
1469  sampled = (*this);
1470  return;
1471  }
1472  unsigned int h = height / v_scale;
1473  unsigned int w = width / h_scale;
1474  sampled.resize(h, w);
1475  for (unsigned int i = 0; i < h; i++)
1476  for (unsigned int j = 0; j < w; j++)
1477  sampled[i][j] = (*this)[i * v_scale][j * h_scale];
1478 }
1479 
1502 template <class Type> void vpImage<Type>::quarterSizeImage(vpImage<Type> &res) const
1503 {
1504  unsigned int h = height / 4;
1505  unsigned int w = width / 4;
1506  res.resize(h, w);
1507  for (unsigned int i = 0; i < h; i++)
1508  for (unsigned int j = 0; j < w; j++)
1509  res[i][j] = (*this)[i << 2][j << 2];
1510 }
1511 
1544 template <class Type> void vpImage<Type>::doubleSizeImage(vpImage<Type> &res)
1545 {
1546  int h = height * 2;
1547  int w = width * 2;
1548 
1549  res.resize(h, w);
1550 
1551  for (int i = 0; i < h; i++)
1552  for (int j = 0; j < w; j++)
1553  res[i][j] = (*this)[i >> 1][j >> 1];
1554 
1555  /*
1556  A B C
1557  E F G
1558  H I J
1559  A C H J are pixels from original image
1560  B E G I are interpolated pixels
1561  */
1562 
1563  // interpolate pixels B and I
1564  for (int i = 0; i < h; i += 2)
1565  for (int j = 1; j < w - 1; j += 2)
1566  res[i][j] = (Type)(0.5 * ((*this)[i >> 1][j >> 1] + (*this)[i >> 1][(j >> 1) + 1]));
1567 
1568  // interpolate pixels E and G
1569  for (int i = 1; i < h - 1; i += 2)
1570  for (int j = 0; j < w; j += 2)
1571  res[i][j] = (Type)(0.5 * ((*this)[i >> 1][j >> 1] + (*this)[(i >> 1) + 1][j >> 1]));
1572 
1573  // interpolate pixel F
1574  for (int i = 1; i < h - 1; i += 2)
1575  for (int j = 1; j < w - 1; j += 2)
1576  res[i][j] = (Type)(0.25 * ((*this)[i >> 1][j >> 1] + (*this)[i >> 1][(j >> 1) + 1] +
1577  (*this)[(i >> 1) + 1][j >> 1] + (*this)[(i >> 1) + 1][(j >> 1) + 1]));
1578 }
1579 
1592 template <class Type> inline Type vpImage<Type>::getValue(unsigned int i, unsigned int j) const
1593 {
1594  if (i >= height || j >= width) {
1595  throw(vpException(vpImageException::notInTheImage, "Pixel outside the image"));
1596  }
1597 
1598  return row[i][j];
1599 }
1600 
1617 template <class Type> Type vpImage<Type>::getValue(double i, double j) const
1618 {
1619  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1620  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1621  }
1622  if (height * width == 0) {
1623  throw vpException(vpImageException::notInitializedError, "Empty image!");
1624  }
1625 
1626  unsigned int iround = static_cast<unsigned int>(floor(i));
1627  unsigned int jround = static_cast<unsigned int>(floor(j));
1628 
1629  double rratio = i - static_cast<double>(iround);
1630  double cratio = j - static_cast<double>(jround);
1631 
1632  double rfrac = 1.0 - rratio;
1633  double cfrac = 1.0 - cratio;
1634 
1635  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1636  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1637 
1638  double value =
1639  (static_cast<double>(row[iround][jround]) * rfrac + static_cast<double>(row[iround_1][jround]) * rratio) * cfrac +
1640  (static_cast<double>(row[iround][jround_1]) * rfrac + static_cast<double>(row[iround_1][jround_1]) * rratio) *
1641  cratio;
1642 
1643  return static_cast<Type>(vpMath::round(value));
1644 }
1645 
1649 template <> inline double vpImage<double>::getValue(double i, double j) const
1650 {
1651  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1652  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1653  }
1654  if (height * width == 0) {
1655  throw vpException(vpImageException::notInitializedError, "Empty image!");
1656  }
1657 
1658  unsigned int iround = static_cast<unsigned int>(floor(i));
1659  unsigned int jround = static_cast<unsigned int>(floor(j));
1660 
1661  double rratio = i - static_cast<double>(iround);
1662  double cratio = j - static_cast<double>(jround);
1663 
1664  double rfrac = 1.0 - rratio;
1665  double cfrac = 1.0 - cratio;
1666 
1667  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1668  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1669 
1670  return (row[iround][jround] * rfrac + row[iround_1][jround] * rratio) * cfrac +
1671  (row[iround][jround_1] * rfrac + row[iround_1][jround_1] * rratio) * cratio;
1672 }
1673 
1677 template <> inline unsigned char vpImage<unsigned char>::getValue(double i, double j) const
1678 {
1679  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1680  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1681  }
1682  if (height * width == 0) {
1683  throw vpException(vpImageException::notInitializedError, "Empty image!");
1684  }
1685 
1686  // alpha architecture is bi-endianness. The following optimization makes testImageGetValue failing
1687 #if (defined(VISP_LITTLE_ENDIAN) || defined(VISP_BIG_ENDIAN)) && !(defined(__alpha__) || defined(_M_ALPHA))
1688  // Fixed-point arithmetic
1689  const int32_t precision = 1 << 16;
1690  int64_t y = static_cast<int64_t>(i * precision);
1691  int64_t x = static_cast<int64_t>(j * precision);
1692 
1693  int64_t iround = y & (~0xFFFF);
1694  int64_t jround = x & (~0xFFFF);
1695 
1696  int64_t rratio = y - iround;
1697  int64_t cratio = x - jround;
1698 
1699  int64_t rfrac = precision - rratio;
1700  int64_t cfrac = precision - cratio;
1701 
1702  int64_t x_ = x >> 16;
1703  int64_t y_ = y >> 16;
1704 
1705  if (y_ + 1 < height && x_ + 1 < width) {
1706  uint16_t up = vpEndian::reinterpret_cast_uchar_to_uint16_LE(bitmap + y_ * width + x_);
1707  uint16_t down = vpEndian::reinterpret_cast_uchar_to_uint16_LE(bitmap + (y_ + 1) * width + x_);
1708 
1709  return static_cast<unsigned char>((((up & 0x00FF) * rfrac + (down & 0x00FF) * rratio) * cfrac +
1710  ((up >> 8) * rfrac + (down >> 8) * rratio) * cratio) >>
1711  32);
1712  }
1713  else if (y_ + 1 < height) {
1714  return static_cast<unsigned char>(((row[y_][x_] * rfrac + row[y_ + 1][x_] * rratio)) >> 16);
1715  }
1716  else if (x_ + 1 < width) {
1717  uint16_t up = vpEndian::reinterpret_cast_uchar_to_uint16_LE(bitmap + y_ * width + x_);
1718  return static_cast<unsigned char>(((up & 0x00FF) * cfrac + (up >> 8) * cratio) >> 16);
1719  }
1720  else {
1721  return row[y_][x_];
1722  }
1723 #else
1724  unsigned int iround = static_cast<unsigned int>(floor(i));
1725  unsigned int jround = static_cast<unsigned int>(floor(j));
1726 
1727  if (iround >= height || jround >= width) {
1728  vpERROR_TRACE("Pixel outside the image");
1729  throw(vpException(vpImageException::notInTheImage, "Pixel outside the image"));
1730  }
1731 
1732  double rratio = i - static_cast<double>(iround);
1733  double cratio = j - static_cast<double>(jround);
1734 
1735  double rfrac = 1.0 - rratio;
1736  double cfrac = 1.0 - cratio;
1737 
1738  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1739  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1740 
1741  double value =
1742  (static_cast<double>(row[iround][jround]) * rfrac + static_cast<double>(row[iround_1][jround]) * rratio) * cfrac +
1743  (static_cast<double>(row[iround][jround_1]) * rfrac + static_cast<double>(row[iround_1][jround_1]) * rratio) *
1744  cratio;
1745  return static_cast<unsigned char>(vpMath::round(value));
1746 #endif
1747 }
1748 
1752 template <> inline vpRGBa vpImage<vpRGBa>::getValue(double i, double j) const
1753 {
1754  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1755  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1756  }
1757  if (height * width == 0) {
1758  throw vpException(vpImageException::notInitializedError, "Empty image!");
1759  }
1760 
1761  unsigned int iround = static_cast<unsigned int>(floor(i));
1762  unsigned int jround = static_cast<unsigned int>(floor(j));
1763 
1764  double rratio = i - static_cast<double>(iround);
1765  double cratio = j - static_cast<double>(jround);
1766 
1767  double rfrac = 1.0 - rratio;
1768  double cfrac = 1.0 - cratio;
1769 
1770  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1771  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1772 
1773  double valueR =
1774  (static_cast<double>(row[iround][jround].R) * rfrac + static_cast<double>(row[iround_1][jround].R) * rratio) *
1775  cfrac +
1776  (static_cast<double>(row[iround][jround_1].R) * rfrac + static_cast<double>(row[iround_1][jround_1].R) * rratio) *
1777  cratio;
1778  double valueG =
1779  (static_cast<double>(row[iround][jround].G) * rfrac + static_cast<double>(row[iround_1][jround].G) * rratio) *
1780  cfrac +
1781  (static_cast<double>(row[iround][jround_1].G) * rfrac + static_cast<double>(row[iround_1][jround_1].G) * rratio) *
1782  cratio;
1783  double valueB =
1784  (static_cast<double>(row[iround][jround].B) * rfrac + static_cast<double>(row[iround_1][jround].B) * rratio) *
1785  cfrac +
1786  (static_cast<double>(row[iround][jround_1].B) * rfrac + static_cast<double>(row[iround_1][jround_1].B) * rratio) *
1787  cratio;
1788 
1789  return vpRGBa(static_cast<unsigned char>(vpMath::round(valueR)), static_cast<unsigned char>(vpMath::round(valueG)),
1790  static_cast<unsigned char>(vpMath::round(valueB)));
1791 }
1792 
1796 template <> inline vpRGBf vpImage<vpRGBf>::getValue(double i, double j) const
1797 {
1798  if (i < 0 || j < 0 || i + 1 > height || j + 1 > width) {
1799  throw(vpException(vpImageException::notInTheImage, "Pixel outside of the image"));
1800  }
1801  if (height * width == 0) {
1802  throw vpException(vpImageException::notInitializedError, "Empty image!");
1803  }
1804 
1805  unsigned int iround = static_cast<unsigned int>(floor(i));
1806  unsigned int jround = static_cast<unsigned int>(floor(j));
1807 
1808  double rratio = i - static_cast<double>(iround);
1809  double cratio = j - static_cast<double>(jround);
1810 
1811  double rfrac = 1.0 - rratio;
1812  double cfrac = 1.0 - cratio;
1813 
1814  unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1815  unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1816 
1817  double valueR =
1818  (static_cast<double>(row[iround][jround].R) * rfrac + static_cast<double>(row[iround_1][jround].R) * rratio) *
1819  cfrac +
1820  (static_cast<double>(row[iround][jround_1].R) * rfrac + static_cast<double>(row[iround_1][jround_1].R) * rratio) *
1821  cratio;
1822  double valueG =
1823  (static_cast<double>(row[iround][jround].G) * rfrac + static_cast<double>(row[iround_1][jround].G) * rratio) *
1824  cfrac +
1825  (static_cast<double>(row[iround][jround_1].G) * rfrac + static_cast<double>(row[iround_1][jround_1].G) * rratio) *
1826  cratio;
1827  double valueB =
1828  (static_cast<double>(row[iround][jround].B) * rfrac + static_cast<double>(row[iround_1][jround].B) * rratio) *
1829  cfrac +
1830  (static_cast<double>(row[iround][jround_1].B) * rfrac + static_cast<double>(row[iround_1][jround_1].B) * rratio) *
1831  cratio;
1832 
1833  return vpRGBf(static_cast<float>(valueR), static_cast<float>(valueG), static_cast<float>(valueB));
1834 }
1835 
1852 template <class Type> inline Type vpImage<Type>::getValue(const vpImagePoint &ip) const
1853 {
1854  return getValue(ip.get_i(), ip.get_j());
1855 }
1856 
1860 template <> inline double vpImage<double>::getValue(const vpImagePoint &ip) const
1861 {
1862  return getValue(ip.get_i(), ip.get_j());
1863 }
1864 
1868 template <> inline unsigned char vpImage<unsigned char>::getValue(const vpImagePoint &ip) const
1869 {
1870  return getValue(ip.get_i(), ip.get_j());
1871 }
1872 
1876 template <> inline vpRGBa vpImage<vpRGBa>::getValue(const vpImagePoint &ip) const
1877 {
1878  return getValue(ip.get_i(), ip.get_j());
1879 }
1880 
1885 template <class Type> inline double vpImage<Type>::getSum() const
1886 {
1887  if ((height == 0) || (width == 0))
1888  return 0.0;
1889 
1890  double res = 0.0;
1891  for (unsigned int i = 0; i < height * width; ++i) {
1892  res += static_cast<double>(bitmap[i]);
1893  }
1894  return res;
1895 }
1896 
1900 template <> inline double vpImage<vpRGBa>::getSum() const
1901 {
1902  if ((height == 0) || (width == 0))
1903  return 0.0;
1904 
1905  double res = 0.0;
1906  for (unsigned int i = 0; i < height * width; ++i) {
1907  res += static_cast<double>(bitmap[i].R) + static_cast<double>(bitmap[i].G) + static_cast<double>(bitmap[i].B);
1908  }
1909  return res;
1910 }
1911 
1915 template <> inline double vpImage<vpRGBf>::getSum() const
1916 {
1917  if ((height == 0) || (width == 0))
1918  return 0.0;
1919 
1920  double res = 0.0;
1921  for (unsigned int i = 0; i < height * width; ++i) {
1922  res += static_cast<double>(bitmap[i].R) + static_cast<double>(bitmap[i].G) + static_cast<double>(bitmap[i].B);
1923  }
1924  return res;
1925 }
1926 
1956 template <class Type> void vpImage<Type>::sub(const vpImage<Type> &B, vpImage<Type> &C) const
1957 {
1958 
1959  try {
1960  if ((this->getHeight() != C.getHeight()) || (this->getWidth() != C.getWidth()))
1961  C.resize(this->getHeight(), this->getWidth());
1962  }
1963  catch (const vpException &me) {
1964  std::cout << me << std::endl;
1965  throw;
1966  }
1967 
1968  if ((this->getWidth() != B.getWidth()) || (this->getHeight() != B.getHeight())) {
1969  throw(vpException(vpException::memoryAllocationError, "vpImage mismatch in vpImage/vpImage subtraction"));
1970  }
1971 
1972  for (unsigned int i = 0; i < this->getWidth() * this->getHeight(); i++) {
1973  *(C.bitmap + i) = *(bitmap + i) - *(B.bitmap + i);
1974  }
1975 }
1976 
1988 template <class Type> void vpImage<Type>::sub(const vpImage<Type> &A, const vpImage<Type> &B, vpImage<Type> &C) const
1989 {
1990 
1991  try {
1992  if ((A.getHeight() != C.getHeight()) || (A.getWidth() != C.getWidth()))
1993  C.resize(A.getHeight(), A.getWidth());
1994  }
1995  catch (const vpException &me) {
1996  std::cout << me << std::endl;
1997  throw;
1998  }
1999 
2000  if ((A.getWidth() != B.getWidth()) || (A.getHeight() != B.getHeight())) {
2001  throw(vpException(vpException::memoryAllocationError, "vpImage mismatch in vpImage/vpImage subtraction "));
2002  }
2003 
2004  for (unsigned int i = 0; i < A.getWidth() * A.getHeight(); i++) {
2005  *(C.bitmap + i) = *(A.bitmap + i) - *(B.bitmap + i);
2006  }
2007 }
2008 
2017 template <class Type> void vpImage<Type>::performLut(const Type(&)[256], unsigned int)
2018 {
2019  std::cerr << "Not implemented !" << std::endl;
2020 }
2021 
2032 template <> inline void vpImage<unsigned char>::performLut(const unsigned char(&lut)[256], unsigned int nbThreads)
2033 {
2034  unsigned int size = getWidth() * getHeight();
2035  unsigned char *ptrStart = (unsigned char *)bitmap;
2036  unsigned char *ptrEnd = ptrStart + size;
2037  unsigned char *ptrCurrent = ptrStart;
2038 
2039  bool use_single_thread = (nbThreads == 0 || nbThreads == 1);
2040 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
2041  use_single_thread = true;
2042 #endif
2043 
2044  if (!use_single_thread && getSize() <= nbThreads) {
2045  use_single_thread = true;
2046  }
2047 
2048  if (use_single_thread) {
2049  // Single thread
2050 
2051  while (ptrCurrent != ptrEnd) {
2052  *ptrCurrent = lut[*ptrCurrent];
2053  ++ptrCurrent;
2054  }
2055  }
2056  else {
2057 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
2058  // Multi-threads
2059 
2060  std::vector<vpThread *> threadpool;
2061  std::vector<vpImageLut_Param_t *> imageLutParams;
2062 
2063  unsigned int image_size = getSize();
2064  unsigned int step = image_size / nbThreads;
2065  unsigned int last_step = image_size - step * (nbThreads - 1);
2066 
2067  for (unsigned int index = 0; index < nbThreads; index++) {
2068  unsigned int start_index = index * step;
2069  unsigned int end_index = (index + 1) * step;
2070 
2071  if (index == nbThreads - 1) {
2072  end_index = start_index + last_step;
2073  }
2074 
2075  vpImageLut_Param_t *imageLut_param = new vpImageLut_Param_t(start_index, end_index, bitmap);
2076  memcpy(imageLut_param->m_lut, lut, 256 * sizeof(unsigned char));
2077 
2078  imageLutParams.push_back(imageLut_param);
2079 
2080  // Start the threads
2081  vpThread *imageLut_thread = new vpThread((vpThread::Fn)performLutThread, (vpThread::Args)imageLut_param);
2082  threadpool.push_back(imageLut_thread);
2083  }
2084 
2085  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2086  // Wait until thread ends up
2087  threadpool[cpt]->join();
2088  }
2089 
2090  // Delete
2091  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2092  delete threadpool[cpt];
2093  }
2094 
2095  for (size_t cpt = 0; cpt < imageLutParams.size(); cpt++) {
2096  delete imageLutParams[cpt];
2097  }
2098 #endif
2099  }
2100 }
2101 
2112 template <> inline void vpImage<vpRGBa>::performLut(const vpRGBa(&lut)[256], unsigned int nbThreads)
2113 {
2114  unsigned int size = getWidth() * getHeight();
2115  unsigned char *ptrStart = (unsigned char *)bitmap;
2116  unsigned char *ptrEnd = ptrStart + size * 4;
2117  unsigned char *ptrCurrent = ptrStart;
2118 
2119  bool use_single_thread = (nbThreads == 0 || nbThreads == 1);
2120 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
2121  use_single_thread = true;
2122 #endif
2123 
2124  if (!use_single_thread && getSize() <= nbThreads) {
2125  use_single_thread = true;
2126  }
2127 
2128  if (use_single_thread) {
2129  // Single thread
2130  while (ptrCurrent != ptrEnd) {
2131  *ptrCurrent = lut[*ptrCurrent].R;
2132  ++ptrCurrent;
2133 
2134  *ptrCurrent = lut[*ptrCurrent].G;
2135  ++ptrCurrent;
2136 
2137  *ptrCurrent = lut[*ptrCurrent].B;
2138  ++ptrCurrent;
2139 
2140  *ptrCurrent = lut[*ptrCurrent].A;
2141  ++ptrCurrent;
2142  }
2143  }
2144  else {
2145 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
2146  // Multi-threads
2147  std::vector<vpThread *> threadpool;
2148  std::vector<vpImageLutRGBa_Param_t *> imageLutParams;
2149 
2150  unsigned int image_size = getSize();
2151  unsigned int step = image_size / nbThreads;
2152  unsigned int last_step = image_size - step * (nbThreads - 1);
2153 
2154  for (unsigned int index = 0; index < nbThreads; index++) {
2155  unsigned int start_index = index * step;
2156  unsigned int end_index = (index + 1) * step;
2157 
2158  if (index == nbThreads - 1) {
2159  end_index = start_index + last_step;
2160  }
2161 
2162  vpImageLutRGBa_Param_t *imageLut_param = new vpImageLutRGBa_Param_t(start_index, end_index, (unsigned char *)bitmap);
2163  memcpy(static_cast<void *>(imageLut_param->m_lut), lut, 256 * sizeof(vpRGBa));
2164 
2165  imageLutParams.push_back(imageLut_param);
2166 
2167  // Start the threads
2168  vpThread *imageLut_thread = new vpThread((vpThread::Fn)performLutRGBaThread, (vpThread::Args)imageLut_param);
2169  threadpool.push_back(imageLut_thread);
2170  }
2171 
2172  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2173  // Wait until thread ends up
2174  threadpool[cpt]->join();
2175  }
2176 
2177  // Delete
2178  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
2179  delete threadpool[cpt];
2180  }
2181 
2182  for (size_t cpt = 0; cpt < imageLutParams.size(); cpt++) {
2183  delete imageLutParams[cpt];
2184  }
2185 #endif
2186  }
2187 }
2188 
2189 template <class Type> void swap(vpImage<Type> &first, vpImage<Type> &second)
2190 {
2191  using std::swap;
2192  swap(first.bitmap, second.bitmap);
2193  swap(first.display, second.display);
2194  swap(first.npixels, second.npixels);
2195  swap(first.width, second.width);
2196  swap(first.height, second.height);
2197  swap(first.row, second.row);
2198 }
2199 
2200 #endif
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
Definition: vpArray2D.h:529
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:313
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:290
void destroy()
Destructor : Memory de-allocation.
Definition: vpImage.h:824
void subsample(unsigned int v_scale, unsigned int h_scale, vpImage< Type > &sampled) const
Definition: vpImage.h:1466
void halfSizeImage(vpImage< Type > &res) const
Definition: vpImage.h:1438
vpImage< Type > & operator=(vpImage< Type > other)
Copy operator.
Definition: vpImage.h:1261
Type * operator[](int i)
Definition: vpImage.h:260
Type getMeanValue() const
Return the mean value of the bitmap.
Definition: vpImage.h:963
Type getMinValue(bool onlyFiniteVal=true) const
Return the minimum value within the bitmap.
Definition: vpImage.h:978
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:1223
void quarterSizeImage(vpImage< Type > &res) const
Definition: vpImage.h:1502
void init(unsigned int height, unsigned int width)
Set the size of the image.
Definition: vpImage.h:639
Type * operator[](unsigned int i)
operator[] allows operation like I[i] = x.
Definition: vpImage.h:259
void resize(unsigned int h, unsigned int w, const Type &val)
resize the image : Image initialization
Definition: vpImage.h:816
unsigned int getWidth() const
Definition: vpImage.h:242
friend std::ostream & operator<<(std::ostream &s, const vpImage< unsigned char > &I)
Definition: vpImage.h:378
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:795
unsigned int getNumberOfPixel() const
Definition: vpImage.h:205
Type getValue(double i, double j) const
Definition: vpImage.h:1617
void doubleSizeImage(vpImage< Type > &res)
Definition: vpImage.h:1544
vpImage(unsigned int height, unsigned int width, Type value)
constructor set the size of the image and init all the pixel
Definition: vpImage.h:752
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage.h:2017
const Type * operator[](int i) const
Definition: vpImage.h:264
friend std::ostream & operator<<(std::ostream &s, const vpImage< float > &I)
Definition: vpImage.h:430
bool operator==(const vpImage< Type > &I) const
Definition: vpImage.h:1293
void insert(const vpImage< Type > &src, const vpImagePoint &topLeft)
Definition: vpImage.h:1361
void sub(const vpImage< Type > &A, const vpImage< Type > &B, vpImage< Type > &C) const
Definition: vpImage.h:1988
Type getValue(unsigned int i, unsigned int j) const
Definition: vpImage.h:1592
double getValue(double i, double j) const
Definition: vpImage.h:1649
double getSum() const
Definition: vpImage.h:1885
vpImage< Type > operator-(const vpImage< Type > &B) const
Definition: vpImage.h:1343
void init(unsigned int height, unsigned int width, Type value)
Set the size of the image.
Definition: vpImage.h:627
unsigned int getSize() const
Definition: vpImage.h:223
friend void swap(vpImage< Type > &first, vpImage< Type > &second)
Definition: vpImage.h:2189
unsigned int getCols() const
Definition: vpImage.h:175
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:263
Type getValue(const vpImagePoint &ip) const
Definition: vpImage.h:1852
void sub(const vpImage< Type > &B, vpImage< Type > &C) const
Definition: vpImage.h:1956
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:762
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:686
Type getMaxValue(bool onlyFiniteVal=true) const
Return the maximum value within the bitmap.
Definition: vpImage.h:890
virtual ~vpImage()
destructor
Definition: vpImage.h:851
unsigned int getHeight() const
Definition: vpImage.h:184
unsigned int getRows() const
Definition: vpImage.h:214
friend std::ostream & operator<<(std::ostream &s, const vpImage< double > &I)
Definition: vpImage.h:457
void getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal=true) const
Look for the minimum and the maximum value within the bitmap.
Definition: vpImage.h:1054
vpImage< Type > & operator=(const Type &v)
= operator : Set all the element of the bitmap to a given value v.
Definition: vpImage.h:1280
vpDisplay * display
Definition: vpImage.h:140
vpImage()
constructor
Definition: vpImage.h:772
friend std::ostream & operator<<(std::ostream &s, const vpImage< char > &I)
Definition: vpImage.h:404
void operator()(const vpImagePoint &ip, const Type &v)
Definition: vpImage.h:306
Type operator()(unsigned int i, unsigned int j) const
Definition: vpImage.h:272
bool operator!=(const vpImage< Type > &I) const
Definition: vpImage.h:1316
vpImage(vpImage< Type > &&)
move constructor
Definition: vpImage.h:869
void init(unsigned int h, unsigned int w, Type value)
Definition: vpImage.h:627
vpImage(const vpImage< Type > &)
copy constructor
Definition: vpImage.h:857
vpImage(unsigned int height, unsigned int width)
constructor set the size of the image
Definition: vpImage.h:742
void operator()(unsigned int i, unsigned int j, const Type &v)
Definition: vpImage.h:278
static int round(double x)
Definition: vpMath.h:323
static bool isFinite(double value)
Definition: vpMath.cpp:178
Definition: vpRGBa.h:61
Definition: vpRGBf.h:57
float B
Blue component.
Definition: vpRGBf.h:127
float G
Green component.
Definition: vpRGBf.h:126
float R
Red component.
Definition: vpRGBf.h:125
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