Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
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)
63typedef long long int64_t;
64typedef unsigned short uint16_t;
65#else
66#include <inttypes.h>
67#endif
68
69class vpDisplay;
70
121// Ref: http://en.cppreference.com/w/cpp/language/friend#Template_friends
122template <class Type> class vpImage; // forward declare to make function declaration possible
123
124// declarations
125template <class Type> std::ostream &operator<<(std::ostream &, const vpImage<Type> &);
126
127std::ostream &operator<<(std::ostream &, const vpImage<unsigned char> &);
128std::ostream &operator<<(std::ostream &, const vpImage<char> &);
129std::ostream &operator<<(std::ostream &, const vpImage<float> &);
130std::ostream &operator<<(std::ostream &, const vpImage<double> &);
131
132template <class Type> void swap(vpImage<Type> &first, vpImage<Type> &second);
133
134template <class Type> class vpImage
135{
136 friend class vpImageConvert;
137
138public:
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
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
347private:
348 unsigned int npixels;
349 unsigned int width;
350 unsigned int height;
351 Type **row;
352 bool hasOwnership;
353};
354
355template <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
378inline 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
404inline 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
430inline 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
457inline 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))
485namespace
486{
487struct 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
502vpThread::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
555struct 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
570vpThread::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
627template <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
639template <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
686template <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
741template <class Type>
742vpImage<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
751template <class Type>
752vpImage<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
761template <class Type>
762vpImage<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
771template <class Type>
772vpImage<Type>::vpImage() : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
773{ }
774
795template <class Type> void vpImage<Type>::resize(unsigned int h, unsigned int w) { init(h, w); }
796
816template <class Type> void vpImage<Type>::resize(unsigned int h, unsigned int w, const Type &val) { init(h, w, val); }
817
824template <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
851template <class Type> vpImage<Type>::~vpImage() { destroy(); }
852
856template <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)
868template <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
890template <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
912template <> 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
940template <> 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
963template <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
978template <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
1000template <> 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
1026template <> 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
1054template <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
1080template <> 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
1117template <> 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
1153template <> 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
1222template <class Type>
1223void 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
1280template <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
1293template <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}
1316template <class Type> bool vpImage<Type>::operator!=(const vpImage<Type> &I) const { return !(*this == I); }
1317
1343template <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
1361template <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
1438template <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
1465template <class Type>
1466void 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
1502template <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
1544template <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
1592template <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
1617template <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) {
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
1649template <> 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) {
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
1677template <> 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) {
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
1752template <> 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) {
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
1796template <> 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) {
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
1852template <class Type> inline Type vpImage<Type>::getValue(const vpImagePoint &ip) const
1853{
1854 return getValue(ip.get_i(), ip.get_j());
1855}
1856
1860template <> inline double vpImage<double>::getValue(const vpImagePoint &ip) const
1861{
1862 return getValue(ip.get_i(), ip.get_j());
1863}
1864
1868template <> inline unsigned char vpImage<unsigned char>::getValue(const vpImagePoint &ip) const
1869{
1870 return getValue(ip.get_i(), ip.get_j());
1871}
1872
1876template <> inline vpRGBa vpImage<vpRGBa>::getValue(const vpImagePoint &ip) const
1877{
1878 return getValue(ip.get_i(), ip.get_j());
1879}
1880
1885template <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
1900template <> 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
1915template <> 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
1956template <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
1988template <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
2017template <class Type> void vpImage<Type>::performLut(const Type(&)[256], unsigned int)
2018{
2019 std::cerr << "Not implemented !" << std::endl;
2020}
2021
2032template <> 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
2112template <> 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
2189template <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
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 ...
double get_j() const
void set_ij(double ii, double jj)
double get_i() const
Definition of the vpImage class member functions.
Definition vpImage.h:135
Type operator()(const vpImagePoint &ip) const
Definition vpImage.h:290
friend std::ostream & operator<<(std::ostream &s, const vpImage< float > &I)
Definition vpImage.h:430
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 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
friend std::ostream & operator<<(std::ostream &s, const vpImage< char > &I)
Definition vpImage.h:404
const Type * operator[](int i) const
Definition vpImage.h:264
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
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
Type getValue(double i, double j) const
Definition vpImage.h:1617
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
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
friend std::ostream & operator<<(std::ostream &s, const vpImage< Type > &I)
Definition vpImage.h:355
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition vpImage.h:2017
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
Type * operator[](unsigned int i)
operator[] allows operation like I[i] = x.
Definition vpImage.h:259
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
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 * operator[](int i)
Definition vpImage.h:260
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
Type getValue(const vpImagePoint &ip) const
Definition vpImage.h:1852
unsigned int getRows() const
Definition vpImage.h:214
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
friend std::ostream & operator<<(std::ostream &s, const vpImage< double > &I)
Definition vpImage.h:457
vpImage()
constructor
Definition vpImage.h:772
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
friend std::ostream & operator<<(std::ostream &s, const vpImage< unsigned char > &I)
Definition vpImage.h:378
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
unsigned char B
Blue component.
Definition vpRGBa.h:140
unsigned char R
Red component.
Definition vpRGBa.h:138
unsigned char G
Green component.
Definition vpRGBa.h:139
unsigned char A
Additionnal component.
Definition vpRGBa.h:141
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 * Args
Definition vpThread.h:72
void * Return
Definition vpThread.h:73
#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