PCL
Image.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.7.0
6 // ----------------------------------------------------------------------------
7 // pcl/Image.h - Released 2024-06-18T15:48:54Z
8 // ----------------------------------------------------------------------------
9 // This file is part of the PixInsight Class Library (PCL).
10 // PCL is a multiplatform C++ framework for development of PixInsight modules.
11 //
12 // Copyright (c) 2003-2024 Pleiades Astrophoto S.L. All Rights Reserved.
13 //
14 // Redistribution and use in both source and binary forms, with or without
15 // modification, is permitted provided that the following conditions are met:
16 //
17 // 1. All redistributions of source code must retain the above copyright
18 // notice, this list of conditions and the following disclaimer.
19 //
20 // 2. All redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
25 // of their contributors, may be used to endorse or promote products derived
26 // from this software without specific prior written permission. For written
27 // permission, please contact info@pixinsight.com.
28 //
29 // 4. All products derived from this software, in any form whatsoever, must
30 // reproduce the following acknowledgment in the end-user documentation
31 // and/or other materials provided with the product:
32 //
33 // "This product is based on software from the PixInsight project, developed
34 // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
35 //
36 // Alternatively, if that is where third-party acknowledgments normally
37 // appear, this acknowledgment must be reproduced in the product itself.
38 //
39 // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
40 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
43 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
45 // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
46 // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 // POSSIBILITY OF SUCH DAMAGE.
50 // ----------------------------------------------------------------------------
51 
52 #ifndef __PCL_Image_h
53 #define __PCL_Image_h
54 
56 
57 #include <pcl/Defs.h>
58 #include <pcl/Diagnostics.h>
59 
60 #include <pcl/AbstractImage.h>
61 #include <pcl/AutoLock.h>
62 #include <pcl/Complex.h>
63 #include <pcl/Compression.h>
64 #include <pcl/File.h>
65 #include <pcl/Mutex.h>
66 #include <pcl/PixelAllocator.h>
67 #include <pcl/PixelTraits.h>
68 #include <pcl/ReferenceArray.h>
69 #include <pcl/Vector.h>
70 
71 #ifndef __PCL_IMAGE_NO_BITMAP
72 # ifdef __PCL_BUILDING_PIXINSIGHT_APPLICATION
73 # ifndef __PI_Bitmap_h
74 # include <API/Bitmap.h> // using server-side bitmaps
75 # endif
76 using namespace pi;
77 # else
78 # ifndef __PCL_Bitmap_h
79 # include <pcl/Bitmap.h> // using client-side bitmaps
80 # endif
81 # endif
82 # ifndef __PCL_Color_h
83 # include <pcl/Color.h> // for RGBA
84 # endif
85 #endif
86 
87 #ifdef __PCL_BUILDING_PIXINSIGHT_APPLICATION
88 namespace pi
89 {
90  class SharedImage;
91 }
92 #endif
93 
94 namespace pcl
95 {
96 
97 // ----------------------------------------------------------------------------
98 
136 namespace ImageOp
137 {
138  enum value_type
139  {
140  Nop, // No operation
141  Mov, // a = b
142  Add, // a + b
143  Sub, // a - b
144  Mul, // a * b
145  Div, // a / b
146  Pow, // Pow( a, b )
147  Dif, // |a - b|
148  Min, // Min( a, b )
149  Max, // Max( a, b )
150  Or, // a | b
151  And, // a & b
152  Xor, // a ^ b
153  Not, // ~a
154  Nor, // ~(a | b)
155  Nand, // ~(a & b)
156  Xnor, // ~(a ^ b)
157  ColorBurn, // 1 - Min( (1 - a)/b, 1 )
158  LinearBurn, // a + b - 1
159  Screen, // 1 - (1 - a)*(1 - b)
160  ColorDodge, // Min( a/(1 - b), 1 )
161  Overlay, // (a > 0.5) ? 1 - ((1 - 2*(a - 0.5)) * (1 - b)) : 2*a*b
162  SoftLight, // (b > 0.5) ? 1 - (1 - a)*(1 - b - 0.5) : a*(b + 0.5)
163  HardLight, // (b > 0.5) ? 1 - (1 - a)*(1 - 2*(b - 0.5)) : 2*a*b
164  VividLight, // (b > 0.5) ? 1 - Max( (1 - a)/(b - 0.5)/2, 1.0 ) : Min( a/(1 - 2*b ), 1.0 )
165  LinearLight, // (b > 0.5) ? Max( a + 2*(b - 0.5), 1.0 ) : Max( a + 2*b - 1, 1.0 )
166  PinLight, // (b > 0.5) ? Max( a, 2*(b - 0.5) ) : Min( a, 2*b )
167  Exclusion, // 0.5 - 2*(a - 0.5)*(b - 0.5)
168  NumberOfOperators
169  };
170 
174  inline bool IsArithmeticOperator( int op ) noexcept
175  {
176  return op >= Add && op <= Dif;
177  }
178 
183  inline bool IsBitwiseLogicalOperator( int op ) noexcept
184  {
185  return op >= Or && op <= Xnor;
186  }
187 
192  inline bool IsMoveOperator( int op ) noexcept
193  {
194  return op == Mov || op == Min || op == Max;
195  }
196 
201  inline bool IsPixelCompositionOperator( int op ) noexcept
202  {
203  return op >= ColorBurn && op <= Exclusion;
204  }
205 
209  String Id( value_type operation );
210 }
211 
212 // ----------------------------------------------------------------------------
213 
214 #define m_pixelData m_data->data
215 #define m_channelData( c ) reinterpret_cast<sample*>( PCL_ASSUME_ALIGNED_32( m_pixelData[c] ) )
216 #define m_allocator m_data->allocator
217 
218 #define m_width m_geometry->width
219 #define m_height m_geometry->height
220 #define m_numberOfChannels m_geometry->numberOfChannels
221 
222 #define m_colorSpace m_color->colorSpace
223 #define m_RGBWS m_color->RGBWS
224 
225 #define m_channel m_selected.channel
226 #define m_lastChannel m_selected.lastChannel
227 #define m_point m_selected.point
228 #define m_rectangle m_selected.rectangle
229 #define m_clipLow m_selected.clipLow
230 #define m_clipHigh m_selected.clipHigh
231 #define m_clippedLow m_selected.clippedLow
232 #define m_clippedHigh m_selected.clippedHigh
233 
234 // ----------------------------------------------------------------------------
235 
236 class PCL_CLASS ImageVariant;
237 class PCL_CLASS ImageTransformation;
238 class PCL_CLASS BidirectionalImageTransformation;
239 
240 // ----------------------------------------------------------------------------
241 
276 template <class P>
277 class PCL_CLASS GenericImage : public AbstractImage
278 {
279 public:
280 
288  using pixel_traits = P;
289 
300 
305  using sample = typename pixel_traits::sample;
306 
312  using color_space = AbstractImage::color_space;
313 
319 
325  using image_op = ImageOp::value_type;
326 
331 
336 
337  // -------------------------------------------------------------------------
338 
343  // -------------------------------------------------------------------------
344 
355  {
356  public:
357 
362 
367 
371  using sample = typename image_type::sample;
372 
376  sample_iterator() = default;
377 
391  sample_iterator( image_type& image, int channel = -1 )
392  : m_image( &image )
393  {
394  m_image->EnsureUnique();
395  if ( m_image->ParseChannel( channel ) )
396  {
397  m_iterator = (*m_image)[channel];
398  m_end = m_iterator + m_image->NumberOfPixels();
399  }
400  }
401 
419  : m_image( &image )
420  , m_iterator( i )
421  , m_end( j )
422  {
423  }
424 
428  sample_iterator( const sample_iterator& ) = default;
429 
433  sample_iterator& operator =( const sample_iterator& ) = default;
434 
439  bool IsValid() const noexcept
440  {
441  return m_image != nullptr && m_iterator != nullptr;
442  }
443 
447  image_type& Image() const noexcept
448  {
449  return *m_image;
450  }
451 
455  sample* Position() const noexcept
456  {
457  return m_iterator;
458  }
459 
467  operator bool() const noexcept
468  {
469  return m_iterator < m_end;
470  }
471 
476  sample& operator *() const noexcept
477  {
478  return *m_iterator;
479  }
480 
486  sample_iterator& operator ++() noexcept
487  {
488  ++m_iterator;
489  return *this;
490  }
491 
497  sample_iterator operator ++( int ) noexcept
498  {
499  return sample_iterator( *m_image, m_iterator++, m_end );
500  }
501 
507  sample_iterator& operator --() noexcept
508  {
509  --m_iterator;
510  return *this;
511  }
512 
518  sample_iterator operator --( int ) noexcept
519  {
520  return sample_iterator( *m_image, m_iterator--, m_end );
521  }
522 
530  sample_iterator& operator +=( distance_type delta ) noexcept
531  {
532  m_iterator += delta;
533  return *this;
534  }
535 
543  sample_iterator& operator -=( distance_type delta ) noexcept
544  {
545  m_iterator -= delta;
546  return *this;
547  }
548 
556  sample_iterator& MoveBy( int dx, int dy ) noexcept
557  {
558  m_iterator += distance_type( dy )*m_image->Width() + distance_type( dx );
559  return *this;
560  }
561 
566  friend sample_iterator operator +( const sample_iterator& i, distance_type delta ) noexcept
567  {
568  return sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
569  }
570 
575  friend sample_iterator operator +( distance_type delta, const sample_iterator& i ) noexcept
576  {
577  return sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
578  }
579 
584  friend sample_iterator operator -( const sample_iterator& i, distance_type delta ) noexcept
585  {
586  return sample_iterator( *i.m_image, i.m_iterator - delta, i.m_end );
587  }
588 
593  friend distance_type operator -( const sample_iterator& i, const sample_iterator& j ) noexcept
594  {
595  return i.m_iterator - j.m_iterator;
596  }
597 
602  friend distance_type operator -( const sample_iterator& i, const sample* j ) noexcept
603  {
604  return i.m_iterator - j;
605  }
606 
611  friend distance_type operator -( const sample* i, const sample_iterator& j ) noexcept
612  {
613  return i - j.m_iterator;
614  }
615 
620  friend bool operator ==( const sample_iterator& i, const sample_iterator& j ) noexcept
621  {
622  return i.m_iterator == j.m_iterator;
623  }
624 
629  friend bool operator ==( const sample_iterator& i, const sample* j ) noexcept
630  {
631  return i.m_iterator == j;
632  }
633 
638  friend bool operator ==( const sample* i, const sample_iterator& j ) noexcept
639  {
640  return i == j.m_iterator;
641  }
642 
647  friend bool operator <( const sample_iterator& i, const sample_iterator& j ) noexcept
648  {
649  return i.m_iterator < j.m_iterator;
650  }
651 
655  friend bool operator <( const sample_iterator& i, const sample* j ) noexcept
656  {
657  return i.m_iterator < j;
658  }
659 
663  friend bool operator <( const sample* i, const sample_iterator& j ) noexcept
664  {
665  return i < j.m_iterator;
666  }
667 
668  protected:
669 
670  image_type* m_image = nullptr;
671  sample* __restrict__ m_iterator = nullptr;
672  const sample* __restrict__ m_end = nullptr;
673 
674  friend class const_sample_iterator;
675  };
676 
677  // -------------------------------------------------------------------------
678 
689  {
690  public:
691 
696 
701 
705  using sample = typename image_type::sample;
706 
711 
725  const_sample_iterator( const image_type& image, int channel = -1 )
726  : m_image( &image )
727  {
728  if ( m_image->ParseChannel( channel ) )
729  {
730  m_iterator = (*m_image)[channel];
731  m_end = m_iterator + m_image->NumberOfPixels();
732  }
733  }
734 
751  const_sample_iterator( const image_type& image, const sample* i, const sample* j )
752  : m_image( &image )
753  , m_iterator( i )
754  , m_end( j )
755  {
756  }
757 
766  : m_image( i.m_image )
767  , m_iterator( i.m_iterator )
768  , m_end( i.m_end )
769  {
770  }
771 
776 
781  const_sample_iterator& operator =( const sample_iterator& i ) noexcept
782  {
783  m_image = i.m_image;
784  m_iterator = i.m_iterator;
785  m_end = i.m_end;
786  return *this;
787  }
788 
792  const_sample_iterator& operator =( const const_sample_iterator& ) = default;
793 
798  bool IsValid() const noexcept
799  {
800  return m_image != nullptr && m_iterator != nullptr;
801  }
802 
807  const image_type& Image() const noexcept
808  {
809  return *m_image;
810  }
811 
816  const sample* Position() const noexcept
817  {
818  return m_iterator;
819  }
820 
828  operator bool() const noexcept
829  {
830  return m_iterator < m_end;
831  }
832 
837  const sample& operator *() const noexcept
838  {
839  return *m_iterator;
840  }
841 
847  const_sample_iterator& operator ++() noexcept
848  {
849  ++m_iterator;
850  return *this;
851  }
852 
858  const_sample_iterator operator ++( int ) noexcept
859  {
860  return const_sample_iterator( *m_image, m_iterator++, m_end );
861  }
862 
868  const_sample_iterator& operator --() noexcept
869  {
870  --m_iterator;
871  return *this;
872  }
873 
879  const_sample_iterator operator --( int ) noexcept
880  {
881  return const_sample_iterator( *m_image, m_iterator--, m_end );
882  }
883 
891  const_sample_iterator& operator +=( distance_type delta ) noexcept
892  {
893  m_iterator += delta;
894  return *this;
895  }
896 
904  const_sample_iterator& operator -=( distance_type delta ) noexcept
905  {
906  m_iterator -= delta;
907  return *this;
908  }
909 
917  const_sample_iterator& MoveBy( int dx, int dy ) noexcept
918  {
919  m_iterator += distance_type( dy )*m_image->Width() + distance_type( dx );
920  return *this;
921  }
922 
928  {
929  return const_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
930  }
931 
937  {
938  return const_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
939  }
940 
946  {
947  return const_sample_iterator( *i.m_image, i.m_iterator - delta, i.m_end );
948  }
949 
955  {
956  return i.m_iterator - j.m_iterator;
957  }
958 
963  friend distance_type operator -( const const_sample_iterator& i, const sample* j ) noexcept
964  {
965  return i.m_iterator - j;
966  }
967 
972  friend distance_type operator -( const sample* i, const const_sample_iterator& j ) noexcept
973  {
974  return i - j.m_iterator;
975  }
976 
981  friend bool operator ==( const const_sample_iterator& i, const const_sample_iterator& j ) noexcept
982  {
983  return i.m_iterator == j.m_iterator;
984  }
985 
990  friend bool operator ==( const const_sample_iterator& i, const sample* j ) noexcept
991  {
992  return i.m_iterator == j;
993  }
994 
999  friend bool operator ==( const sample* i, const const_sample_iterator& j ) noexcept
1000  {
1001  return i == j.m_iterator;
1002  }
1003 
1008  friend bool operator <( const const_sample_iterator& i, const const_sample_iterator& j ) noexcept
1009  {
1010  return i.m_iterator < j.m_iterator;
1011  }
1012 
1016  friend bool operator <( const const_sample_iterator& i, const sample* j ) noexcept
1017  {
1018  return i.m_iterator < j;
1019  }
1020 
1024  friend bool operator <( const sample* i, const const_sample_iterator& j ) noexcept
1025  {
1026  return i < j.m_iterator;
1027  }
1028 
1029  protected:
1030 
1031  const image_type* m_image = nullptr;
1032  const sample* __restrict__ m_iterator = nullptr;
1033  const sample* __restrict__ m_end = nullptr;
1034  };
1035 
1036  // -------------------------------------------------------------------------
1037 
1038  template <class image_type, class sample_pointer>
1039  class roi_sample_iterator_base
1040  {
1041  protected:
1042 
1043  image_type* m_image = nullptr;
1044  sample_pointer m_iterator = nullptr;
1045  sample_pointer m_rowBegin = nullptr;
1046  sample_pointer m_rowEnd = nullptr;
1047  sample_pointer m_end = nullptr;
1048 
1049  roi_sample_iterator_base() = default;
1050 
1051  roi_sample_iterator_base( image_type& image, const Rect& rect, int channel )
1052  : m_image( &image )
1053  {
1054  Rect r = rect;
1055  if ( m_image->ParseRect( r ) )
1056  {
1057  if ( m_image->ParseChannel( channel ) )
1058  {
1059  m_iterator = m_rowBegin = m_image->PixelAddress( r.x0, r.y0, channel );
1060  m_rowEnd = m_rowBegin + r.Width();
1061  m_end = m_rowEnd + ((r.Height() - 1)*m_image->Width());
1062  }
1063  }
1064  }
1065 
1066  roi_sample_iterator_base( image_type& image, sample_pointer i, sample_pointer j )
1067  : m_image( &image )
1068  {
1069  if ( j < i )
1070  pcl::Swap( i, j );
1071  m_iterator = m_rowBegin = i;
1072  m_rowEnd = m_rowBegin + (j - i)%m_image->Width();
1073  m_end = j;
1074  }
1075 
1076  roi_sample_iterator_base( const roi_sample_iterator_base& i ) = default;
1077 
1078  roi_sample_iterator_base& operator =( const roi_sample_iterator_base& ) = default;
1079 
1080  void Increment() noexcept
1081  {
1082  if ( ++m_iterator == m_rowEnd )
1083  {
1084  m_rowBegin += m_image->Width();
1085  m_rowEnd += m_image->Width();
1086  m_iterator = m_rowBegin;
1087  }
1088  }
1089 
1090  void Decrement() noexcept
1091  {
1092  if ( m_iterator == m_rowBegin )
1093  {
1094  m_rowBegin -= m_image->Width();
1095  m_rowEnd -= m_image->Width();
1096  m_iterator = m_rowEnd;
1097  }
1098  --m_iterator;
1099  }
1100 
1101  void MoveBy( int cols, int rows ) noexcept
1102  {
1103  cols += m_iterator - m_rowBegin;
1104  if ( cols != 0 )
1105  {
1106  int w = m_rowEnd - m_rowBegin;
1107  if ( pcl::Abs( cols ) >= w )
1108  {
1109  rows += cols/w;
1110  cols %= w;
1111  }
1112  }
1113  int dy = rows * m_image->Width();
1114  m_rowBegin += dy;
1115  m_rowEnd += dy;
1116  m_iterator = m_rowBegin + cols;
1117  }
1118  };
1119 
1120  // -------------------------------------------------------------------------
1121 
1132  class roi_sample_iterator : private roi_sample_iterator_base<GenericImage<P>, sample*>
1133  {
1134  public:
1135 
1140 
1145 
1149  using sample = typename image_type::sample;
1150 
1151  using iterator_base = roi_sample_iterator_base<GenericImage<P>, sample*>;
1152 
1156  roi_sample_iterator() = default;
1157 
1180  roi_sample_iterator( image_type& image, const Rect& rect = Rect( 0 ), int channel = -1 )
1181  : iterator_base( image.EnsureUnique(), rect, channel )
1182  {
1183  }
1184 
1202  : iterator_base( image, i, j )
1203  {
1204  }
1205 
1210 
1214  roi_sample_iterator& operator =( const roi_sample_iterator& ) = default;
1215 
1220  bool IsValid() const noexcept
1221  {
1222  return this->m_image != nullptr && this->m_iterator != nullptr;
1223  }
1224 
1228  image_type& Image() const noexcept
1229  {
1230  return *this->m_image;
1231  }
1232 
1236  sample* Position() const noexcept
1237  {
1238  return this->m_iterator;
1239  }
1240 
1247  operator bool() const noexcept
1248  {
1249  return this->m_iterator < this->m_end;
1250  }
1251 
1256  sample& operator *() const noexcept
1257  {
1258  return *this->m_iterator;
1259  }
1260 
1266  roi_sample_iterator& operator ++() noexcept
1267  {
1268  this->Increment();
1269  return *this;
1270  }
1271 
1277  roi_sample_iterator operator ++( int ) noexcept
1278  {
1279  roi_sample_iterator i0( *this );
1280  this->Increment();
1281  return i0;
1282  }
1283 
1289  roi_sample_iterator& operator --() noexcept
1290  {
1291  this->Decrement();
1292  return *this;
1293  }
1294 
1300  roi_sample_iterator operator --( int ) noexcept
1301  {
1302  roi_sample_iterator i0( *this );
1303  this->Decrement();
1304  return i0;
1305  }
1306 
1316  roi_sample_iterator& operator +=( distance_type delta ) noexcept
1317  {
1318  int w = this->m_rowEnd - this->m_rowBegin;
1319  iterator_base::MoveBy( delta%w, delta/w );
1320  return *this;
1321  }
1322 
1332  roi_sample_iterator& operator -=( distance_type delta ) noexcept
1333  {
1334  int w = this->m_rowEnd - this->m_rowBegin;
1335  iterator_base::MoveBy( -delta%w, -delta/w );
1336  return *this;
1337  }
1338 
1347  roi_sample_iterator& MoveBy( int dx, int dy ) noexcept
1348  {
1349  iterator_base::MoveBy( dx, dy );
1350  return *this;
1351  }
1352 
1358  {
1359  roi_sample_iterator j( i );
1360  j += delta;
1361  return j;
1362  }
1363 
1369  {
1370  roi_sample_iterator j( i );
1371  j += delta;
1372  return j;
1373  }
1374 
1380  {
1381  roi_sample_iterator j( i );
1382  j -= delta;
1383  return j;
1384  }
1385 
1390  friend bool operator ==( const roi_sample_iterator& i, const roi_sample_iterator& j ) noexcept
1391  {
1392  return i.m_iterator == j.m_iterator;
1393  }
1394 
1399  friend bool operator ==( const roi_sample_iterator& i, const sample* j ) noexcept
1400  {
1401  return i.m_iterator == j;
1402  }
1403 
1408  friend bool operator ==( const sample* i, const roi_sample_iterator& j ) noexcept
1409  {
1410  return i == j.m_iterator;
1411  }
1412 
1417  friend bool operator <( const roi_sample_iterator& i, const roi_sample_iterator& j ) noexcept
1418  {
1419  return i.m_iterator < j.m_iterator;
1420  }
1421 
1425  friend bool operator <( const roi_sample_iterator& i, const sample* j ) noexcept
1426  {
1427  return i.m_iterator < j;
1428  }
1429 
1433  friend bool operator <( const sample* i, const roi_sample_iterator& j ) noexcept
1434  {
1435  return i < j.m_iterator;
1436  }
1437 
1438  friend class const_roi_pixel_iterator;
1439  };
1440 
1441  // -------------------------------------------------------------------------
1442 
1453  class const_roi_sample_iterator : private roi_sample_iterator_base<const GenericImage<P>, const sample*>
1454  {
1455  public:
1456 
1461 
1466 
1470  using sample = typename image_type::sample;
1471 
1472  using iterator_base = roi_sample_iterator_base<const GenericImage<P>, const sample*>;
1473 
1478 
1501  const_roi_sample_iterator( const image_type& image, const Rect& rect = Rect( 0 ), int channel = -1 )
1502  : iterator_base( image, rect, channel )
1503  {
1504  }
1505 
1522  const_roi_sample_iterator( const image_type& image, const sample* i, const sample* j )
1523  : iterator_base( image, i, j )
1524  {
1525  }
1526 
1536  : iterator_base( i.m_image, i.m_rowBegin, i.m_end )
1537  {
1538  }
1539 
1544 
1549  const_roi_sample_iterator& operator =( const roi_sample_iterator& i ) noexcept
1550  {
1551  this->m_image = i.m_image;
1552  this->m_iterator = i.m_iterator;
1553  this->m_rowBegin = i.m_rowBegin;
1554  this->m_rowEnd = i.m_rowEnd;
1555  this->m_end = i.m_end;
1556  return *this;
1557  }
1558 
1562  const_roi_sample_iterator& operator =( const const_roi_sample_iterator& ) = default;
1563 
1568  bool IsValid() const noexcept
1569  {
1570  return this->m_image != nullptr && this->m_iterator != nullptr;
1571  }
1572 
1577  const image_type& Image() const noexcept
1578  {
1579  return *this->m_image;
1580  }
1581 
1586  const sample* Position() const noexcept
1587  {
1588  return this->m_iterator;
1589  }
1590 
1597  operator bool() const noexcept
1598  {
1599  return this->m_iterator < this->m_end;
1600  }
1601 
1606  const sample& operator *() const noexcept
1607  {
1608  return *this->m_iterator;
1609  }
1610 
1616  const_roi_sample_iterator& operator ++() noexcept
1617  {
1618  this->Increment();
1619  return *this;
1620  }
1621 
1627  const_roi_sample_iterator operator ++( int ) noexcept
1628  {
1629  const_roi_sample_iterator i0( *this );
1630  this->Increment();
1631  return i0;
1632  }
1633 
1639  const_roi_sample_iterator& operator --() noexcept
1640  {
1641  this->Decrement();
1642  return *this;
1643  }
1644 
1650  const_roi_sample_iterator operator --( int ) noexcept
1651  {
1652  const_roi_sample_iterator i0( *this );
1653  this->Decrement();
1654  return i0;
1655  }
1656 
1666  const_roi_sample_iterator& operator +=( distance_type delta ) noexcept
1667  {
1668  int w = this->m_rowEnd - this->m_rowBegin;
1669  iterator_base::MoveBy( delta%w, delta/w );
1670  return *this;
1671  }
1672 
1682  const_roi_sample_iterator& operator -=( distance_type delta ) noexcept
1683  {
1684  int w = this->m_rowEnd - this->m_rowBegin;
1685  iterator_base::MoveBy( -delta%w, -delta/w );
1686  return *this;
1687  }
1688 
1697  const_roi_sample_iterator& MoveBy( int dx, int dy ) noexcept
1698  {
1699  iterator_base::MoveBy( dx, dy );
1700  return *this;
1701  }
1702 
1708  {
1710  j += delta;
1711  return j;
1712  }
1713 
1719  {
1721  j += delta;
1722  return j;
1723  }
1724 
1730  {
1732  j -= delta;
1733  return j;
1734  }
1735 
1740  friend bool operator ==( const const_roi_sample_iterator& i, const const_roi_sample_iterator& j ) noexcept
1741  {
1742  return i.m_iterator == j.m_iterator;
1743  }
1744 
1749  friend bool operator ==( const const_roi_sample_iterator& i, const sample* j ) noexcept
1750  {
1751  return i.m_iterator == j;
1752  }
1753 
1758  friend bool operator ==( const sample* i, const const_roi_sample_iterator& j ) noexcept
1759  {
1760  return i == j.m_iterator;
1761  }
1762 
1767  friend bool operator <( const const_roi_sample_iterator& i, const const_roi_sample_iterator& j ) noexcept
1768  {
1769  return i.m_iterator < j.m_iterator;
1770  }
1771 
1775  friend bool operator <( const const_roi_sample_iterator& i, const sample* j ) noexcept
1776  {
1777  return i.m_iterator < j;
1778  }
1779 
1783  friend bool operator <( const sample* i, const const_roi_sample_iterator& j ) noexcept
1784  {
1785  return i < j.m_iterator;
1786  }
1787  };
1788 
1789  // -------------------------------------------------------------------------
1790 
1791  template <class image_type, class iterator_base, class sample_pointer, class filter_type>
1792  class filter_sample_iterator_base : public iterator_base
1793  {
1794  protected:
1795 
1796  filter_type m_filter;
1797  sample_pointer m_begin = nullptr;
1798 
1799  filter_sample_iterator_base() = default;
1800 
1801  filter_sample_iterator_base( image_type& image, const filter_type& filter, int channel )
1802  : iterator_base( image, channel )
1803  , m_filter( filter )
1804  , m_begin( iterator_base::m_iterator )
1805  {
1806  JumpToNextValidSample();
1807  }
1808 
1809  filter_sample_iterator_base( image_type& image, const filter_type& filter, sample_pointer i, sample_pointer j )
1810  : iterator_base( image, i, j )
1811  , m_filter( filter )
1812  , m_begin( iterator_base::m_iterator )
1813  {
1814  JumpToNextValidSample();
1815  }
1816 
1817  filter_sample_iterator_base( const iterator_base& i, const filter_type& filter )
1818  : iterator_base( i )
1819  , m_filter( filter )
1820  , m_begin( iterator_base::m_iterator )
1821  {
1822  JumpToNextValidSample();
1823  }
1824 
1825  filter_sample_iterator_base( const filter_sample_iterator_base& ) = default;
1826 
1827  filter_sample_iterator_base& operator =( const filter_sample_iterator_base& ) = default;
1828 
1829  filter_sample_iterator_base& operator =( const iterator_base& i ) noexcept
1830  {
1831  (void)iterator_base::operator =( i );
1832  JumpToNextValidSample();
1833  return *this;
1834  }
1835 
1836  void JumpToNextValidSample() noexcept
1837  {
1838  while ( this->m_iterator < this->m_end && !this->m_filter( *this->m_iterator ) )
1839  ++this->m_iterator;
1840  }
1841 
1842  void JumpToPrevValidSample() noexcept
1843  {
1844  while ( this->m_iterator > this->m_begin && !this->m_filter( *this->m_iterator ) )
1845  --this->m_iterator;
1846  }
1847  };
1848 
1849  // -------------------------------------------------------------------------
1850 
1884  template <class F>
1886  public filter_sample_iterator_base<GenericImage<P>, sample_iterator, sample*, F>
1887  {
1888  public:
1889 
1894 
1899 
1903  using sample = typename image_type::sample;
1904 
1909  using filter_type = F;
1910 
1911  using iterator_base = filter_sample_iterator_base<GenericImage<P>, sample_iterator, sample*, F>;
1912 
1917 
1934  filter_sample_iterator( image_type& image, const F& filter, int channel = -1 )
1935  : iterator_base( image.EnsureUnique(), filter, channel )
1936  {
1937  }
1938 
1957  filter_sample_iterator( image_type& image, const F& filter, sample* i, sample* j )
1958  : iterator_base( image, filter, i, j )
1959  {
1960  }
1961 
1966  filter_sample_iterator( const sample_iterator& i, const F& filter )
1967  : iterator_base( i, filter )
1968  {
1969  }
1970 
1975 
1979  filter_sample_iterator& operator =( const filter_sample_iterator& ) = default;
1980 
1985  filter_sample_iterator& operator =( const sample_iterator& i ) noexcept
1986  {
1987  (void)iterator_base::operator =( i );
1988  return *this;
1989  }
1990 
1995  bool IsValid() const noexcept
1996  {
1997  return this->m_image != nullptr && this->m_iterator != nullptr;
1998  }
1999 
2003  image_type& Image() const noexcept
2004  {
2005  return *this->m_image;
2006  }
2007 
2012  const filter_type& Filter() const noexcept
2013  {
2014  return this->m_filter;
2015  }
2016 
2021  filter_type& Filter() noexcept
2022  {
2023  return this->m_filter;
2024  }
2025 
2029  sample* Position() const noexcept
2030  {
2031  return this->m_iterator;
2032  }
2033 
2041  operator bool() const noexcept
2042  {
2043  return this->m_iterator < this->m_end;
2044  }
2045 
2050  sample& operator *() const noexcept
2051  {
2052  return *this->m_iterator;
2053  }
2054 
2060  filter_sample_iterator& operator ++() noexcept
2061  {
2062  ++this->m_iterator;
2063  this->JumpToNextValidSample();
2064  return *this;
2065  }
2066 
2072  filter_sample_iterator operator ++( int ) noexcept
2073  {
2074  sample* __restrict__ i0 = this->m_iterator++;
2075  this->JumpToNextValidSample();
2076  return filter_sample_iterator( *this->m_image, this->m_filter, i0, this->m_end );
2077  }
2078 
2084  filter_sample_iterator& operator --() noexcept
2085  {
2086  --this->m_iterator;
2087  this->JumpToPrevValidSample();
2088  return *this;
2089  }
2090 
2096  filter_sample_iterator operator --( int ) noexcept
2097  {
2098  sample* __restrict__ i0 = this->m_iterator--;
2099  this->JumpToPrevValidSample();
2100  return filter_sample_iterator( *this->m_image, this->m_filter, i0, this->m_end );
2101  }
2102 
2110  filter_sample_iterator& operator +=( distance_type delta ) noexcept
2111  {
2112  this->m_iterator += delta;
2113  this->JumpToNextValidSample();
2114  return *this;
2115  }
2116 
2124  filter_sample_iterator& operator -=( distance_type delta ) noexcept
2125  {
2126  this->m_iterator -= delta;
2127  this->JumpToPrevValidSample();
2128  return *this;
2129  }
2130 
2138  filter_sample_iterator& MoveBy( int dx, int dy ) noexcept
2139  {
2140  distance_type d = distance_type( dy )*this->m_image->Width() + distance_type( dx );
2141  this->m_iterator += d;
2142  if ( d >= 0 )
2143  this->JumpToNextValidSample();
2144  else
2145  this->JumpToPrevValidSample();
2146  return *this;
2147  }
2148 
2154  {
2155  return filter_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
2156  }
2157 
2163  {
2164  return filter_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
2165  }
2166 
2172  {
2173  return filter_sample_iterator( *i.m_image, i.m_iterator - delta, i.m_end );
2174  }
2175 
2181  {
2182  return i.m_iterator - j.m_iterator;
2183  }
2184 
2189  friend bool operator ==( const filter_sample_iterator& i, const filter_sample_iterator& j ) noexcept
2190  {
2191  return i.m_iterator == j.m_iterator;
2192  }
2193 
2198  friend bool operator ==( const filter_sample_iterator& i, const sample* j ) noexcept
2199  {
2200  return i.m_iterator == j;
2201  }
2202 
2207  friend bool operator ==( const sample* i, const filter_sample_iterator& j ) noexcept
2208  {
2209  return i == j.m_iterator;
2210  }
2211 
2216  friend bool operator <( const filter_sample_iterator& i, const filter_sample_iterator& j ) noexcept
2217  {
2218  return i.m_iterator < j.m_iterator;
2219  }
2220 
2224  friend bool operator <( const filter_sample_iterator& i, const sample* j ) noexcept
2225  {
2226  return i.m_iterator < j;
2227  }
2228 
2232  friend bool operator <( const sample* i, const filter_sample_iterator& j ) noexcept
2233  {
2234  return i < j.m_iterator;
2235  }
2236  };
2237 
2238  // -------------------------------------------------------------------------
2239 
2273  template <class F>
2275  public filter_sample_iterator_base<const GenericImage<P>, const_sample_iterator, const sample*, F>
2276  {
2277  public:
2278 
2283 
2288 
2292  using sample = typename image_type::sample;
2293 
2298  using filter_type = F;
2299 
2300  using iterator_base = filter_sample_iterator_base<const GenericImage<P>, const_sample_iterator, const sample*, F>;
2301 
2306 
2323  const_filter_sample_iterator( const image_type& image, const F& filter, int channel = -1 )
2324  : iterator_base( image, filter, channel )
2325  {
2326  }
2327 
2346  const_filter_sample_iterator( const image_type& image, const F& filter, const sample* i, const sample* j )
2347  : iterator_base( image, filter, i, j )
2348  {
2349  }
2350 
2355  const_filter_sample_iterator( const sample_iterator& i, const F& filter )
2356  : iterator_base( i.m_image, filter, i.m_iterator, i.m_end )
2357  {
2358  }
2359 
2365  : iterator_base( i, filter )
2366  {
2367  }
2368 
2374  : iterator_base( i )
2375  {
2376  }
2377 
2382 
2387 
2392  const_filter_sample_iterator& operator =( const sample_iterator& i ) noexcept
2393  {
2394  (void)const_sample_iterator::operator =( i );
2395  this->JumpToNextValidSample();
2396  return *this;
2397  }
2398 
2403  const_filter_sample_iterator& operator =( const const_sample_iterator& i ) noexcept
2404  {
2405  (void)iterator_base::operator =( i );
2406  return *this;
2407  }
2408 
2413  bool IsValid() const noexcept
2414  {
2415  return this->m_image != nullptr && this->m_iterator != nullptr;
2416  }
2417 
2422  const image_type& Image() const noexcept
2423  {
2424  return *this->m_image;
2425  }
2426 
2431  const filter_type& Filter() const noexcept
2432  {
2433  return this->m_filter;
2434  }
2435 
2440  filter_type& Filter() noexcept
2441  {
2442  return this->m_filter;
2443  }
2444 
2449  const sample* Position() const noexcept
2450  {
2451  return this->m_iterator;
2452  }
2453 
2461  operator bool() const noexcept
2462  {
2463  return this->m_iterator < this->m_end;
2464  }
2465 
2470  const sample& operator *() const noexcept
2471  {
2472  return *this->m_iterator;
2473  }
2474 
2480  const_filter_sample_iterator& operator ++() noexcept
2481  {
2482  ++this->m_iterator;
2483  this->JumpToNextValidSample();
2484  return *this;
2485  }
2486 
2492  const_filter_sample_iterator operator ++( int ) noexcept
2493  {
2494  sample* __restrict__ i0 = this->m_iterator++;
2495  this->JumpToNextValidSample();
2496  return const_filter_sample_iterator( *this->m_image, this->m_filter, i0, this->m_end );
2497  }
2498 
2504  const_filter_sample_iterator& operator --() noexcept
2505  {
2506  --this->m_iterator;
2507  this->JumpToPrevValidSample();
2508  return *this;
2509  }
2510 
2516  const_filter_sample_iterator operator --( int ) noexcept
2517  {
2518  sample* __restrict__ i0 = this->m_iterator--;
2519  this->JumpToPrevValidSample();
2520  return const_filter_sample_iterator( *this->m_image, this->m_filter, i0, this->m_end );
2521  }
2522 
2530  const_filter_sample_iterator& operator +=( distance_type delta ) noexcept
2531  {
2532  this->m_iterator += delta;
2533  this->JumpToNextValidSample();
2534  return *this;
2535  }
2536 
2544  const_filter_sample_iterator& operator -=( distance_type delta ) noexcept
2545  {
2546  this->m_iterator -= delta;
2547  this->JumpToPrevValidSample();
2548  return *this;
2549  }
2550 
2558  const_filter_sample_iterator& MoveBy( int dx, int dy ) noexcept
2559  {
2560  distance_type d = distance_type( dy )*this->m_image->Width() + distance_type( dx );
2561  this->m_iterator += d;
2562  if ( d >= 0 )
2563  this->JumpToNextValidSample();
2564  else
2565  this->JumpToPrevValidSample();
2566  return *this;
2567  }
2568 
2574  {
2575  return const_filter_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
2576  }
2577 
2583  {
2584  return const_filter_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
2585  }
2586 
2592  {
2593  return const_filter_sample_iterator( *i.m_image, i.m_iterator - delta, i.m_end );
2594  }
2595 
2601  {
2602  return i.m_iterator - j.m_iterator;
2603  }
2604 
2609  friend bool operator ==( const const_filter_sample_iterator& i, const const_filter_sample_iterator& j ) noexcept
2610  {
2611  return i.m_iterator == j.m_iterator;
2612  }
2613 
2618  friend bool operator ==( const const_filter_sample_iterator& i, const sample* j ) noexcept
2619  {
2620  return i.m_iterator == j;
2621  }
2622 
2627  friend bool operator ==( const sample* i, const const_filter_sample_iterator& j ) noexcept
2628  {
2629  return i == j.m_iterator;
2630  }
2631 
2636  friend bool operator <( const const_filter_sample_iterator& i, const const_filter_sample_iterator& j ) noexcept
2637  {
2638  return i.m_iterator < j.m_iterator;
2639  }
2640 
2644  friend bool operator <( const const_filter_sample_iterator& i, const sample* j ) noexcept
2645  {
2646  return i.m_iterator < j;
2647  }
2648 
2652  friend bool operator <( const sample* i, const const_filter_sample_iterator& j ) noexcept
2653  {
2654  return i < j.m_iterator;
2655  }
2656  };
2657 
2658  // -------------------------------------------------------------------------
2659 
2660  template <class image_type, class sample_pointer, class filter_type>
2661  class roi_filter_sample_iterator_base : public roi_sample_iterator_base<image_type, sample_pointer>
2662  {
2663  protected:
2664 
2665  using roi_iterator_base = roi_sample_iterator_base<image_type, sample_pointer>;
2666 
2667  filter_type m_filter;
2668  sample_pointer m_begin = nullptr;
2669 
2670  roi_filter_sample_iterator_base() = default;
2671 
2672  roi_filter_sample_iterator_base( image_type& image, const filter_type& filter, const Rect& rect, int channel )
2673  : roi_iterator_base( image, rect, channel )
2674  , m_filter( filter )
2675  , m_begin( roi_iterator_base::m_iterator )
2676  {
2677  JumpToNextValidSample();
2678  }
2679 
2680  roi_filter_sample_iterator_base( image_type& image, const filter_type& filter, sample_pointer i, sample_pointer j )
2681  : roi_iterator_base( image, i, j )
2682  , m_filter( filter )
2683  , m_begin( roi_iterator_base::m_iterator )
2684  {
2685  JumpToNextValidSample();
2686  }
2687 
2688  roi_filter_sample_iterator_base( const roi_iterator_base& i, const filter_type& filter )
2689  : roi_iterator_base( i )
2690  , m_filter( filter )
2691  , m_begin( roi_iterator_base::m_iterator )
2692  {
2693  JumpToNextValidSample();
2694  }
2695 
2696  roi_filter_sample_iterator_base( const roi_filter_sample_iterator_base& ) = default;
2697 
2698  roi_filter_sample_iterator_base& operator =( const roi_filter_sample_iterator_base& i ) = default;
2699 
2700  roi_filter_sample_iterator_base& operator =( const roi_iterator_base& i ) noexcept
2701  {
2702  (void)roi_iterator_base::operator =( i );
2703  JumpToNextValidSample();
2704  return *this;
2705  }
2706 
2707  void JumpToNextValidSample() noexcept
2708  {
2709  while ( this->m_iterator < this->m_end && !this->m_filter( *this->m_iterator ) )
2710  roi_iterator_base::Increment();
2711  }
2712 
2713  void JumpToPrevValidSample() noexcept
2714  {
2715  while ( this->m_iterator > this->m_begin && !this->m_filter( *this->m_iterator ) )
2716  roi_iterator_base::Decrement();
2717  }
2718  };
2719 
2720  // -------------------------------------------------------------------------
2721 
2732  template <class F>
2733  class roi_filter_sample_iterator : public roi_filter_sample_iterator_base<GenericImage<P>, sample*, F>
2734  {
2735  public:
2736 
2741 
2746 
2750  using sample = typename image_type::sample;
2751 
2756  using filter_type = F;
2757 
2758  using iterator_base = roi_filter_sample_iterator_base<GenericImage<P>, sample*, F>;
2759 
2764 
2790  roi_filter_sample_iterator( image_type& image, const F& filter, const Rect& rect = Rect( 0 ), int channel = -1 )
2791  : iterator_base( image.EnsureUnique(), filter, rect, channel )
2792  {
2793  }
2794 
2813  roi_filter_sample_iterator( image_type& image, const F& filter, sample* i, sample* j )
2814  : iterator_base( image, filter, i, j )
2815  {
2816  }
2817 
2823  : iterator_base( i, filter )
2824  {
2825  }
2826 
2831 
2836 
2841  roi_filter_sample_iterator& operator =( const roi_sample_iterator& i ) noexcept
2842  {
2843  (void)iterator_base::operator =( i );
2844  return *this;
2845  }
2846 
2851  bool IsValid() const noexcept
2852  {
2853  return this->m_image != nullptr && this->m_iterator != nullptr;
2854  }
2855 
2859  image_type& Image() const noexcept
2860  {
2861  return *this->m_image;
2862  }
2863 
2868  const filter_type& Filter() const noexcept
2869  {
2870  return this->m_filter;
2871  }
2872 
2877  filter_type& Filter() noexcept
2878  {
2879  return this->m_filter;
2880  }
2881 
2885  sample* Position() const noexcept
2886  {
2887  return this->m_iterator;
2888  }
2889 
2896  operator bool() const noexcept
2897  {
2898  return this->m_iterator < this->m_end;
2899  }
2900 
2905  sample& operator *() const noexcept
2906  {
2907  return *this->m_iterator;
2908  }
2909 
2915  roi_filter_sample_iterator& operator ++() noexcept
2916  {
2917  this->Increment();
2918  this->JumpToNextValidSample();
2919  return *this;
2920  }
2921 
2927  roi_filter_sample_iterator operator ++( int ) noexcept
2928  {
2929  roi_filter_sample_iterator i0( *this );
2930  this->Increment();
2931  this->JumpToNextValidSample();
2932  return i0;
2933  }
2934 
2940  roi_filter_sample_iterator& operator --() noexcept
2941  {
2942  this->Decrement();
2943  this->JumpToPrevValidSample();
2944  return *this;
2945  }
2946 
2952  roi_filter_sample_iterator operator --( int ) noexcept
2953  {
2954  roi_filter_sample_iterator i0( *this );
2955  this->Decrement();
2956  this->JumpToPrevValidSample();
2957  return i0;
2958  }
2959 
2969  roi_filter_sample_iterator& operator +=( distance_type delta ) noexcept
2970  {
2971  int w = this->m_rowEnd - this->m_rowBegin;
2972  return MoveBy( delta%w, delta/w );
2973  }
2974 
2984  roi_filter_sample_iterator& operator -=( distance_type delta ) noexcept
2985  {
2986  int w = this->m_rowEnd - this->m_rowBegin;
2987  return MoveBy( -delta%w, -delta/w );
2988  }
2989 
2998  roi_filter_sample_iterator& MoveBy( int dx, int dy ) noexcept
2999  {
3000  sample* __restrict__ i0 = this->m_iterator;
3001  iterator_base::MoveBy( dx, dy );
3002  if ( this->m_iterator >= i0 )
3003  this->JumpToNextValidSample();
3004  else
3005  this->JumpToPrevValidSample();
3006  return *this;
3007  }
3008 
3014  {
3016  j += delta;
3017  return j;
3018  }
3019 
3025  {
3027  j += delta;
3028  return j;
3029  }
3030 
3036  {
3038  j -= delta;
3039  return j;
3040  }
3041 
3046  friend bool operator ==( const roi_filter_sample_iterator& i, const roi_filter_sample_iterator& j ) noexcept
3047  {
3048  return i.m_iterator == j.m_iterator;
3049  }
3050 
3055  friend bool operator ==( const roi_filter_sample_iterator& i, const sample* j ) noexcept
3056  {
3057  return i.m_iterator == j;
3058  }
3059 
3064  friend bool operator ==( const sample* i, const roi_filter_sample_iterator& j ) noexcept
3065  {
3066  return i == j.m_iterator;
3067  }
3068 
3073  friend bool operator <( const roi_filter_sample_iterator& i, const roi_filter_sample_iterator& j ) noexcept
3074  {
3075  return i.m_iterator < j.m_iterator;
3076  }
3077 
3081  friend bool operator <( const roi_filter_sample_iterator& i, const sample* j ) noexcept
3082  {
3083  return i.m_iterator < j;
3084  }
3085 
3089  friend bool operator <( const sample* i, const roi_filter_sample_iterator& j ) noexcept
3090  {
3091  return i < j.m_iterator;
3092  }
3093  };
3094 
3095  // -------------------------------------------------------------------------
3096 
3107  template <class F>
3108  class const_roi_filter_sample_iterator : public roi_filter_sample_iterator_base<const GenericImage<P>, const sample*, F>
3109  {
3110  public:
3111 
3116 
3121 
3125  using sample = typename image_type::sample;
3126 
3131  using filter_type = F;
3132 
3133  using iterator_base = roi_filter_sample_iterator_base<const GenericImage<P>, const sample*, F>;
3134 
3139 
3165  const_roi_filter_sample_iterator( const image_type& image, const F& filter, const Rect& rect = Rect( 0 ), int channel = -1 )
3166  : iterator_base( image, filter, rect, channel )
3167  {
3168  }
3169 
3188  const_roi_filter_sample_iterator( const image_type& image, const F& filter, const sample* i, const sample* j )
3189  : iterator_base( image, filter, i, j )
3190  {
3191  }
3192 
3198  : iterator_base( i, filter )
3199  {
3200  }
3201 
3206 
3211 
3217  {
3218  (void)iterator_base::operator =( i );
3219  return *this;
3220  }
3221 
3226  bool IsValid() const noexcept
3227  {
3228  return this->m_image != nullptr && this->m_iterator != nullptr;
3229  }
3230 
3235  const image_type& Image() const noexcept
3236  {
3237  return *this->m_image;
3238  }
3239 
3244  const filter_type& Filter() const noexcept
3245  {
3246  return this->m_filter;
3247  }
3248 
3253  filter_type& Filter() noexcept
3254  {
3255  return this->m_filter;
3256  }
3257 
3262  const sample* Position() const noexcept
3263  {
3264  return this->m_iterator;
3265  }
3266 
3273  operator bool() const noexcept
3274  {
3275  return this->m_iterator < this->m_end;
3276  }
3277 
3282  const sample& operator *() const noexcept
3283  {
3284  return *this->m_iterator;
3285  }
3286 
3292  const_roi_filter_sample_iterator& operator ++() noexcept
3293  {
3294  this->Increment();
3295  this->JumpToNextValidSample();
3296  return *this;
3297  }
3298 
3304  const_roi_filter_sample_iterator operator ++( int ) noexcept
3305  {
3307  this->Increment();
3308  this->JumpToNextValidSample();
3309  return i0;
3310  }
3311 
3317  const_roi_filter_sample_iterator& operator --() noexcept
3318  {
3319  this->Decrement();
3320  this->JumpToPrevValidSample();
3321  return *this;
3322  }
3323 
3329  const_roi_filter_sample_iterator operator --( int ) noexcept
3330  {
3332  this->Decrement();
3333  this->JumpToPrevValidSample();
3334  return i0;
3335  }
3336 
3346  const_roi_filter_sample_iterator& operator +=( distance_type delta ) noexcept
3347  {
3348  int w = this->m_rowEnd - this->m_rowBegin;
3349  return MoveBy( delta%w, delta/w );
3350  }
3351 
3361  const_roi_filter_sample_iterator& operator -=( distance_type delta ) noexcept
3362  {
3363  int w = this->m_rowEnd - this->m_rowBegin;
3364  return MoveBy( -delta%w, -delta/w );
3365  }
3366 
3375  const_roi_filter_sample_iterator& MoveBy( int dx, int dy ) noexcept
3376  {
3377  const sample* __restrict__ i0 = this->m_iterator;
3378  iterator_base::MoveBy( dx, dy );
3379  if ( this->m_iterator >= i0 )
3380  this->JumpToNextValidSample();
3381  else
3382  this->JumpToPrevValidSample();
3383  return *this;
3384  }
3385 
3391  {
3393  j += delta;
3394  return j;
3395  }
3396 
3402  {
3404  j += delta;
3405  return j;
3406  }
3407 
3413  {
3415  j -= delta;
3416  return j;
3417  }
3418 
3424  {
3425  return i.m_iterator == j.m_iterator;
3426  }
3427 
3432  friend bool operator ==( const const_roi_filter_sample_iterator& i, const sample* j ) noexcept
3433  {
3434  return i.m_iterator == j;
3435  }
3436 
3441  friend bool operator ==( const sample* i, const const_roi_filter_sample_iterator& j ) noexcept
3442  {
3443  return i == j.m_iterator;
3444  }
3445 
3451  {
3452  return i.m_iterator < j.m_iterator;
3453  }
3454 
3458  friend bool operator <( const const_roi_filter_sample_iterator& i, const sample* j ) noexcept
3459  {
3460  return i.m_iterator < j;
3461  }
3462 
3466  friend bool operator <( const sample* i, const const_roi_filter_sample_iterator& j ) noexcept
3467  {
3468  return i < j.m_iterator;
3469  }
3470  };
3471 
3472  // -------------------------------------------------------------------------
3473 
3484  {
3485  public:
3486 
3491 
3496 
3500  using sample = typename image_type::sample;
3501 
3503 
3507  pixel_iterator() = default;
3508 
3513  : m_image( &image )
3514  {
3515  m_image->EnsureUnique();
3516  if ( !m_image->IsEmpty() )
3517  {
3518  m_iterator = iterator_type( m_image->NumberOfChannels() );
3519  for ( int i = 0; i < m_iterator.Length(); ++i )
3520  m_iterator[i] = (*m_image)[i];
3521  m_end = m_iterator[0] + m_image->NumberOfPixels();
3522  }
3523  }
3524 
3528  pixel_iterator( const pixel_iterator& ) = default;
3529 
3533  pixel_iterator& operator =( const pixel_iterator& ) = default;
3534 
3539  bool IsValid() const noexcept
3540  {
3541  return m_image != nullptr && !m_iterator.IsEmpty();
3542  }
3543 
3547  image_type& Image() const noexcept
3548  {
3549  return *m_image;
3550  }
3551 
3556  sample* Position( int channel ) const noexcept
3557  {
3558  return m_iterator[channel];
3559  }
3560 
3566  operator bool() const noexcept
3567  {
3568  return m_iterator[0] < m_end;
3569  }
3570 
3575  sample& operator []( int channel ) const noexcept
3576  {
3577  return *m_iterator[channel];
3578  }
3579 
3584  pixel_iterator& operator ++() noexcept
3585  {
3586  for ( int i = 0; i < m_iterator.Length(); ++i )
3587  ++m_iterator[i];
3588  return *this;
3589  }
3590 
3596  pixel_iterator operator ++( int ) noexcept
3597  {
3598  pixel_iterator i0( *this );
3599  for ( int i = 0; i < m_iterator.Length(); ++i )
3600  ++m_iterator[i];
3601  return i0;
3602  }
3603 
3608  pixel_iterator& operator --() noexcept
3609  {
3610  for ( int i = 0; i < m_iterator.Length(); ++i )
3611  --m_iterator[i];
3612  return *this;
3613  }
3614 
3620  pixel_iterator operator --( int ) noexcept
3621  {
3622  pixel_iterator i0( *this );
3623  for ( int i = 0; i < m_iterator.Length(); ++i )
3624  --m_iterator[i];
3625  return i0;
3626  }
3627 
3635  pixel_iterator& operator +=( distance_type delta ) noexcept
3636  {
3637  for ( int i = 0; i < m_iterator.Length(); ++i )
3638  m_iterator[i] += delta;
3639  return *this;
3640  }
3641 
3649  pixel_iterator& operator -=( distance_type delta ) noexcept
3650  {
3651  for ( int i = 0; i < m_iterator.Length(); ++i )
3652  m_iterator[i] -= delta;
3653  return *this;
3654  }
3655 
3663  pixel_iterator& MoveBy( int dx, int dy ) noexcept
3664  {
3665  return operator +=( distance_type( dy )*m_image->Width() + distance_type( dx ) );
3666  }
3667 
3672  friend pixel_iterator operator +( const pixel_iterator& i, distance_type delta ) noexcept
3673  {
3674  pixel_iterator j( i );
3675  j += delta;
3676  return j;
3677  }
3678 
3683  friend pixel_iterator operator +( distance_type delta, const pixel_iterator& i ) noexcept
3684  {
3685  pixel_iterator j( i );
3686  j += delta;
3687  return j;
3688  }
3689 
3694  friend pixel_iterator operator -( const pixel_iterator& i, distance_type delta ) noexcept
3695  {
3696  pixel_iterator j( i );
3697  j -= delta;
3698  return j;
3699  }
3700 
3705  friend distance_type operator -( const pixel_iterator& i, const pixel_iterator& j ) noexcept
3706  {
3707  return i.m_iterator[0] - j.m_iterator[0];
3708  }
3709 
3714  friend bool operator ==( const pixel_iterator& i, const pixel_iterator& j ) noexcept
3715  {
3716  return i.m_iterator[0] == j.m_iterator[0];
3717  }
3718 
3723  friend bool operator <( const pixel_iterator& i, const pixel_iterator& j ) noexcept
3724  {
3725  return i.m_iterator[0] < j.m_iterator[0];
3726  }
3727 
3728  protected:
3729 
3730  image_type* m_image = nullptr;
3731  iterator_type m_iterator;
3732  const sample* __restrict__ m_end = nullptr;
3733  };
3734 
3735  // -------------------------------------------------------------------------
3736 
3747  {
3748  public:
3749 
3754 
3759 
3763  using sample = typename image_type::sample;
3764 
3766 
3771 
3776  : m_image( &image )
3777  {
3778  if ( !m_image->IsEmpty() )
3779  {
3780  m_iterator = iterator_type( m_image->NumberOfChannels() );
3781  for ( int i = 0; i < m_iterator.Length(); ++i )
3782  m_iterator[i] = (*m_image)[i];
3783  m_end = m_iterator[0] + m_image->NumberOfPixels();
3784  }
3785  }
3786 
3791 
3795  const_pixel_iterator& operator =( const const_pixel_iterator& ) = default;
3796 
3801  bool IsValid() const noexcept
3802  {
3803  return m_image != nullptr && !m_iterator.IsEmpty();
3804  }
3805 
3810  const image_type& Image() const noexcept
3811  {
3812  return *m_image;
3813  }
3814 
3819  const sample* Position( int channel ) const noexcept
3820  {
3821  return m_iterator[channel];
3822  }
3823 
3829  operator bool() const noexcept
3830  {
3831  return m_iterator[0] < m_end;
3832  }
3833 
3838  const sample& operator []( int channel ) const noexcept
3839  {
3840  return *m_iterator[channel];
3841  }
3842 
3847  const_pixel_iterator& operator ++() noexcept
3848  {
3849  for ( int i = 0; i < m_iterator.Length(); ++i )
3850  ++m_iterator[i];
3851  return *this;
3852  }
3853 
3859  const_pixel_iterator operator ++( int ) noexcept
3860  {
3861  const_pixel_iterator i0( *this );
3862  for ( int i = 0; i < m_iterator.Length(); ++i )
3863  ++m_iterator[i];
3864  return i0;
3865  }
3866 
3871  const_pixel_iterator& operator --() noexcept
3872  {
3873  for ( int i = 0; i < m_iterator.Length(); ++i )
3874  --m_iterator[i];
3875  return *this;
3876  }
3877 
3883  const_pixel_iterator operator --( int ) noexcept
3884  {
3885  const_pixel_iterator i0( *this );
3886  for ( int i = 0; i < m_iterator.Length(); ++i )
3887  --m_iterator[i];
3888  return i0;
3889  }
3890 
3898  const_pixel_iterator& operator +=( distance_type delta ) noexcept
3899  {
3900  for ( int i = 0; i < m_iterator.Length(); ++i )
3901  m_iterator[i] += delta;
3902  return *this;
3903  }
3904 
3912  const_pixel_iterator& operator -=( distance_type delta ) noexcept
3913  {
3914  for ( int i = 0; i < m_iterator.Length(); ++i )
3915  m_iterator[i] -= delta;
3916  return *this;
3917  }
3918 
3926  const_pixel_iterator& MoveBy( int dx, int dy ) noexcept
3927  {
3928  return operator +=( distance_type( dy )*m_image->Width() + distance_type( dx ) );
3929  }
3930 
3936  {
3937  const_pixel_iterator j( i );
3938  j += delta;
3939  return j;
3940  }
3941 
3947  {
3948  const_pixel_iterator j( i );
3949  j += delta;
3950  return j;
3951  }
3952 
3958  {
3959  const_pixel_iterator j( i );
3960  j -= delta;
3961  return j;
3962  }
3963 
3969  {
3970  return i.m_iterator[0] - j.m_iterator[0];
3971  }
3972 
3977  friend bool operator ==( const const_pixel_iterator& i, const const_pixel_iterator& j ) noexcept
3978  {
3979  return i.m_iterator[0] == j.m_iterator[0];
3980  }
3981 
3986  friend bool operator <( const const_pixel_iterator& i, const const_pixel_iterator& j ) noexcept
3987  {
3988  return i.m_iterator[0] < j.m_iterator[0];
3989  }
3990 
3991  protected:
3992 
3993  const image_type* m_image = nullptr;
3994  iterator_type m_iterator;
3995  const sample* __restrict__ m_end = nullptr;
3996  };
3997 
3998  // -------------------------------------------------------------------------
3999 
4000  template <class image_type, class sample_pointer>
4001  class roi_pixel_iterator_base
4002  {
4003  protected:
4004 
4005  using iterator_type = GenericVector<sample_pointer>;
4006 
4007  image_type* m_image = nullptr;
4008  iterator_type m_iterator;
4009  sample_pointer m_rowBegin = nullptr;
4010  sample_pointer m_rowEnd = nullptr;
4011  sample_pointer m_end = nullptr;
4012 
4013  roi_pixel_iterator_base() = default;
4014 
4015  roi_pixel_iterator_base( image_type& image, const Rect& rect )
4016  : m_image( &image )
4017  {
4018  Rect r = rect;
4019  if ( m_image->ParseRect( r ) )
4020  {
4021  m_iterator = iterator_type( m_image->NumberOfChannels() );
4022  for ( int i = 0; i < m_iterator.Length(); ++i )
4023  m_iterator[i] = m_image->PixelAddress( r.x0, r.y0, i );
4024  m_rowBegin = m_iterator[0];
4025  m_rowEnd = m_rowBegin + r.Width();
4026  m_end = m_rowEnd + ((r.Height() - 1)*m_image->Width());
4027  }
4028  }
4029 
4030  roi_pixel_iterator_base( const roi_pixel_iterator_base& ) = default;
4031 
4032  roi_pixel_iterator_base& operator =( const roi_pixel_iterator_base& ) = default;
4033 
4034  void Increment() noexcept
4035  {
4036  for ( int i = 0; i < m_iterator.Length(); ++i )
4037  ++m_iterator[i];
4038  if ( m_iterator[0] == m_rowEnd )
4039  {
4040  int w = m_rowEnd - m_rowBegin;
4041  for ( int i = 0; i < m_iterator.Length(); ++i )
4042  m_iterator[i] += m_image->Width() - w;
4043  m_rowBegin += m_image->Width();
4044  m_rowEnd += m_image->Width();
4045  }
4046  }
4047 
4048  void Decrement() noexcept
4049  {
4050  if ( m_iterator[0] == m_rowBegin )
4051  {
4052  int w = m_rowEnd - m_rowBegin;
4053  for ( int i = 0; i < m_iterator.Length(); ++i )
4054  m_iterator[i] -= m_image->Width() - w;
4055  m_rowBegin -= m_image->Width();
4056  m_rowEnd -= m_image->Width();
4057  }
4058  for ( int i = 0; i < m_iterator.Length(); ++i )
4059  --m_iterator[i];
4060  }
4061 
4062  void MoveBy( int cols, int rows ) noexcept
4063  {
4064  int dx = m_iterator[0] - m_rowBegin;
4065  for ( int i = 0; i < m_iterator.Length(); ++i )
4066  m_iterator[i] -= dx;
4067  cols += dx;
4068  if ( cols != 0 )
4069  {
4070  int w = m_rowEnd - m_rowBegin;
4071  if ( pcl::Abs( cols ) >= w )
4072  {
4073  rows += cols/w;
4074  cols %= w;
4075  }
4076  }
4077  int dy = rows * m_image->Width();
4078  for ( int i = 0; i < m_iterator.Length(); ++i )
4079  m_iterator[i] += dy + cols;
4080  m_rowBegin += dy;
4081  m_rowEnd += dy;
4082  }
4083  };
4084 
4085  // -------------------------------------------------------------------------
4086 
4096  class roi_pixel_iterator : private roi_pixel_iterator_base<GenericImage<P>, sample*>
4097  {
4098  public:
4099 
4104 
4109 
4113  using sample = typename image_type::sample;
4114 
4115  using iterator_base = roi_pixel_iterator_base<GenericImage<P>, sample*>;
4116 
4120  roi_pixel_iterator() = default;
4121 
4136  roi_pixel_iterator( image_type& image, const Rect& rect = Rect( 0 ) )
4137  : iterator_base( image.EnsureUnique(), rect )
4138  {
4139  }
4140 
4145 
4149  roi_pixel_iterator& operator =( const roi_pixel_iterator& ) = default;
4150 
4155  bool IsValid() const noexcept
4156  {
4157  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
4158  }
4159 
4163  image_type& Image() const noexcept
4164  {
4165  return *this->m_image;
4166  }
4167 
4172  sample* Position( int channel ) const noexcept
4173  {
4174  return this->m_iterator[channel];
4175  }
4176 
4183  operator bool() const noexcept
4184  {
4185  return this->m_iterator[0] < this->m_end;
4186  }
4187 
4192  sample& operator []( int channel ) const noexcept
4193  {
4194  return *this->m_iterator[channel];
4195  }
4196 
4202  roi_pixel_iterator& operator ++() noexcept
4203  {
4204  this->Increment();
4205  return *this;
4206  }
4207 
4213  roi_pixel_iterator operator ++( int ) noexcept
4214  {
4215  roi_pixel_iterator i0( *this );
4216  this->Increment();
4217  return i0;
4218  }
4219 
4225  roi_pixel_iterator& operator --() noexcept
4226  {
4227  this->Decrement();
4228  return *this;
4229  }
4230 
4236  roi_pixel_iterator operator --( int ) noexcept
4237  {
4238  roi_pixel_iterator i0( *this );
4239  this->Decrement();
4240  return i0;
4241  }
4242 
4252  roi_pixel_iterator& operator +=( distance_type delta ) noexcept
4253  {
4254  int w = this->m_rowEnd - this->m_rowBegin;
4255  iterator_base::MoveBy( delta%w, delta/w );
4256  return *this;
4257  }
4258 
4268  roi_pixel_iterator& operator -=( distance_type delta ) noexcept
4269  {
4270  int w = this->m_rowEnd - this->m_rowBegin;
4271  iterator_base::MoveBy( -delta%w, -delta/w );
4272  return *this;
4273  }
4274 
4283  roi_pixel_iterator& MoveBy( int dx, int dy ) noexcept
4284  {
4285  iterator_base::MoveBy( dx, dy );
4286  return *this;
4287  }
4288 
4294  {
4295  roi_pixel_iterator j( i );
4296  j += delta;
4297  return j;
4298  }
4299 
4305  {
4306  roi_pixel_iterator j( i );
4307  j += delta;
4308  return j;
4309  }
4310 
4316  {
4317  roi_pixel_iterator j( i );
4318  j -= delta;
4319  return j;
4320  }
4321 
4326  friend bool operator ==( const roi_pixel_iterator& i, const roi_pixel_iterator& j ) noexcept
4327  {
4328  return i.m_iterator[0] == j.m_iterator[0];
4329  }
4330 
4335  friend bool operator <( const roi_pixel_iterator& i, const roi_pixel_iterator& j ) noexcept
4336  {
4337  return i.m_iterator[0] < j.m_iterator[0];
4338  }
4339  };
4340 
4341  // -------------------------------------------------------------------------
4342 
4352  class const_roi_pixel_iterator : private roi_pixel_iterator_base<const GenericImage<P>, const sample*>
4353  {
4354  public:
4355 
4360 
4365 
4369  using sample = typename image_type::sample;
4370 
4371  using iterator_base = roi_pixel_iterator_base<const GenericImage<P>, const sample*>;
4372 
4377 
4392  const_roi_pixel_iterator( const image_type& image, const Rect& rect = Rect( 0 ) )
4393  : iterator_base( image, rect )
4394  {
4395  }
4396 
4401 
4405  const_roi_pixel_iterator& operator =( const const_roi_pixel_iterator& ) = default;
4406 
4411  bool IsValid() const noexcept
4412  {
4413  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
4414  }
4415 
4420  const image_type& Image() const noexcept
4421  {
4422  return *this->m_image;
4423  }
4424 
4429  const sample* Position( int channel ) const noexcept
4430  {
4431  return this->m_iterator[channel];
4432  }
4433 
4440  operator bool() const noexcept
4441  {
4442  return this->m_iterator[0] < this->m_end;
4443  }
4444 
4449  const sample& operator []( int channel ) const noexcept
4450  {
4451  return *this->m_iterator[channel];
4452  }
4453 
4459  const_roi_pixel_iterator& operator ++() noexcept
4460  {
4461  this->Increment();
4462  return *this;
4463  }
4464 
4470  const_roi_pixel_iterator operator ++( int ) noexcept
4471  {
4472  const_roi_pixel_iterator i0( *this );
4473  this->Increment();
4474  return i0;
4475  }
4476 
4482  const_roi_pixel_iterator& operator --() noexcept
4483  {
4484  this->Decrement();
4485  return *this;
4486  }
4487 
4493  const_roi_pixel_iterator operator --( int ) noexcept
4494  {
4495  const_roi_pixel_iterator i0( *this );
4496  this->Decrement();
4497  return i0;
4498  }
4499 
4509  const_roi_pixel_iterator& operator +=( distance_type delta ) noexcept
4510  {
4511  int w = this->m_rowEnd - this->m_rowBegin;
4512  iterator_base::MoveBy( delta%w, delta/w );
4513  return *this;
4514  }
4515 
4525  const_roi_pixel_iterator& operator -=( distance_type delta ) noexcept
4526  {
4527  int w = this->m_rowEnd - this->m_rowBegin;
4528  iterator_base::MoveBy( -delta%w, -delta/w );
4529  return *this;
4530  }
4531 
4540  const_roi_pixel_iterator& MoveBy( int dx, int dy ) noexcept
4541  {
4542  iterator_base::MoveBy( dx, dy );
4543  return *this;
4544  }
4545 
4551  {
4552  const_roi_pixel_iterator j( i );
4553  j += delta;
4554  return j;
4555  }
4556 
4562  {
4563  const_roi_pixel_iterator j( i );
4564  j += delta;
4565  return j;
4566  }
4567 
4573  {
4574  const_roi_pixel_iterator j( i );
4575  j -= delta;
4576  return j;
4577  }
4578 
4583  friend bool operator ==( const const_roi_pixel_iterator& i, const const_roi_pixel_iterator& j ) noexcept
4584  {
4585  return i.m_iterator[0] == j.m_iterator[0];
4586  }
4587 
4592  friend bool operator <( const const_roi_pixel_iterator& i, const const_roi_pixel_iterator& j ) noexcept
4593  {
4594  return i.m_iterator[0] < j.m_iterator[0];
4595  }
4596  };
4597 
4598  // -------------------------------------------------------------------------
4599 
4600  template <class image_type, class iterator_base, class sample_pointer, class filter_type>
4601  class filter_pixel_iterator_base : public iterator_base
4602  {
4603  protected:
4604 
4605  filter_type m_filter;
4606  sample_pointer m_begin = nullptr;
4607 
4608  filter_pixel_iterator_base() = default;
4609 
4610  filter_pixel_iterator_base( image_type& image, const filter_type& filter )
4611  : iterator_base( image )
4612  , m_filter( filter )
4613  , m_begin( iterator_base::m_iterator )
4614  {
4615  JumpToNextValidSample();
4616  }
4617 
4618  filter_pixel_iterator_base( const iterator_base& i, const filter_type& filter )
4619  : iterator_base( i )
4620  , m_filter( filter )
4621  , m_begin( iterator_base::m_iterator )
4622  {
4623  JumpToNextValidSample();
4624  }
4625 
4626  filter_pixel_iterator_base( const filter_pixel_iterator_base& ) = default;
4627 
4628  filter_pixel_iterator_base& operator =( const filter_pixel_iterator_base& ) = default;
4629 
4630  filter_pixel_iterator_base& operator =( const iterator_base& i ) noexcept
4631  {
4632  (void)iterator_base::operator =( i );
4633  JumpToNextValidSample();
4634  }
4635 
4636  void JumpToNextValidSample() noexcept
4637  {
4638  while ( this->m_iterator[0] < this->m_end && !this->m_filter( this->m_iterator ) )
4639  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4640  ++this->m_iterator[i];
4641  }
4642 
4643  void JumpToPrevValidSample() noexcept
4644  {
4645  while ( this->m_iterator[0] > this->m_begin && !this->m_filter( this->m_iterator ) )
4646  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4647  --this->m_iterator[i];
4648  }
4649  };
4650 
4651  // -------------------------------------------------------------------------
4652 
4688  template <class F>
4690  public filter_pixel_iterator_base<GenericImage<P>, pixel_iterator, sample*, F>
4691  {
4692  public:
4693 
4698 
4703 
4707  using sample = typename image_type::sample;
4708 
4713  using filter_type = F;
4714 
4715  using iterator_base = filter_pixel_iterator_base<GenericImage<P>, pixel_iterator, sample*, F>;
4716 
4721 
4730  filter_pixel_iterator( image_type& image, const F& filter )
4731  : iterator_base( image.EnsureUnique(), filter )
4732  {
4733  }
4734 
4739  filter_pixel_iterator( const pixel_iterator& i, const F& filter )
4740  : iterator_base( i, filter )
4741  {
4742  }
4743 
4748 
4752  filter_pixel_iterator& operator =( const filter_pixel_iterator& ) = default;
4753 
4758  filter_pixel_iterator& operator =( const pixel_iterator& i ) noexcept
4759  {
4760  (void)iterator_base::operator =( i );
4761  return *this;
4762  }
4763 
4768  bool IsValid() const noexcept
4769  {
4770  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
4771  }
4772 
4776  image_type& Image() const noexcept
4777  {
4778  return *this->m_image;
4779  }
4780 
4785  const filter_type& Filter() const noexcept
4786  {
4787  return this->m_filter;
4788  }
4789 
4794  filter_type& Filter() noexcept
4795  {
4796  return this->m_filter;
4797  }
4798 
4803  sample* Position( int channel ) const noexcept
4804  {
4805  return this->m_iterator[channel];
4806  }
4807 
4813  operator bool() const noexcept
4814  {
4815  return this->m_iterator[0] < this->m_end;
4816  }
4817 
4822  sample& operator []( int channel ) const noexcept
4823  {
4824  return *this->m_iterator[channel];
4825  }
4826 
4832  filter_pixel_iterator& operator ++() noexcept
4833  {
4834  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4835  ++this->m_iterator[i];
4836  this->JumpToNextValidSample();
4837  return *this;
4838  }
4839 
4845  filter_pixel_iterator operator ++( int ) noexcept
4846  {
4847  filter_pixel_iterator i0( *this );
4848  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4849  ++this->m_iterator[i];
4850  this->JumpToNextValidSample();
4851  return i0;
4852  }
4853 
4859  filter_pixel_iterator& operator --() noexcept
4860  {
4861  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4862  --this->m_iterator[i];
4863  this->JumpToPrevValidSample();
4864  return *this;
4865  }
4866 
4872  filter_pixel_iterator operator --( int ) noexcept
4873  {
4874  filter_pixel_iterator i0( *this );
4875  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4876  --this->m_iterator[i];
4877  this->JumpToPrevValidSample();
4878  return i0;
4879  }
4880 
4888  filter_pixel_iterator& operator +=( distance_type delta ) noexcept
4889  {
4890  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4891  this->m_iterator[i] += delta;
4892  this->JumpToNextValidSample();
4893  return *this;
4894  }
4895 
4903  filter_pixel_iterator& operator -=( distance_type delta ) noexcept
4904  {
4905  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4906  this->m_iterator[i] -= delta;
4907  this->JumpToPrevValidSample();
4908  return *this;
4909  }
4910 
4918  filter_pixel_iterator& MoveBy( int dx, int dy ) noexcept
4919  {
4920  distance_type d = distance_type( dy )*this->m_image->Width() + distance_type( dx );
4921  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4922  this->m_iterator[i] += d;
4923  if ( d >= 0 )
4924  this->JumpToNextValidSample();
4925  else
4926  this->JumpToPrevValidSample();
4927  return *this;
4928  }
4929 
4935  {
4936  filter_pixel_iterator j( i );
4937  j += delta;
4938  return j;
4939  }
4940 
4946  {
4947  filter_pixel_iterator j( i );
4948  j += delta;
4949  return j;
4950  }
4951 
4957  {
4958  filter_pixel_iterator j( i );
4959  j -= delta;
4960  return j;
4961  }
4962 
4967  friend bool operator ==( const filter_pixel_iterator& i, const filter_pixel_iterator& j ) noexcept
4968  {
4969  return i.m_iterator[0] == j.m_iterator[0];
4970  }
4971 
4976  friend bool operator <( const filter_pixel_iterator& i, const filter_pixel_iterator& j ) noexcept
4977  {
4978  return i.m_iterator[0] < j.m_iterator[0];
4979  }
4980  };
4981 
4982  // -------------------------------------------------------------------------
4983 
5019  template <class F>
5021  public filter_pixel_iterator_base<const GenericImage<P>, const_pixel_iterator, const sample*, F>
5022  {
5023  public:
5024 
5029 
5034 
5038  using sample = typename image_type::sample;
5039 
5044  using filter_type = F;
5045 
5046  using iterator_base = filter_pixel_iterator_base<const GenericImage<P>, const_pixel_iterator, const sample*, F>;
5047 
5052 
5061  const_filter_pixel_iterator( const image_type& image, const F& filter )
5062  : iterator_base( image, filter )
5063  {
5064  }
5065 
5071  : iterator_base( i, filter )
5072  {
5073  }
5074 
5079 
5084 
5089  const_filter_pixel_iterator& operator =( const const_pixel_iterator& i ) noexcept
5090  {
5091  (void)iterator_base::operator =( i );
5092  return *this;
5093  }
5094 
5099  bool IsValid() const noexcept
5100  {
5101  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
5102  }
5103 
5108  const image_type& Image() const noexcept
5109  {
5110  return *this->m_image;
5111  }
5112 
5117  const filter_type& Filter() const noexcept
5118  {
5119  return this->m_filter;
5120  }
5121 
5126  filter_type& Filter() noexcept
5127  {
5128  return this->m_filter;
5129  }
5130 
5135  const sample* Position( int channel ) const noexcept
5136  {
5137  return this->m_iterator[channel];
5138  }
5139 
5145  operator bool() const noexcept
5146  {
5147  return this->m_iterator[0] < this->m_end;
5148  }
5149 
5154  const sample& operator []( int channel ) const noexcept
5155  {
5156  return *this->m_iterator[channel];
5157  }
5158 
5164  const_filter_pixel_iterator& operator ++() noexcept
5165  {
5166  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5167  ++this->m_iterator[i];
5168  this->JumpToNextValidSample();
5169  return *this;
5170  }
5171 
5177  const_filter_pixel_iterator operator ++( int ) noexcept
5178  {
5179  const_filter_pixel_iterator i0( *this );
5180  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5181  ++this->m_iterator[i];
5182  this->JumpToNextValidSample();
5183  return i0;
5184  }
5185 
5191  const_filter_pixel_iterator& operator --() noexcept
5192  {
5193  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5194  --this->m_iterator[i];
5195  this->JumpToPrevValidSample();
5196  return *this;
5197  }
5198 
5204  const_filter_pixel_iterator operator --( int ) noexcept
5205  {
5206  const_filter_pixel_iterator i0( *this );
5207  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5208  --this->m_iterator[i];
5209  this->JumpToPrevValidSample();
5210  return i0;
5211  }
5212 
5220  const_filter_pixel_iterator& operator +=( distance_type delta ) noexcept
5221  {
5222  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5223  this->m_iterator[i] += delta;
5224  this->JumpToNextValidSample();
5225  return *this;
5226  }
5227 
5235  const_filter_pixel_iterator& operator -=( distance_type delta ) noexcept
5236  {
5237  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5238  this->m_iterator[i] -= delta;
5239  this->JumpToPrevValidSample();
5240  return *this;
5241  }
5242 
5250  const_filter_pixel_iterator& MoveBy( int dx, int dy ) noexcept
5251  {
5252  distance_type d = distance_type( dy )*this->m_image->Width() + distance_type( dx );
5253  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5254  this->m_iterator[i] += d;
5255  if ( d >= 0 )
5256  this->JumpToNextValidSample();
5257  else
5258  this->JumpToPrevValidSample();
5259  return *this;
5260  }
5261 
5267  {
5269  j += delta;
5270  return j;
5271  }
5272 
5278  {
5280  j += delta;
5281  return j;
5282  }
5283 
5289  {
5291  j -= delta;
5292  return j;
5293  }
5294 
5299  friend bool operator ==( const const_filter_pixel_iterator& i, const const_filter_pixel_iterator& j ) noexcept
5300  {
5301  return i.m_iterator[0] == j.m_iterator[0];
5302  }
5303 
5308  friend bool operator <( const const_filter_pixel_iterator& i, const const_filter_pixel_iterator& j ) noexcept
5309  {
5310  return i.m_iterator[0] < j.m_iterator[0];
5311  }
5312  };
5313 
5314  // -------------------------------------------------------------------------
5315 
5316  template <class image_type, class sample_pointer, class filter_type>
5317  class roi_filter_pixel_iterator_base : public roi_pixel_iterator_base<image_type, sample_pointer>
5318  {
5319  protected:
5320 
5321  using roi_iterator_base = roi_pixel_iterator_base<image_type, sample_pointer>;
5322 
5323  filter_type m_filter;
5324  sample_pointer m_begin = nullptr;
5325 
5326  roi_filter_pixel_iterator_base() = default;
5327 
5328  roi_filter_pixel_iterator_base( image_type& image, const filter_type& filter, const Rect& rect )
5329  : roi_iterator_base( image, rect )
5330  , m_filter( filter )
5331  , m_begin( roi_iterator_base::m_iterator )
5332  {
5333  JumpToNextValidSample();
5334  }
5335 
5336  roi_filter_pixel_iterator_base( const roi_iterator_base& i, const filter_type& filter )
5337  : roi_iterator_base( i )
5338  , m_filter( filter )
5339  , m_begin( roi_iterator_base::m_iterator )
5340  {
5341  JumpToNextValidSample();
5342  }
5343 
5344  roi_filter_pixel_iterator_base( const roi_filter_pixel_iterator_base& ) = default;
5345 
5346  roi_filter_pixel_iterator_base& operator =( const roi_filter_pixel_iterator_base& ) = default;
5347 
5348  roi_filter_pixel_iterator_base& operator =( const roi_iterator_base& i ) noexcept
5349  {
5350  (void)roi_iterator_base::operator =( i );
5351  JumpToNextValidSample();
5352  return *this;
5353  }
5354 
5355  void JumpToNextValidSample() noexcept
5356  {
5357  while ( this->m_iterator[0] < this->m_end && !this->m_filter( this->m_iterator ) )
5358  roi_iterator_base::Increment();
5359  }
5360 
5361  void JumpToPrevValidSample() noexcept
5362  {
5363  while ( this->m_iterator[0] > this->m_begin && !this->m_filter( this->m_iterator ) )
5364  roi_iterator_base::Decrement();
5365  }
5366  };
5367 
5368  // -------------------------------------------------------------------------
5369 
5380  template <class F>
5381  class roi_filter_pixel_iterator : public roi_filter_pixel_iterator_base<GenericImage<P>, sample*, F>
5382  {
5383  public:
5384 
5389 
5394 
5398  using sample = typename image_type::sample;
5399 
5404  using filter_type = F;
5405 
5406  using iterator_base = roi_filter_pixel_iterator_base<GenericImage<P>, sample*, F>;
5407 
5412 
5430  roi_filter_pixel_iterator( image_type& image, const F& filter, const Rect& rect = Rect( 0 ) )
5431  : iterator_base( image.EnsureUnique(), filter, rect )
5432  {
5433  }
5434 
5439  roi_filter_pixel_iterator( const roi_pixel_iterator& i, const F& filter )
5440  : iterator_base( i, filter )
5441  {
5442  }
5443 
5448 
5452  roi_filter_pixel_iterator& operator =( const roi_filter_pixel_iterator& ) = default;
5453 
5457  roi_filter_pixel_iterator& operator =( const roi_pixel_iterator& i ) noexcept
5458  {
5459  (void)iterator_base::operator =( i );
5460  return *this;
5461  }
5462 
5467  bool IsValid() const noexcept
5468  {
5469  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
5470  }
5471 
5475  image_type& Image() const noexcept
5476  {
5477  return *this->m_image;
5478  }
5479 
5484  const filter_type& Filter() const noexcept
5485  {
5486  return this->m_filter;
5487  }
5488 
5493  filter_type& Filter() noexcept
5494  {
5495  return this->m_filter;
5496  }
5497 
5502  sample* Position( int channel ) const noexcept
5503  {
5504  return this->m_iterator[channel];
5505  }
5506 
5513  operator bool() const noexcept
5514  {
5515  return this->m_iterator[0] < this->m_end;
5516  }
5517 
5522  sample& operator []( int channel ) const noexcept
5523  {
5524  return *this->m_iterator[channel];
5525  }
5526 
5532  roi_filter_pixel_iterator& operator ++() noexcept
5533  {
5534  this->Increment();
5535  this->JumpToNextValidSample();
5536  return *this;
5537  }
5538 
5544  roi_filter_pixel_iterator operator ++( int ) noexcept
5545  {
5546  roi_filter_pixel_iterator i0( *this );
5547  this->Increment();
5548  this->JumpToNextValidSample();
5549  return i0;
5550  }
5551 
5557  roi_filter_pixel_iterator& operator --() noexcept
5558  {
5559  this->Decrement();
5560  this->JumpToPrevValidSample();
5561  return *this;
5562  }
5563 
5569  roi_filter_pixel_iterator operator --( int ) noexcept
5570  {
5571  roi_filter_pixel_iterator i0( *this );
5572  this->Decrement();
5573  this->JumpToPrevValidSample();
5574  return i0;
5575  }
5576 
5586  roi_filter_pixel_iterator& operator +=( distance_type delta ) noexcept
5587  {
5588  int w = this->m_rowEnd - this->m_rowBegin;
5589  return MoveBy( delta%w, delta/w );
5590  }
5591 
5601  roi_filter_pixel_iterator& operator -=( distance_type delta ) noexcept
5602  {
5603  int w = this->m_rowEnd - this->m_rowBegin;
5604  return MoveBy( -delta%w, -delta/w );
5605  }
5606 
5615  roi_filter_pixel_iterator& MoveBy( int dx, int dy ) noexcept
5616  {
5617  sample* __restrict__ i0 = this->m_iterator[0];
5618  iterator_base::MoveBy( dx, dy );
5619  if ( this->m_iterator[0] >= i0 )
5620  this->JumpToNextValidSample();
5621  else
5622  this->JumpToPrevValidSample();
5623  return *this;
5624  }
5625 
5631  {
5633  j += delta;
5634  return j;
5635  }
5636 
5642  {
5644  j += delta;
5645  return j;
5646  }
5647 
5653  {
5655  j -= delta;
5656  return j;
5657  }
5658 
5663  friend bool operator ==( const roi_filter_pixel_iterator& i, const roi_filter_pixel_iterator& j ) noexcept
5664  {
5665  return i.m_iterator[0] == j.m_iterator[0];
5666  }
5667 
5672  friend bool operator <( const roi_filter_pixel_iterator& i, const roi_filter_pixel_iterator& j ) noexcept
5673  {
5674  return i.m_iterator[0] < j.m_iterator[0];
5675  }
5676  };
5677 
5678  // -------------------------------------------------------------------------
5679 
5690  template <class F>
5691  class const_roi_filter_pixel_iterator : public roi_filter_pixel_iterator_base<const GenericImage<P>, const sample*, F>
5692  {
5693  public:
5694 
5699 
5704 
5708  using sample = typename image_type::sample;
5709 
5714  using filter_type = F;
5715 
5716  using iterator_base = roi_filter_pixel_iterator_base<const GenericImage<P>, const sample*, F>;
5717 
5722 
5741  const_roi_filter_pixel_iterator( const image_type& image, const F& filter, const Rect& rect = Rect( 0 ) )
5742  : iterator_base( image, filter, rect )
5743  {
5744  }
5745 
5751  : iterator_base( i, filter )
5752  {
5753  }
5754 
5759 
5760 
5765 
5770  {
5771  (void)iterator_base::operator =( i );
5772  return *this;
5773  }
5774 
5779  bool IsValid() const noexcept
5780  {
5781  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
5782  }
5783 
5788  const image_type& Image() const noexcept
5789  {
5790  return *this->m_image;
5791  }
5792 
5797  const filter_type& Filter() const noexcept
5798  {
5799  return this->m_filter;
5800  }
5801 
5806  filter_type& Filter() noexcept
5807  {
5808  return this->m_filter;
5809  }
5810 
5815  const sample* Position( int channel ) const noexcept
5816  {
5817  return this->m_iterator[channel];
5818  }
5819 
5826  operator bool() const noexcept
5827  {
5828  return this->m_iterator[0] < this->m_end;
5829  }
5830 
5835  const sample& operator []( int channel ) const noexcept
5836  {
5837  return *this->m_iterator[channel];
5838  }
5839 
5845  const_roi_filter_pixel_iterator& operator ++() noexcept
5846  {
5847  this->Increment();
5848  this->JumpToNextValidSample();
5849  return *this;
5850  }
5851 
5857  const_roi_filter_pixel_iterator operator ++( int ) noexcept
5858  {
5859  const_roi_filter_pixel_iterator i0( *this );
5860  this->Increment();
5861  this->JumpToNextValidSample();
5862  return i0;
5863  }
5864 
5870  const_roi_filter_pixel_iterator& operator --() noexcept
5871  {
5872  this->Decrement();
5873  this->JumpToPrevValidSample();
5874  return *this;
5875  }
5876 
5882  const_roi_filter_pixel_iterator operator --( int ) noexcept
5883  {
5884  const_roi_filter_pixel_iterator i0( *this );
5885  this->Decrement();
5886  this->JumpToPrevValidSample();
5887  return i0;
5888  }
5889 
5899  const_roi_filter_pixel_iterator& operator +=( distance_type delta ) noexcept
5900  {
5901  int w = this->m_rowEnd - this->m_rowBegin;
5902  return MoveBy( delta%w, delta/w );
5903  }
5904 
5914  const_roi_filter_pixel_iterator& operator -=( distance_type delta ) noexcept
5915  {
5916  int w = this->m_rowEnd - this->m_rowBegin;
5917  return MoveBy( -delta%w, -delta/w );
5918  }
5919 
5928  const_roi_filter_pixel_iterator& MoveBy( int dx, int dy ) noexcept
5929  {
5930  const sample* __restrict__ i0 = this->m_iterator[0];
5931  iterator_base::MoveBy( dx, dy );
5932  if ( this->m_iterator[0] >= i0 )
5933  this->JumpToNextValidSample();
5934  else
5935  this->JumpToPrevValidSample();
5936  return *this;
5937  }
5938 
5944  {
5946  j += delta;
5947  return j;
5948  }
5949 
5955  {
5957  j += delta;
5958  return j;
5959  }
5960 
5966  {
5968  j -= delta;
5969  return j;
5970  }
5971 
5977  {
5978  return i.m_iterator[0] == j.m_iterator[0];
5979  }
5980 
5986  {
5987  return i.m_iterator[0] < j.m_iterator[0];
5988  }
5989  };
5990 
5991  // -------------------------------------------------------------------------
5992 
5997  static bool IsFloatSample() noexcept
5998  {
5999  return pixel_traits::IsFloatSample();
6000  }
6001 
6006  static bool IsComplexSample() noexcept
6007  {
6008  return pixel_traits::IsComplexSample();
6009  }
6010 
6015  static int BytesPerSample() noexcept
6016  {
6017  return P::BytesPerSample();
6018  }
6019 
6024  static int BitsPerSample() noexcept
6025  {
6026  return P::BitsPerSample();
6027  }
6028 
6036  template <class P1>
6037  bool SameSampleType( const GenericImage<P1>& image ) const noexcept
6038  {
6039  return image.BitsPerSample() == BitsPerSample() &&
6040  image.IsFloatSample() == IsFloatSample() &&
6041  image.IsComplexSample() == IsComplexSample();
6042  }
6043 
6049  bool SameSampleType( const GenericImage& image ) const noexcept
6050  {
6051  return true;
6052  }
6053 
6054  // -------------------------------------------------------------------------
6055 
6061  {
6062  m_data = new Data( this );
6063  }
6064 
6094  GenericImage( const GenericImage& image )
6095  {
6096  if ( !image.IsShared() )
6097  if ( image.IsCompletelySelected() )
6098  {
6099  image.m_data->Attach( this );
6100  m_data = image.m_data;
6101  m_status = image.m_status;
6102  ResetSelections();
6103  return;
6104  }
6105 
6106  m_data = new Data( this );
6107  (void)Assign( image );
6108  }
6109 
6114  : AbstractImage( image )
6115  , m_data( image.m_data )
6116  {
6117  image.m_data = nullptr;
6118  }
6119 
6132  template <class P1>
6134  {
6135  m_data = new Data( this );
6136  (void)Assign( image );
6137  }
6138 
6179  template <class P1>
6180  GenericImage( const GenericImage<P1>& image, const Rect& rect, int firstChannel = -1, int lastChannel = -1 )
6181  {
6182  m_data = new Data( this );
6183  (void)Assign( image, rect, firstChannel, lastChannel );
6184  }
6185 
6204  GenericImage( int width, int height, color_space colorSpace = ColorSpace::Gray )
6205  {
6206  m_data = new Data( this );
6207  m_data->Allocate( width, height, ColorSpace::NumberOfNominalChannels( colorSpace ), colorSpace );
6208  ResetSelections();
6209  }
6210 
6225  explicit GenericImage( File& stream )
6226  {
6227  m_data = new Data( this );
6228  Read( stream );
6229  }
6230 
6250  explicit GenericImage( void* handle )
6251  {
6252  m_data = new Data( this, handle );
6253  ResetSelections();
6254  }
6255 
6283  GenericImage( void*, int width, int height, color_space colorSpace = ColorSpace::Gray )
6284  {
6285  m_data = new Data( this, width, height, ColorSpace::NumberOfNominalChannels( colorSpace ), colorSpace );
6286  ResetSelections();
6287  }
6288 
6306  ~GenericImage() override
6307  {
6308  if ( m_data != nullptr )
6309  {
6310  DetachFromData();
6311  m_data = nullptr;
6312  }
6313  }
6314 
6315  // -------------------------------------------------------------------------
6316 
6333  bool IsShared() const noexcept
6334  {
6335  return m_data->IsShared();
6336  }
6337 
6348  bool IsUnique() const noexcept
6349  {
6350  return m_data->IsUnique();
6351  }
6352 
6366  {
6367  if ( m_data->IsShared() )
6368  {
6369  GenericImage local_;
6370  GenericImage* local = &local_; // ### Workaround to GCC 7's 'dereferencing type-punned pointer' bugs
6371  local->m_data->Allocate( m_width, m_height, m_numberOfChannels, m_colorSpace );
6372  local->m_RGBWS = m_RGBWS;
6373  local->m_selected = m_selected;
6374  local->m_savedSelections = m_savedSelections;
6375  local->m_status = m_status;
6376  for ( int c = 0; c < m_numberOfChannels; ++c )
6377  P::Copy( (*local)[c], m_channelData( c ), NumberOfPixels() );
6378 
6379  local->m_data->Attach( this );
6380  DetachFromData();
6381  m_data = local->m_data;
6382  }
6383  return *this;
6384  }
6385 
6402  {
6403  if ( !m_data->IsUnique() )
6404  {
6405  Data* newData = m_data->Clone( this );
6406  DetachFromData();
6407  m_data = newData;
6408  }
6409  return *this;
6410  }
6411 
6434  pixel_allocator& Allocator() const noexcept
6435  {
6436  return m_allocator;
6437  }
6438 
6444  void Synchronize()
6445  {
6446  m_data->SynchronizeWithSharedImage();
6447  ResetSelections();
6448  }
6449 
6484  GenericImage& AllocateData( int width, int height,
6485  int numberOfChannels = 1,
6486  color_space colorSpace = ColorSpace::Gray )
6487  {
6488  if ( !m_data->IsUnique() )
6489  {
6490  Data* newData = new Data( this );
6491  DetachFromData();
6492  m_data = newData;
6493  }
6494  m_data->Allocate( width, height, numberOfChannels, colorSpace );
6495  ResetSelections();
6496  return *this;
6497  }
6498 
6510  int numberOfChannels = 1,
6511  color_space colorSpace = ColorSpace::Gray )
6512  {
6513  return AllocateData( rect.Width(), rect.Height(), numberOfChannels, colorSpace );
6514  }
6515 
6528  {
6529  if ( !m_data->IsEmpty() )
6530  if ( m_data->IsUnique() )
6531  m_data->Deallocate();
6532  else
6533  {
6534  Data* newData = new Data( this );
6535  DetachFromData();
6536  m_data = newData;
6537  }
6538  ResetSelections();
6539  return *this;
6540  }
6541 
6597  GenericImage& ImportData( sample** data, int width, int height,
6598  int numberOfChannels = 1, color_space colorSpace = ColorSpace::Gray )
6599  {
6600  if ( !m_data->IsUnique() )
6601  {
6602  if ( m_data->IsShared() )
6603  throw Error( "GenericImage::ImportData(): Invalid operation for an aliased shared image" );
6604  Data* newData = new Data( this );
6605  DetachFromData();
6606  m_data = newData;
6607  }
6608  m_data->Import( data, width, height, numberOfChannels, colorSpace );
6609  ResetSelections();
6610  return *this;
6611  }
6612 
6648  {
6649  if ( !m_data->IsUnique() )
6650  throw Error( "GenericImage::ReleaseData(): Invalid operation for an aliased image" );
6651  sample** data = m_data->Release();
6652  ResetSelections();
6653  return data;
6654  }
6655 
6656  // -------------------------------------------------------------------------
6657 
6662  size_type LineSize() const noexcept
6663  {
6664  return BytesPerSample() * size_type( m_width );
6665  }
6666 
6671  size_type ChannelSize() const noexcept
6672  {
6673  return BytesPerSample() * NumberOfPixels();
6674  }
6675 
6682  size_type ImageSize() const noexcept
6683  {
6684  return ChannelSize() * size_type( m_numberOfChannels );
6685  }
6686 
6692  size_type NominalSize() const noexcept
6693  {
6694  return ChannelSize() * NumberOfNominalChannels();
6695  }
6696 
6702  size_type AlphaSize() const noexcept
6703  {
6704  return ChannelSize() * NumberOfAlphaChannels();
6705  }
6706 
6721  sample* PixelData( int channel = 0 )
6722  {
6723  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6724  EnsureUnique();
6725  return m_channelData( channel );
6726  }
6727 
6734  const sample* PixelData( int channel = 0 ) const noexcept
6735  {
6736  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6737  return m_channelData( channel );
6738  }
6739 
6743  operator bool() const noexcept
6744  {
6745  return m_data != nullptr && !m_data->IsEmpty();
6746  }
6747 
6758  sample* operator []( int channel )
6759  {
6760  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6761  return PixelData( channel );
6762  }
6763 
6770  const sample* operator []( int channel ) const noexcept
6771  {
6772  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6773  return PixelData( channel );
6774  }
6775 
6784  {
6785  PCL_PRECONDITION( 0 < m_numberOfChannels )
6786  return PixelData( 0 );
6787  }
6788 
6795  const sample* operator *() const noexcept
6796  {
6797  PCL_PRECONDITION( 0 < m_numberOfChannels )
6798  return PixelData( 0 );
6799  }
6800 
6820  sample* ScanLine( int y, int channel = 0 )
6821  {
6822  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6823  PCL_PRECONDITION( 0 <= y && y < m_height )
6824  EnsureUnique();
6825  return m_channelData( channel ) + RowOffset( y );
6826  }
6827 
6834  const sample* ScanLine( int y, int channel = 0 ) const noexcept
6835  {
6836  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6837  PCL_PRECONDITION( 0 <= y && y < m_height )
6838  return m_channelData( channel ) + RowOffset( y );
6839  }
6840 
6864  sample* PixelAddress( int x, int y, int channel = 0 )
6865  {
6866  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6867  PCL_PRECONDITION( 0 <= x && x < m_width )
6868  PCL_PRECONDITION( 0 <= y && y < m_height )
6869  EnsureUnique();
6870  return m_channelData( channel ) + PixelOffset( x, y );
6871  }
6872 
6879  const sample* PixelAddress( int x, int y, int channel = 0 ) const noexcept
6880  {
6881  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6882  PCL_PRECONDITION( 0 <= x && x < m_width )
6883  PCL_PRECONDITION( 0 <= y && y < m_height )
6884  return m_channelData( channel ) + PixelOffset( x, y );
6885  }
6886 
6907  sample* PixelAddress( const Point& p, int channel = 0 )
6908  {
6909  return PixelAddress( p.x, p.y, channel );
6910  }
6911 
6919  const sample* PixelAddress( const Point& p, int channel = 0 ) const noexcept
6920  {
6921  return PixelAddress( p.x, p.y, channel );
6922  }
6923 
6944  sample& operator ()( int x, int y, int channel = 0 )
6945  {
6946  return *PixelAddress( x, y, channel );
6947  }
6948 
6965  sample operator ()( int x, int y, int channel = 0 ) const noexcept
6966  {
6967  return *PixelAddress( x, y, channel );
6968  }
6969 
6987  sample& operator ()( const Point& p, int channel = 0 )
6988  {
6989  return *PixelAddress( p, channel );
6990  }
6991 
7005  sample operator ()( const Point& p, int channel = 0 ) const noexcept
7006  {
7007  return *PixelAddress( p, channel );
7008  }
7009 
7017  sample& Pixel( int x, int y, int channel = 0 )
7018  {
7019  return operator()( x, y, channel );
7020  }
7021 
7029  sample Pixel( int x, int y, int channel = 0 ) const noexcept
7030  {
7031  return operator()( x, y, channel );
7032  }
7033 
7041  sample& Pixel( const Point& p, int channel = 0 )
7042  {
7043  return operator()( p, channel );
7044  }
7045 
7054  sample Pixel( const Point& p, int channel = 0 ) const noexcept
7055  {
7056  return operator()( p, channel );
7057  }
7058 
7059  // -------------------------------------------------------------------------
7060 
7068  void SetRGBWorkingSpace( const RGBColorSystem& RGBWS ) override
7069  {
7070  if ( !IsShared() )
7071  {
7072  EnsureUnique();
7073  m_RGBWS = RGBWS;
7074  }
7075  }
7076 
7077  // -------------------------------------------------------------------------
7078 
7149  template <class P1>
7151  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
7152  {
7153  m_status = image.Status();
7154 
7155  Rect r = rect;
7156  if ( !image.ParseSelection( r, firstChannel, lastChannel ) )
7157  {
7158  FreeData();
7159  return *this;
7160  }
7161 
7162  int n = 1 + lastChannel - firstChannel;
7163  AllocateData( r, n, (firstChannel == 0 && n >= ColorSpace::NumberOfNominalChannels( image.ColorSpace() )) ?
7164  image.ColorSpace() : ColorSpace::Gray );
7165 
7166  if ( !IsShared() ) // ### cannot modify a shared image's RGBWS
7167  m_RGBWS = image.RGBWorkingSpace();
7168 
7169  ResetSelections();
7170 
7171  if ( r == image.Bounds() )
7172  for ( int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7173  P::Copy( m_channelData( c ), image[firstChannel], NumberOfPixels() );
7174  else
7175  for ( int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7176  {
7177  sample* f = m_channelData( c );
7178  const typename P1::sample* g = image.PixelAddress( r.LeftTop(), firstChannel );
7179  for ( int y = 0; y < m_height; ++y, f += m_width, g += image.Width() )
7180  P::Copy( f, g, m_width );
7181  }
7182 
7183  return *this;
7184  }
7185 
7186  GenericImage& Assign( const GenericImage& image,
7187  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
7188  {
7189  m_status = image.Status();
7190 
7191  Rect r = rect;
7192  if ( !image.ParseSelection( r, firstChannel, lastChannel ) )
7193  {
7194  FreeData();
7195  return *this;
7196  }
7197 
7198 #define completeSelection (firstChannel == 0 && lastChannel == image.m_numberOfChannels-1 && r == image.Bounds())
7199 
7200  if ( m_data == image.m_data )
7201  {
7202  // Self-assignment
7203  if ( !completeSelection )
7204  {
7205  GenericImage result( image, r, firstChannel, lastChannel ); // ### implicit recursion
7206  result.m_data->Attach( this );
7207  DetachFromData();
7208  m_data = result.m_data;
7209  }
7210  ResetSelections();
7211  return *this;
7212  }
7213 
7214  if ( !IsShared() )
7215  if ( !image.IsShared() )
7216  if ( completeSelection )
7217  {
7218  image.m_data->Attach( this );
7219  DetachFromData();
7220  m_data = image.m_data;
7221  ResetSelections();
7222  return *this;
7223  }
7224 
7225 #undef completeSelection
7226 
7227  int n = 1 + lastChannel - firstChannel;
7228  AllocateData( r, n, (firstChannel == 0 && n >= ColorSpace::NumberOfNominalChannels( image.ColorSpace() )) ?
7229  image.ColorSpace() : ColorSpace::Gray );
7230 
7231  if ( !IsShared() ) // ### cannot modify a shared image's RGBWS
7232  m_RGBWS = image.m_RGBWS;
7233 
7234  ResetSelections();
7235 
7236  if ( r == image.Bounds() )
7237  for ( int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7238  P::Copy( m_channelData( c ), image[firstChannel], NumberOfPixels() );
7239  else
7240  for ( int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7241  {
7242  sample* f = m_channelData( c );
7243  const sample* g = image.PixelAddress( r.LeftTop(), firstChannel );
7244  for ( int y = 0; y < m_height; ++y, f += m_width, g += image.m_width )
7245  P::Copy( f, g, m_width );
7246  }
7247 
7248  return *this;
7249  }
7250 
7257  template <class P1>
7258  GenericImage& operator =( const GenericImage<P1>& image )
7259  {
7260  return Assign( image );
7261  }
7262 
7273  GenericImage& operator =( const GenericImage& image )
7274  {
7275  return Assign( image );
7276  }
7277 
7278 #define TRANSFER_BODY() \
7279  if ( m_data != image.m_data ) \
7280  { \
7281  DetachFromData(); \
7282  m_data = image.m_data; \
7283  (void)AbstractImage::operator =( image ); \
7284  image.m_data = nullptr; \
7285  } \
7286  return *this
7287 
7300  {
7301  TRANSFER_BODY();
7302  }
7303 
7316  {
7317  TRANSFER_BODY();
7318  }
7319 
7320 #undef TRANSFER_BODY
7321 
7327  GenericImage& operator =( GenericImage&& image )
7328  {
7329  return Transfer( image );
7330  }
7331 
7338  GenericImage& operator =( sample scalar )
7339  {
7340  return Fill( scalar );
7341  }
7342 
7346  friend void Swap( GenericImage& x1, GenericImage& x2 ) noexcept
7347  {
7348  x1.AbstractImage::Swap( x2 );
7349  pcl::Swap( x1.m_data, x2.m_data );
7350  }
7351 
7352  // -------------------------------------------------------------------------
7353 
7354 #ifndef __PCL_NO_VECTOR_IMAGE_CONVERSION
7355 
7374  sample_vector RowVector( int y, int channel = -1 ) const
7375  {
7376  if ( channel < 0 )
7377  channel = m_channel;
7378  if ( y < 0 || y >= m_height || channel < 0 || channel >= m_numberOfChannels )
7379  return sample_vector();
7380  sample_vector row( m_width );
7381  P::Get( row.Begin(), ScanLine( y, channel ), m_width );
7382  return row;
7383  }
7384 
7403  sample_vector ColumnVector( int x, int channel = -1 ) const
7404  {
7405  if ( channel < 0 )
7406  channel = m_channel;
7407  if ( x < 0 || x >= m_width || channel < 0 || channel >= m_numberOfChannels )
7408  return sample_vector();
7409  sample_vector col( m_height );
7410  const sample* v = PixelAddress( x, 0, channel );
7411  for ( int y = 0; y < m_height; ++y, v += m_width )
7412  col[y] = *v;
7413  return col;
7414  }
7415 
7419  sample_vector ColVector( int x, int channel = 0 ) const
7420  {
7421  return ColumnVector( x, channel );
7422  }
7423 
7424 #endif // !__PCL_NO_VECTOR_IMAGE_CONVERSION
7425 
7447  template <typename T>
7448  void GetRow( T* buffer, int y, int channel = -1 ) const
7449  {
7450  PCL_PRECONDITION( buffer != 0 )
7451  if ( channel < 0 )
7452  channel = m_channel;
7453  if ( y >= 0 && y < m_height && channel >= 0 && channel < m_numberOfChannels )
7454  P::Get( buffer, ScanLine( y, channel ), m_width );
7455  }
7456 
7478  template <typename T>
7479  void GetColumn( T* buffer, int x, int channel = -1 ) const
7480  {
7481  PCL_PRECONDITION( buffer != 0 )
7482  if ( channel < 0 )
7483  channel = m_channel;
7484  if ( x >= 0 && x < m_width && channel >= 0 && channel < m_numberOfChannels )
7485  {
7486  const sample* v = PixelAddress( x, 0, channel );
7487  for ( int y = 0; y < m_height; ++y, ++buffer, v += m_width )
7488  P::FromSample( *buffer, *v );
7489  }
7490  }
7491 
7513  template <typename T>
7514  GenericImage& SetRow( const T* buffer, int y, int channel = -1 )
7515  {
7516  PCL_PRECONDITION( buffer != 0 )
7517  if ( channel < 0 )
7518  channel = m_channel;
7519  if ( y >= 0 && y < m_height && channel >= 0 && channel < m_numberOfChannels )
7520  P::Copy( ScanLine( y, channel ), buffer, m_width );
7521  return *this;
7522  }
7523 
7545  template <typename T>
7546  GenericImage& SetColumn( const T* buffer, int x, int channel = -1 )
7547  {
7548  PCL_PRECONDITION( buffer != 0 )
7549  if ( channel < 0 )
7550  channel = m_channel;
7551  if ( x >= 0 && x < m_width && channel >= 0 && channel < m_numberOfChannels )
7552  {
7553  sample* v = PixelAddress( x, 0, channel );
7554  for ( int y = 0; y < m_height; ++y, ++buffer, v += m_width )
7555  *v = P::ToSample( *buffer );
7556  }
7557  return *this;
7558  }
7559 
7560  // -------------------------------------------------------------------------
7561 
7572  {
7573  if ( n > 0 && m_numberOfChannels > 0 )
7574  {
7575  EnsureUnique();
7576  sample** oldData = m_pixelData;
7577  sample** newData = nullptr;
7578  try
7579  {
7580  newData = m_allocator.AllocateChannelSlots( m_numberOfChannels+n );
7581  for ( int i = 0; i < m_numberOfChannels; ++i )
7582  newData[i] = oldData[i];
7583  for ( int i = 0; i < n; ++i )
7584  newData[m_numberOfChannels+i] = m_allocator.AllocatePixels( m_width, m_height );
7585  }
7586  catch ( ... )
7587  {
7588  if ( newData != nullptr )
7589  {
7590  for ( int i = 0; i < n; ++i )
7591  if ( newData[m_numberOfChannels+i] != nullptr )
7592  m_allocator.Deallocate( newData[m_numberOfChannels+i] );
7593  m_allocator.Deallocate( newData );
7594  }
7595  throw;
7596  }
7597 
7598  m_allocator.SetSharedData( m_pixelData = newData );
7599  m_allocator.SetSharedGeometry( m_width, m_height, m_numberOfChannels += n );
7600  m_allocator.Deallocate( oldData );
7601  }
7602 
7603  return *this;
7604  }
7605 
7621  {
7622  // $$$ WARNING $$$
7623  // * If this is a shared image, data must either be null or point to a
7624  // shared memory block.
7625  // * If this is a local image, data must either be null or point to a
7626  // block allocated in the local heap.
7627 
7628  if ( data == nullptr )
7629  CreateAlphaChannels( 1 );
7630  else if ( m_numberOfChannels > 0 )
7631  {
7632  EnsureUnique();
7633  sample** oldData = m_pixelData;
7634  sample** newData = nullptr;
7635  try
7636  {
7637  newData = m_allocator.AllocateChannelSlots( m_numberOfChannels+1 );
7638  for ( int i = 0; i < m_numberOfChannels; ++i )
7639  newData[i] = oldData[i];
7640  newData[m_numberOfChannels] = data;
7641  }
7642  catch ( ... )
7643  {
7644  if ( newData != nullptr )
7645  m_allocator.Deallocate( newData );
7646  throw;
7647  }
7648 
7649  m_allocator.SetSharedData( m_pixelData = newData );
7650  m_allocator.SetSharedGeometry( m_width, m_height, ++m_numberOfChannels );
7651  m_allocator.Deallocate( oldData );
7652  }
7653 
7654  return *this;
7655  }
7656 
7680  {
7681  if ( IsShared() != image.IsShared() )
7682  throw Error( "GenericImage::ReleaseAlphaChannel(): Cannot release pixel data between local and shared images" );
7683 
7684  if ( channel < 0 || channel >= NumberOfAlphaChannels() )
7685  {
7686  image.FreeData();
7687  return *this;
7688  }
7689 
7690  int c = NumberOfNominalChannels() + channel;
7691 
7692  sample** newData = nullptr;
7693  try
7694  {
7695  newData = image.m_allocator.AllocateChannelSlots( 1 );
7696  *newData = m_pixelData[c];
7697  }
7698  catch ( ... )
7699  {
7700  if ( newData != nullptr )
7701  image.m_allocator.Deallocate( newData );
7702  throw;
7703  }
7704 
7705  image.FreeData();
7706 
7707  image.m_pixelData = newData;
7708  image.m_width = m_width;
7709  image.m_height = m_height;
7710  image.m_numberOfChannels = 1;
7711  image.m_colorSpace = ColorSpace::Gray;
7712  image.m_data->UpdateSharedImage();
7713  image.ResetSelections();
7714 
7715  m_pixelData[c] = nullptr;
7716  ForgetAlphaChannel( channel );
7717 
7718  return *this;
7719  }
7720 
7733  {
7734  if ( channel >= 0 && channel < NumberOfAlphaChannels() )
7735  {
7736  EnsureUnique();
7737  int c = NumberOfNominalChannels() + channel;
7738  m_allocator.Deallocate( m_pixelData[c] );
7739  m_pixelData[c] = nullptr;
7740  ForgetAlphaChannel( channel );
7741  }
7742 
7743  return *this;
7744  }
7745 
7763  {
7764  if ( channel >= 0 && channel < NumberOfAlphaChannels() )
7765  {
7766  EnsureUnique();
7767  sample** oldData = m_pixelData;
7768  sample** newData = m_allocator.AllocateChannelSlots( m_numberOfChannels-1 );
7769 
7770  int n0 = NumberOfNominalChannels();
7771  int c = n0 + channel;
7772 
7773  for ( int i = 0; i < c; ++i )
7774  newData[i] = oldData[i];
7775  for ( int i = c, j = c; ++j < m_numberOfChannels; ++i )
7776  newData[i] = oldData[j];
7777 
7778  m_allocator.SetSharedData( m_pixelData = newData );
7779  m_allocator.SetSharedGeometry( m_width, m_height, --m_numberOfChannels );
7780 
7781  if ( m_channel >= n0 || m_lastChannel >= n0 )
7782  ResetChannelRange();
7783 
7784  m_allocator.Deallocate( oldData );
7785  }
7786 
7787  return *this;
7788  }
7789 
7795  {
7796  int n0 = NumberOfNominalChannels();
7797  int n = m_numberOfChannels;
7798  if ( n > n0 )
7799  {
7800  EnsureUnique();
7801  do
7802  m_allocator.Deallocate( m_pixelData[--n] ), m_pixelData[n] = nullptr;
7803  while ( n > n0 );
7804  ForgetAlphaChannels();
7805  }
7806 
7807  return *this;
7808  }
7809 
7819  {
7820  int n0 = NumberOfNominalChannels();
7821  if ( m_numberOfChannels > n0 )
7822  {
7823  EnsureUnique();
7824  sample** oldData = m_pixelData;
7825  sample** newData = m_allocator.AllocateChannelSlots( n0 );
7826 
7827  for ( int i = 0; i < n0; ++i )
7828  newData[i] = oldData[i];
7829 
7830  m_allocator.SetSharedData( m_pixelData = newData );
7831  m_allocator.SetSharedGeometry( m_width, m_height, m_numberOfChannels = n0 );
7832 
7833  if ( m_channel >= n0 || m_lastChannel >= n0 )
7834  ResetChannelRange();
7835 
7836  m_allocator.Deallocate( oldData );
7837  }
7838 
7839  return *this;
7840  }
7841 
7842  // -------------------------------------------------------------------------
7843 
7880  template <typename T>
7881  GenericImage& Fill( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
7882  {
7883  Rect r = rect;
7884  if ( !ParseSelection( r, firstChannel, lastChannel ) )
7885  return *this;
7886 
7887  EnsureUnique();
7888 
7889  size_type N = size_type( r.Width() )*size_type( r.Height() );
7890  if ( m_status.IsInitializationEnabled() )
7891  m_status.Initialize( "Filling image", N*(1 + lastChannel - firstChannel) );
7892 
7893  sample v = P::ToSample( scalar );
7894 
7895  if ( r == Bounds() )
7896  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
7897  P::Fill( m_pixelData[i], v, N );
7898  else
7899  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
7900  {
7901  sample* __restrict__ f = PixelAddress( r.LeftTop(), i );
7902  PCL_IVDEP
7903  for ( int j = 0; j < h; ++j, f += m_width )
7904  P::Fill( f, v, w );
7905  }
7906 
7907  return *this;
7908  }
7909 
7927  template <typename T>
7929  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
7930  {
7931  Rect r = rect;
7932  if ( !ParseSelection( r, firstChannel, lastChannel ) )
7933  return *this;
7934 
7935  EnsureUnique();
7936 
7937  size_type N = size_type( r.Width() )*size_type( r.Height() );
7938  if ( m_status.IsInitializationEnabled() )
7939  m_status.Initialize( "Filling image", N*(1 + lastChannel - firstChannel) );
7940 
7941  if ( r == Bounds() )
7942  for ( int i = firstChannel, c = 0; i <= lastChannel; ++i, ++c, m_status += N )
7943  {
7944  sample v = (c < values.Length()) ? P::ToSample( values[c] ) : P::MinSampleValue();
7945  P::Fill( m_pixelData[i], v, N );
7946  }
7947  else
7948  for ( int i = firstChannel, c = 0, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, ++c, m_status += N )
7949  {
7950  sample* __restrict__ f = PixelAddress( r.LeftTop(), i );
7951  sample v = (c < values.Length()) ? P::ToSample( values[c] ) : P::MinSampleValue();
7952  PCL_IVDEP
7953  for ( int j = 0; j < h; ++j, f += m_width )
7954  P::Fill( f, v, w );
7955  }
7956 
7957  return *this;
7958  }
7959 
7970  template <typename T>
7971  GenericImage Filled( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
7972  {
7973  GenericImage result( *this, rect, firstChannel, lastChannel );
7974  (void)result.Fill( scalar );
7975  return result;
7976  }
7977 
7989  template <typename T>
7991  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
7992  {
7993  GenericImage result( *this, rect, firstChannel, lastChannel );
7994  (void)result.Fill( values );
7995  return result;
7996  }
7997 
8012  GenericImage& Zero( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8013  {
8014  return Fill( P::ToSample( 0.0 ), rect, firstChannel, lastChannel );
8015  }
8016 
8031  GenericImage& One( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8032  {
8033  return Fill( P::ToSample( 1.0 ), rect, firstChannel, lastChannel );
8034  }
8035 
8049  GenericImage& Black( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8050  {
8051  return Fill( P::MinSampleValue(), rect, firstChannel, lastChannel );
8052  }
8053 
8067  GenericImage& White( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8068  {
8069  return Fill( P::MaxSampleValue(), rect, firstChannel, lastChannel );
8070  }
8071 
8072  // -------------------------------------------------------------------------
8073 
8088  template <typename T>
8089  GenericImage& Invert( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8090  {
8091  Rect r = rect;
8092  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8093  return *this;
8094 
8095  EnsureUnique();
8096 
8097  size_type N = size_type( r.Width() )*size_type( r.Height() );
8098  if ( m_status.IsInitializationEnabled() )
8099  m_status.Initialize( "Inverting pixel samples", N*(1 + lastChannel - firstChannel) );
8100 
8101  sample v = P::ToSample( scalar );
8102  if ( r == Bounds() )
8103  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8104  {
8105  sample* __restrict__ f = m_pixelData[i];
8106  PCL_IVDEP
8107  for ( size_type j = 0; j < N; ++j, ++f )
8108  *f = v - *f;
8109  }
8110  else
8111  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8112  {
8113  sample* __restrict__ f = PixelAddress( r.LeftTop(), i );
8114  PCL_IVDEP
8115  for ( int j = 0; j < h; ++j, f += m_width-w )
8116  {
8117  PCL_IVDEP
8118  for ( int k = 0; k < w; ++k, ++f )
8119  *f = v - *f;
8120  }
8121  }
8122 
8123  return *this;
8124  }
8125 
8136  template <typename T>
8137  GenericImage Inverted( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8138  {
8139  GenericImage result( *this, rect, firstChannel, lastChannel );
8140  (void)result.Invert( scalar );
8141  return result;
8142  }
8143 
8161  GenericImage& Invert( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8162  {
8163  return Invert( P::MaxSampleValue(), rect, firstChannel, lastChannel );
8164  }
8165 
8177  GenericImage Inverted( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8178  {
8179  GenericImage result( *this, rect, firstChannel, lastChannel );
8180  (void)result.Invert();
8181  return result;
8182  }
8183 
8192  GenericImage operator ~() const
8193  {
8194  GenericImage result( *this );
8195  (void)result.Invert();
8196  return result;
8197  }
8198 
8209  GenericImage& Not( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8210  {
8211  Rect r = rect;
8212  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8213  return *this;
8214 
8215  EnsureUnique();
8216 
8217  size_type N = size_type( r.Width() )*size_type( r.Height() );
8218  if ( m_status.IsInitializationEnabled() )
8219  m_status.Initialize( "Bitwise Not", N*(1 + lastChannel - firstChannel) );
8220 
8221  if ( r == Bounds() )
8222  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8223  {
8224  sample* __restrict__ f = m_pixelData[i];
8225  PCL_IVDEP
8226  for ( size_type j = 0; j < N; ++j, ++f )
8227  P::Not( *f );
8228  }
8229  else
8230  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8231  {
8232  sample* __restrict__ f = PixelAddress( r.LeftTop(), i );
8233  PCL_IVDEP
8234  for ( int j = 0; j < h; ++j, f += m_width-w )
8235  {
8236  PCL_IVDEP
8237  for ( int k = 0; k < w; ++k, ++f )
8238  P::Not( *f );
8239  }
8240  }
8241 
8242  return *this;
8243  }
8244 
8261  template <typename T>
8262  GenericImage& Truncate( T lowerBound, T upperBound,
8263  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8264  {
8265  Rect r = rect;
8266  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8267  return *this;
8268 
8269  EnsureUnique();
8270 
8271  size_type N = size_type( r.Width() )*size_type( r.Height() );
8272  if ( m_status.IsInitializationEnabled() )
8273  m_status.Initialize( "Truncating pixel samples", N*(1 + lastChannel - firstChannel) );
8274 
8275  sample b0 = P::ToSample( lowerBound );
8276  sample b1 = P::ToSample( upperBound );
8277  if ( b1 < b0 )
8278  pcl::Swap( b0, b1 );
8279 
8280  if ( r == Bounds() )
8281  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8282  {
8283  sample* __restrict__ f = m_pixelData[i];
8284  PCL_IVDEP
8285  for ( size_type j = 0; j < N; ++j, ++f )
8286  if ( *f < b0 )
8287  *f = b0;
8288  else if ( b1 < *f )
8289  *f = b1;
8290  }
8291  else
8292  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8293  {
8294  sample* __restrict__ f = PixelAddress( r.LeftTop(), i );
8295  PCL_IVDEP
8296  for ( int j = 0; j < h; ++j, f += m_width-w )
8297  {
8298  PCL_IVDEP
8299  for ( int k = 0; k < w; ++k, ++f )
8300  if ( *f < b0 )
8301  *f = b0;
8302  else if ( b1 < *f )
8303  *f = b1;
8304  }
8305  }
8306 
8307  return *this;
8308  }
8309 
8323  template <typename T>
8324  GenericImage Truncated( T lowerBound, T upperBound,
8325  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8326  {
8327  GenericImage result( *this, rect, firstChannel, lastChannel );
8328  (void)result.Truncate( lowerBound, upperBound );
8329  return result;
8330  }
8331 
8353  GenericImage& Truncate( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8354  {
8355  return Truncate( P::MinSampleValue(), P::MaxSampleValue(), rect, firstChannel, lastChannel );
8356  }
8357 
8368  GenericImage Truncated( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8369  {
8370  GenericImage result( *this, rect, firstChannel, lastChannel );
8371  (void)result.Truncate();
8372  return result;
8373  }
8374 
8403  template <typename T>
8404  GenericImage& Rescale( T lowerBound, T upperBound,
8405  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8406  {
8407  Rect r = rect;
8408  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8409  return *this;
8410 
8411  size_type N = size_type( r.Width() )*size_type( r.Height() );
8412  size_type Ns = N*(1 + lastChannel - firstChannel);
8413  if ( m_status.IsInitializationEnabled() )
8414  m_status.Initialize( "Rescaling pixel samples", Ns );
8415 
8416  sample b0 = P::ToSample( lowerBound );
8417  sample b1 = P::ToSample( upperBound );
8418  if ( b1 < b0 )
8419  pcl::Swap( b0, b1 );
8420 
8421  sample v0, v1;
8422  GetExtremePixelValues( v0, v1, r, firstChannel, lastChannel );
8423  if ( v0 == b0 && v1 == b1 )
8424  {
8425  m_status += Ns;
8426  return *this;
8427  }
8428 
8429  EnsureUnique();
8430 
8431  double d = 0;
8432  if ( b0 != b1 )
8433  if ( v0 != v1 )
8434  d = (double( b1 ) - double( b0 ))/(double( v1 ) - double( v0 ));
8435 
8436  if ( r == Bounds() )
8437  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8438  {
8439  sample* __restrict__ f = m_pixelData[i];
8440 
8441  if ( v0 != v1 )
8442  {
8443  if ( b0 != b1 )
8444  {
8445  if ( b0 == sample( 0 ) )
8446  {
8447  PCL_IVDEP
8448  for ( size_type j = 0; j < N; ++j, ++f )
8449  *f = P::FloatToSample( d*(*f - v0) );
8450  }
8451  else
8452  {
8453  PCL_IVDEP
8454  for ( size_type j = 0; j < N; ++j, ++f )
8455  *f = P::FloatToSample( d*(*f - v0) + b0 );
8456  }
8457  }
8458  else
8459  P::Fill( f, b0, N );
8460  }
8461  else
8462  P::Fill( f, pcl::Range( v0, b0, b1 ), N );
8463  }
8464  else
8465  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8466  {
8467  sample* __restrict__ f = PixelAddress( r.LeftTop(), i );
8468 
8469  if ( v0 != v1 )
8470  {
8471  if ( b0 != b1 )
8472  {
8473  if ( b0 == sample( 0 ) )
8474  {
8475  PCL_IVDEP
8476  for ( int j = 0; j < h; ++j, f += m_width-w )
8477  {
8478  PCL_IVDEP
8479  for ( int k = 0; k < w; ++k, ++f )
8480  *f = P::FloatToSample( d*(*f - v0) );
8481  }
8482  }
8483  else
8484  {
8485  PCL_IVDEP
8486  for ( int j = 0; j < h; ++j, f += m_width-w )
8487  {
8488  PCL_IVDEP
8489  for ( int k = 0; k < w; ++k, ++f )
8490  *f = P::FloatToSample( d*(*f - v0) + b0 );
8491  }
8492  }
8493  }
8494  else
8495  {
8496  PCL_IVDEP
8497  for ( int j = 0; j < h; ++j, f += m_width )
8498  P::Fill( f, b0, w );
8499  }
8500  }
8501  else
8502  {
8503  sample v = pcl::Range( v0, b0, b1 );
8504  PCL_IVDEP
8505  for ( int j = 0; j < h; ++j, f += m_width )
8506  P::Fill( f, v, w );
8507  }
8508  }
8509 
8510  return *this;
8511  }
8512 
8526  template <typename T>
8527  GenericImage Rescaled( T lowerBound, T upperBound,
8528  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8529  {
8530  GenericImage result( *this, rect, firstChannel, lastChannel );
8531  (void)result.Rescale( lowerBound, upperBound );
8532  return result;
8533  }
8534 
8551  GenericImage& Rescale( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8552  {
8553  return Rescale( P::MinSampleValue(), P::MaxSampleValue(), rect, firstChannel, lastChannel );
8554  }
8555 
8566  GenericImage Rescaled( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8567  {
8568  GenericImage result( *this, rect, firstChannel, lastChannel );
8569  (void)result.Rescale();
8570  return result;
8571  }
8572 
8607  template <typename T>
8608  GenericImage& Normalize( T lowerBound, T upperBound,
8609  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8610  {
8611  Rect r = rect;
8612  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8613  return *this;
8614 
8615  size_type N = size_type( r.Width() )*size_type( r.Height() );
8616  size_type Ns = N*(1 + lastChannel - firstChannel);
8617  if ( m_status.IsInitializationEnabled() )
8618  m_status.Initialize( "Normalizing pixel samples", Ns );
8619 
8620  sample b0 = P::ToSample( lowerBound );
8621  sample b1 = P::ToSample( upperBound );
8622  if ( b1 < b0 )
8623  pcl::Swap( b0, b1 );
8624 
8625  sample v0, v1;
8626  GetExtremePixelValues( v0, v1, r, firstChannel, lastChannel );
8627 
8628  if ( v0 >= b0 && v1 <= b1 )
8629  {
8630  m_status += Ns;
8631  return *this;
8632  }
8633 
8634  EnsureUnique();
8635 
8636  double d = 0;
8637  if ( b0 != b1 )
8638  if ( v0 != v1 )
8639  d = (double( b1 ) - double( b0 ))/(double( v1 ) - double( v0 ));
8640 
8641  if ( r == Bounds() )
8642  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8643  {
8644  sample* __restrict__ f = m_pixelData[i];
8645 
8646  if ( v0 != v1 )
8647  {
8648  if ( b0 != b1 )
8649  {
8650  if ( b0 == sample( 0 ) )
8651  {
8652  PCL_IVDEP
8653  for ( size_type j = 0; j < N; ++j, ++f )
8654  *f = P::FloatToSample( d*(*f - v0) );
8655  }
8656  else
8657  {
8658  PCL_IVDEP
8659  for ( size_type j = 0; j < N; ++j, ++f )
8660  *f = P::FloatToSample( d*(*f - v0) + b0 );
8661  }
8662  }
8663  else
8664  P::Fill( f, b0, N );
8665  }
8666  else
8667  P::Fill( f, pcl::Range( v0, b0, b1 ), N );
8668  }
8669  else
8670  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8671  {
8672  sample* __restrict__ f = PixelAddress( r.LeftTop(), i );
8673 
8674  if ( v0 != v1 )
8675  {
8676  if ( b0 != b1 )
8677  {
8678  if ( b0 == sample( 0 ) )
8679  {
8680  PCL_IVDEP
8681  for ( int j = 0; j < h; ++j, f += m_width-w )
8682  {
8683  PCL_IVDEP
8684  for ( int k = 0; k < w; ++k, ++f )
8685  *f = P::FloatToSample( d*(*f - v0) );
8686  }
8687  }
8688  else
8689  {
8690  PCL_IVDEP
8691  for ( int j = 0; j < h; ++j, f += m_width-w )
8692  {
8693  PCL_IVDEP
8694  for ( int k = 0; k < w; ++k, ++f )
8695  *f = P::FloatToSample( d*(*f - v0) + b0 );
8696  }
8697  }
8698  }
8699  else
8700  {
8701  PCL_IVDEP
8702  for ( int j = 0; j < h; ++j, f += m_width )
8703  P::Fill( f, b0, w );
8704  }
8705  }
8706  else
8707  {
8708  sample v = pcl::Range( v0, b0, b1 );
8709  PCL_IVDEP
8710  for ( int j = 0; j < h; ++j, f += m_width )
8711  P::Fill( f, v, w );
8712  }
8713  }
8714 
8715  return *this;
8716  }
8717 
8731  template <typename T>
8732  GenericImage Normalized( T lowerBound, T upperBound,
8733  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8734  {
8735  GenericImage result( *this, rect, firstChannel, lastChannel );
8736  (void)result.Normalize( lowerBound, upperBound );
8737  return result;
8738  }
8739 
8756  GenericImage& Normalize( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8757  {
8758  return Normalize( P::MinSampleValue(), P::MaxSampleValue(), rect, firstChannel, lastChannel );
8759  }
8760 
8771  GenericImage Normalized( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8772  {
8773  GenericImage result( *this, rect, firstChannel, lastChannel );
8774  (void)result.Normalize();
8775  return result;
8776  }
8777 
8807  template <typename T>
8808  GenericImage& Binarize( T threshold,
8809  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8810  {
8811  Rect r = rect;
8812  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8813  return *this;
8814 
8815  EnsureUnique();
8816 
8817  size_type N = size_type( r.Width() )*size_type( r.Height() );
8818  if ( m_status.IsInitializationEnabled() )
8819  m_status.Initialize( "Binarizing pixel samples", N*(1 + lastChannel - firstChannel) );
8820 
8821  sample t = P::ToSample( threshold );
8822 
8823  if ( r == Bounds() )
8824  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8825  {
8826  sample* __restrict__ f = m_pixelData[i];
8827  PCL_IVDEP
8828  for ( size_type j = 0; j < N; ++j, ++f )
8829  *f = (*f < t) ? P::MinSampleValue() : P::MaxSampleValue();
8830  }
8831  else
8832  for ( int c = firstChannel, w = r.Width(), h = r.Height(); c <= lastChannel; ++c, m_status += N )
8833  {
8834  sample* __restrict__ f = PixelAddress( r.LeftTop(), c );
8835  PCL_IVDEP
8836  for ( int j = 0; j < h; ++j, f += m_width-w )
8837  {
8838  PCL_IVDEP
8839  for ( int k = 0; k < w; ++k, ++f )
8840  *f = (*f < t) ? P::MinSampleValue() : P::MaxSampleValue();
8841  }
8842  }
8843 
8844  return *this;
8845  }
8846 
8857  template <typename T>
8858  GenericImage Binarized( T threshold,
8859  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8860  {
8861  GenericImage result( *this, rect, firstChannel, lastChannel );
8862  (void)result.Binarize( threshold );
8863  return result;
8864  }
8865 
8882  GenericImage& Binarize( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8883  {
8884  return Binarize( (P::MinSampleValue() + P::MaxSampleValue())/2, rect, firstChannel, lastChannel );
8885  }
8886 
8898  GenericImage Binarized( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8899  {
8900  GenericImage result( *this, rect, firstChannel, lastChannel );
8901  (void)result.Binarize();
8902  return result;
8903  }
8904 
8918  GenericImage& SetAbsoluteValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8919  {
8920  Rect r = rect;
8921  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8922  return *this;
8923 
8924  EnsureUnique();
8925 
8926  size_type N = size_type( r.Width() )*size_type( r.Height() );
8927  if ( m_status.IsInitializationEnabled() )
8928  m_status.Initialize( "Computing absolute value", N*(1 + lastChannel - firstChannel) );
8929 
8930  if ( r == Bounds() )
8931  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8932  {
8933  sample* __restrict__ f = m_pixelData[i];
8934  PCL_IVDEP
8935  for ( size_type j = 0; j < N; ++j, ++f )
8936  *f = pcl::Abs( *f );
8937  }
8938  else
8939  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8940  {
8941  sample* __restrict__ f = PixelAddress( r.LeftTop(), i );
8942  PCL_IVDEP
8943  for ( int j = 0; j < h; ++j, f += m_width-w )
8944  {
8945  PCL_IVDEP
8946  for ( int k = 0; k < w; ++k, ++f )
8947  *f = pcl::Abs( *f );
8948  }
8949  }
8950 
8951  return *this;
8952  }
8953 
8957  GenericImage& Abs( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8958  {
8959  return SetAbsoluteValue( rect, firstChannel, lastChannel );
8960  }
8961 
8972  GenericImage AbsoluteValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8973  {
8974  GenericImage result( *this, rect, firstChannel, lastChannel );
8975  (void)result.SetAbsoluteValue();
8976  return result;
8977  }
8978 
8979  // -------------------------------------------------------------------------
8980 
8981  /*
8982  * Implementation of Apply( scalar ) member functions. We have to have a
8983  * separate implementation function to prevent infinite recursion in several
8984  * template specializations of the Apply() member function.
8985  */
8986  template <typename T>
8987  GenericImage& ApplyScalar( T scalar, image_op op = ImageOp::Mov,
8988  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8989  {
8990  if ( op == ImageOp::Div )
8991  if ( 1 + scalar == 1 )
8992  throw Error( "Division by zero or insignificant scalar" );
8993 
8994  Rect r = rect;
8995  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8996  return *this;
8997 
8998  EnsureUnique();
8999 
9000  size_type N = size_type( r.Width() )*size_type( r.Height() );
9001  if ( m_status.IsInitializationEnabled() )
9002  m_status.Initialize( "Applying scalar: "
9003  + ImageOp::Id( op )
9004  + ' ' + String( scalar ), N*(1 + lastChannel - firstChannel) );
9005 
9006  if ( r == Bounds() )
9007  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
9008  {
9009  sample* __restrict__ f = m_pixelData[i];
9010 #define ITERATE( Op ) \
9011  PCL_IVDEP \
9012  for ( size_type j = 0; j < N; ++j, ++f ) \
9013  P::Op( *f, scalar )
9014  switch ( op )
9015  {
9016  case ImageOp::Mov: ITERATE( Mov ); break;
9017  case ImageOp::Add: ITERATE( Add ); break;
9018  case ImageOp::Sub: ITERATE( Sub ); break;
9019  case ImageOp::Mul: ITERATE( Mul ); break;
9020  case ImageOp::Div: ITERATE( Div ); break;
9021  case ImageOp::Pow: ITERATE( Pow ); break;
9022  case ImageOp::Dif: ITERATE( Dif ); break;
9023  case ImageOp::Min: ITERATE( Min ); break;
9024  case ImageOp::Max: ITERATE( Max ); break;
9025  case ImageOp::Not: ITERATE( Not ); break;
9026  case ImageOp::Or: ITERATE( Or ); break;
9027  case ImageOp::Nor: ITERATE( Nor ); break;
9028  case ImageOp::And: ITERATE( And ); break;
9029  case ImageOp::Nand: ITERATE( Nand ); break;
9030  case ImageOp::Xor: ITERATE( Xor ); break;
9031  case ImageOp::Xnor: ITERATE( Xnor ); break;
9032  case ImageOp::ColorBurn: ITERATE( ColorBurn ); break;
9033  case ImageOp::LinearBurn: ITERATE( LinearBurn ); break;
9034  case ImageOp::Screen: ITERATE( Screen ); break;
9035  case ImageOp::ColorDodge: ITERATE( ColorDodge ); break;
9036  case ImageOp::Overlay: ITERATE( Overlay ); break;
9037  case ImageOp::SoftLight: ITERATE( SoftLight ); break;
9038  case ImageOp::HardLight: ITERATE( HardLight ); break;
9039  case ImageOp::VividLight: ITERATE( VividLight ); break;
9040  case ImageOp::LinearLight: ITERATE( LinearLight ); break;
9041  case ImageOp::PinLight: ITERATE( PinLight ); break;
9042  case ImageOp::Exclusion: ITERATE( Exclusion ); break;
9043  default: break;
9044  }
9045 #undef ITERATE
9046  }
9047  else
9048  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
9049  {
9050  sample* __restrict__ f = PixelAddress( r.LeftTop(), i );
9051 #define ITERATE( Op ) \
9052  PCL_IVDEP \
9053  for ( int j = 0; j < h; ++j, f += m_width-w ) \
9054  { \
9055  PCL_IVDEP \
9056  for ( int k = 0; k < w; ++k, ++f ) \
9057  P::Op( *f, scalar ); \
9058  }
9059  switch ( op )
9060  {
9061  case ImageOp::Mov: ITERATE( Mov ); break;
9062  case ImageOp::Add: ITERATE( Add ); break;
9063  case ImageOp::Sub: ITERATE( Sub ); break;
9064  case ImageOp::Mul: ITERATE( Mul ); break;
9065  case ImageOp::Div: ITERATE( Div ); break;
9066  case ImageOp::Pow: ITERATE( Pow ); break;
9067  case ImageOp::Dif: ITERATE( Dif ); break;
9068  case ImageOp::Min: ITERATE( Min ); break;
9069  case ImageOp::Max: ITERATE( Max ); break;
9070  case ImageOp::Not: ITERATE( Not ); break;
9071  case ImageOp::Or: ITERATE( Or ); break;
9072  case ImageOp::Nor: ITERATE( Nor ); break;
9073  case ImageOp::And: ITERATE( And ); break;
9074  case ImageOp::Nand: ITERATE( Nand ); break;
9075  case ImageOp::Xor: ITERATE( Xor ); break;
9076  case ImageOp::Xnor: ITERATE( Xnor ); break;
9077  case ImageOp::ColorBurn: ITERATE( ColorBurn ); break;
9078  case ImageOp::LinearBurn: ITERATE( LinearBurn ); break;
9079  case ImageOp::Screen: ITERATE( Screen ); break;
9080  case ImageOp::ColorDodge: ITERATE( ColorDodge ); break;
9081  case ImageOp::Overlay: ITERATE( Overlay ); break;
9082  case ImageOp::SoftLight: ITERATE( SoftLight ); break;
9083  case ImageOp::HardLight: ITERATE( HardLight ); break;
9084  case ImageOp::VividLight: ITERATE( VividLight ); break;
9085  case ImageOp::LinearLight: ITERATE( LinearLight ); break;
9086  case ImageOp::PinLight: ITERATE( PinLight ); break;
9087  case ImageOp::Exclusion: ITERATE( Exclusion ); break;
9088  default: break;
9089  }
9090 #undef ITERATE
9091  }
9092 
9093  return *this;
9094  }
9095 
9118  template <typename T>
9119  GenericImage& Apply( T scalar, image_op op = ImageOp::Mov,
9120  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9121  {
9122  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9123  }
9124 
9125  GenericImage& Apply( float scalar, image_op op = ImageOp::Mov,
9126  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9127  {
9129  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9130  return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9131  }
9132 
9133  GenericImage& Apply( double scalar, image_op op = ImageOp::Mov,
9134  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9135  {
9137  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9138  return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9139  }
9140 
9141  GenericImage& Apply( pcl::Complex<float> scalar, image_op op = ImageOp::Mov,
9142  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9143  {
9145  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9146  return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9147  }
9148 
9149  GenericImage& Apply( pcl::Complex<double> scalar, image_op op = ImageOp::Mov,
9150  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9151  {
9153  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9154  return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9155  }
9156 
9175  template <typename T>
9176  GenericImage Applied( T scalar, image_op op = ImageOp::Mov,
9177  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9178  {
9179  GenericImage result( *this, rect, firstChannel, lastChannel );
9180  (void)result.Apply( scalar, op );
9181  return result;
9182  }
9183 
9184  // -------------------------------------------------------------------------
9185 
9230  template <class P1>
9231  GenericImage& Apply( const GenericImage<P1>& image, image_op op = ImageOp::Mov,
9232  const Point& point = Point( int_max ), int channel = -1,
9233  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9234  {
9235  Rect r = rect;
9236  if ( !image.ParseSelection( r, firstChannel, lastChannel ) )
9237  return *this;
9238 
9239  if ( !ParseChannel( channel ) )
9240  return *this;
9241 
9242  Point p = point;
9243  if ( p.x == int_max || p.y == int_max )
9244  p = m_point;
9245 
9246  if ( p.x < 0 )
9247  {
9248  if ( (r.x0 -= p.x) >= r.x1 )
9249  return *this;
9250  p.x = 0;
9251  }
9252  else if ( p.x >= m_width )
9253  return *this;
9254 
9255  if ( p.y < 0 )
9256  {
9257  if ( (r.y0 -= p.y) >= r.y1 )
9258  return *this;
9259  p.y = 0;
9260  }
9261  else if ( p.y >= m_height )
9262  return *this;
9263 
9264  r.ResizeTo( pcl::Min( m_width - p.x, r.Width() ),
9265  pcl::Min( m_height - p.y, r.Height() ) );
9266 
9267  lastChannel = pcl::Min( lastChannel, firstChannel + m_numberOfChannels - channel - 1 );
9268 
9269  EnsureUnique();
9270 
9271  size_type N = size_type( r.Width() )*size_type( r.Height() );
9272  if ( m_status.IsInitializationEnabled() )
9273  m_status.Initialize( "Applying image, op=" + ImageOp::Id( op ), N*(1 + lastChannel - firstChannel) );
9274 
9275  if ( r == Bounds() && r == image.Bounds() )
9276  for ( int i = channel, j = firstChannel; j <= lastChannel; ++i, ++j, m_status += N )
9277  {
9278  sample* __restrict__ f = m_pixelData[i];
9279  const typename P1::sample* __restrict__ g = image[j];
9280 
9281 #define ITERATE( Op ) \
9282  PCL_IVDEP \
9283  for ( size_type k = 0; k < N; ++k, ++f, ++g ) \
9284  P::Op( *f, *g )
9285  switch ( op )
9286  {
9287  case ImageOp::Mov:
9288  P::Copy( f, g, N );
9289  break;
9290  case ImageOp::Min:
9291  P::CopyMin( f, g, N );
9292  break;
9293  case ImageOp::Max:
9294  P::CopyMax( f, g, N );
9295  break;
9296  default:
9297  switch ( op )
9298  {
9299  case ImageOp::Add: ITERATE( Add ); break;
9300  case ImageOp::Sub: ITERATE( Sub ); break;
9301  case ImageOp::Mul: ITERATE( Mul ); break;
9302  case ImageOp::Div:
9303  for ( size_type j = 0; j < N; ++j, ++f, ++g )
9304  if ( *g != 0 )
9305  P::Div( *f, *g );
9306  else
9307  *f = P::MaxSampleValue();
9308  break;
9309  case ImageOp::Pow: ITERATE( Pow ); break;
9310  case ImageOp::Dif: ITERATE( Dif ); break;
9311  case ImageOp::Not: ITERATE( Not ); break;
9312  case ImageOp::Or: ITERATE( Or ); break;
9313  case ImageOp::Nor: ITERATE( Nor ); break;
9314  case ImageOp::And: ITERATE( And ); break;
9315  case ImageOp::Nand: ITERATE( Nand ); break;
9316  case ImageOp::Xor: ITERATE( Xor ); break;
9317  case ImageOp::Xnor: ITERATE( Xnor ); break;
9318  case ImageOp::ColorBurn: ITERATE( ColorBurn ); break;
9319  case ImageOp::LinearBurn: ITERATE( LinearBurn ); break;
9320  case ImageOp::Screen: ITERATE( Screen ); break;
9321  case ImageOp::ColorDodge: ITERATE( ColorDodge ); break;
9322  case ImageOp::Overlay: ITERATE( Overlay ); break;
9323  case ImageOp::SoftLight: ITERATE( SoftLight ); break;
9324  case ImageOp::HardLight: ITERATE( HardLight ); break;
9325  case ImageOp::VividLight: ITERATE( VividLight ); break;
9326  case ImageOp::LinearLight: ITERATE( LinearLight ); break;
9327  case ImageOp::PinLight: ITERATE( PinLight ); break;
9328  case ImageOp::Exclusion: ITERATE( Exclusion ); break;
9329  default: break;
9330  }
9331 #undef ITERATE
9332  break;
9333  }
9334  }
9335  else
9336  for ( int i = channel, j = firstChannel, w = r.Width(), h = r.Height(); j <= lastChannel; ++i, ++j, m_status += N )
9337  {
9338  sample* __restrict__ f = PixelAddress( p, i );
9339  const typename P1::sample* __restrict__ g = image.PixelAddress( r.LeftTop(), j );
9340 
9341 #define ITERATE( Op ) \
9342  PCL_IVDEP \
9343  for ( int k = 0; k < h; ++k, f += m_width-w, g += image.Width()-w ) \
9344  { \
9345  PCL_IVDEP \
9346  for ( int l = 0; l < w; ++l, ++f, ++g ) \
9347  P::Op( *f, *g ); \
9348  }
9349  switch ( op )
9350  {
9351  case ImageOp::Mov:
9352  for ( int k = 0; k < h; ++k, f += m_width, g += image.Width() )
9353  P::Copy( f, g, w );
9354  break;
9355  case ImageOp::Min:
9356  for ( int k = 0; k < h; ++k, f += m_width, g += image.Width() )
9357  P::CopyMin( f, g, w );
9358  break;
9359  case ImageOp::Max:
9360  for ( int k = 0; k < h; ++k, f += m_width, g += image.Width() )
9361  P::CopyMax( f, g, w );
9362  break;
9363  case ImageOp::Add: ITERATE( Add ); break;
9364  case ImageOp::Sub: ITERATE( Sub ); break;
9365  case ImageOp::Mul: ITERATE( Mul ); break;
9366  case ImageOp::Div:
9367  PCL_IVDEP
9368  for ( int k = 0; k < h; ++k, f += m_width-w, g += image.Width()-w )
9369  {
9370  PCL_IVDEP
9371  for ( int l = 0; l < w; ++l, ++f, ++g )
9372  if ( *g != 0 )
9373  P::Div( *f, *g );
9374  else
9375  *f = P::MaxSampleValue();
9376  }
9377  break;
9378  case ImageOp::Pow: ITERATE( Pow ); break;
9379  case ImageOp::Dif: ITERATE( Dif ); break;
9380  case ImageOp::Not: ITERATE( Not ); break;
9381  case ImageOp::Or: ITERATE( Or ); break;
9382  case ImageOp::Nor: ITERATE( Nor ); break;
9383  case ImageOp::And: ITERATE( And ); break;
9384  case ImageOp::Nand: ITERATE( Nand ); break;
9385  case ImageOp::Xor: ITERATE( Xor ); break;
9386  case ImageOp::Xnor: ITERATE( Xnor ); break;
9387  case ImageOp::ColorBurn: ITERATE( ColorBurn ); break;
9388  case ImageOp::LinearBurn: ITERATE( LinearBurn ); break;
9389  case ImageOp::Screen: ITERATE( Screen ); break;
9390  case ImageOp::ColorDodge: ITERATE( ColorDodge ); break;
9391  case ImageOp::Overlay: ITERATE( Overlay ); break;
9392  case ImageOp::SoftLight: ITERATE( SoftLight ); break;
9393  case ImageOp::HardLight: ITERATE( HardLight ); break;
9394  case ImageOp::VividLight: ITERATE( VividLight ); break;
9395  case ImageOp::LinearLight: ITERATE( LinearLight ); break;
9396  case ImageOp::PinLight: ITERATE( PinLight ); break;
9397  case ImageOp::Exclusion: ITERATE( Exclusion ); break;
9398  break;
9399  default:
9400  break;
9401  }
9402 #undef ITERATE
9403  }
9404 
9405  return *this;
9406  }
9407 
9419  template <class P1>
9420  GenericImage Applied( const GenericImage<P1>& image, image_op op = ImageOp::Mov,
9421  const Point& point = Point( int_max ), int channel = -1,
9422  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9423  {
9424  int c0 = (channel < 0) ? m_channel : channel;
9425  int c1 = c0 + ((firstChannel < 0) ? image.FirstSelectedChannel() : firstChannel);
9426  int c2 = c0 + ((lastChannel < 0) ? image.LastSelectedChannel() : lastChannel);
9427  GenericImage result( *this, rect.MovedTo( point ), c1, c2 );
9428  (void)result.Apply( image, op, Point( 0 ), 0, rect, firstChannel, lastChannel );
9429  return result;
9430  }
9431 
9432  // -------------------------------------------------------------------------
9433 
9467  GenericImage& Apply( const ImageTransformation& transformation,
9468  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 );
9469  // ### Implemented in pcl/ImageTransformation.h (because of mutual dependencies)
9470 
9489  GenericImage Applied( const ImageTransformation& transformation,
9490  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9491  {
9492  GenericImage result( *this, rect, firstChannel, lastChannel );
9493  (void)result.Apply( transformation );
9494  return result;
9495  }
9496 
9518  void Transform( BidirectionalImageTransformation& transform,
9519  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const;
9520  // ### Implemented in pcl/ImageTransformation.h (because of mutual dependencies)
9521 
9522  // -------------------------------------------------------------------------
9523 
9524 #ifndef __PCL_IMAGE_NO_BITMAP
9525 
9567  GenericImage& Blend( const Bitmap& bitmap,
9568  const Point& point = Point( int_max ), const Rect& rect = Rect( 0 ) )
9569  {
9570  Rect r = rect;
9571  if ( r.IsRect() )
9572  r = bitmap.Bounds().Intersection( r );
9573  else
9574  r = bitmap.Bounds();
9575  if ( !r.IsRect() )
9576  return *this;
9577 
9578  Point p = point;
9579  if ( p.x == int_max || p.y == int_max )
9580  p = m_point;
9581 
9582  if ( p.x < 0 )
9583  {
9584  if ( (r.x0 -= p.x) >= r.x1 )
9585  return *this;
9586  p.x = 0;
9587  }
9588  else if ( p.x >= m_width )
9589  return *this;
9590 
9591  if ( p.y < 0 )
9592  {
9593  if ( (r.y0 -= p.y) >= r.y1 )
9594  return *this;
9595  p.y = 0;
9596  }
9597  else if ( p.y >= m_height )
9598  return *this;
9599 
9600  r.ResizeTo( pcl::Min( m_width - p.x, r.Width() ),
9601  pcl::Min( m_height - p.y, r.Height() ) );
9602 
9603  bool hasAlpha = HasAlphaChannels();
9604  int w = r.Width();
9605  int h = r.Height();
9606 
9607  EnsureUnique();
9608 
9609  if ( IsColor() )
9610  {
9611  if ( m_status.IsInitializationEnabled() )
9612  m_status.Initialize( "Blending RGBA bitmap", size_type( w )*size_type( h ) );
9613 
9614  sample* __restrict__ fR = nullptr;
9615  sample* __restrict__ fG = nullptr;
9616  sample* __restrict__ fB = nullptr;
9617  sample* __restrict__ fA = nullptr;
9618 
9619  for ( int i = 0; i < h; ++i, ++p.y, m_status += w )
9620  {
9621  fR = PixelAddress( p, 0 );
9622  fG = PixelAddress( p, 1 );
9623  fB = PixelAddress( p, 2 );
9624  if ( hasAlpha )
9625  fA = PixelAddress( p, 3 );
9626 
9627  const RGBA* __restrict__ g = bitmap.ScanLine( r.y0 + i ) + r.x0;
9628 
9629  for ( int j = 0; j < w; ++j, ++fR, ++fG, ++fB, ++fA, ++g )
9630  {
9631  RGBA rgba = *g;
9632 
9633  uint8 A = Alpha( rgba );
9634 
9635  if ( hasAlpha )
9636  {
9637  P::Mov( *fR, Red( rgba ) );
9638  P::Mov( *fG, Green( rgba ) );
9639  P::Mov( *fB, Blue( rgba ) );
9640  P::Mov( *fA, A );
9641  }
9642  else if ( A != 0 )
9643  {
9644  if ( A == 0xFF )
9645  {
9646  P::Mov( *fR, Red( rgba ) );
9647  P::Mov( *fG, Green( rgba ) );
9648  P::Mov( *fB, Blue( rgba ) );
9649  }
9650  else
9651  {
9652  double k = PTLUT->pDLUTA[A];
9653  double k1 = PTLUT->p1DLUT8[A];
9654  double v;
9655  P::FromSample( v, *fR ), P::Mov( *fR, k*Red( rgba ) + k1*v );
9656  P::FromSample( v, *fG ), P::Mov( *fG, k*Green( rgba ) + k1*v );
9657  P::FromSample( v, *fB ), P::Mov( *fB, k*Blue( rgba ) + k1*v );
9658  }
9659  }
9660  }
9661  }
9662  }
9663  else
9664  {
9665  if ( m_status.IsInitializationEnabled() )
9666  m_status.Initialize( "Blending grayscale bitmap", size_type( w )*size_type( h ) );
9667 
9668  sample* __restrict__ fK = nullptr;
9669  sample* __restrict__ fA = nullptr;
9670 
9671  for ( int i = 0; i < h; ++i, ++p.y, m_status += w )
9672  {
9673  fK = PixelAddress( p, 0 );
9674  if ( hasAlpha )
9675  fA = PixelAddress( p, 1 );
9676 
9677  const RGBA* __restrict__ g = bitmap.ScanLine( r.y0 + i ) + r.x0;
9678 
9679  for ( int j = 0; j < w; ++j, ++fK, ++fA, ++g )
9680  {
9681  RGBA rgba = *g;
9682  uint8 R = Red( rgba );
9683  uint8 G = Green( rgba );
9684  uint8 B = Blue( rgba );
9685  uint8 A = Alpha( rgba );
9686 
9687  double K = 0.5*(pcl::Min( pcl::Min( R, G ), B )
9688  + pcl::Max( pcl::Max( R, G ), B ));
9689 
9690  if ( hasAlpha )
9691  {
9692  P::Mov( *fK, K/255 );
9693  P::Mov( *fA, A );
9694  }
9695  else if ( A != 0 )
9696  {
9697  if ( A == 0xFF )
9698  P::Mov( *fK, K/255 );
9699  else
9700  {
9701  double v;
9702  P::FromSample( v, *fK );
9703  P::Mov( *fK, PTLUT->pDLUTA[A]*K + PTLUT->p1DLUT8[A]*v );
9704  }
9705  }
9706  }
9707  }
9708  }
9709 
9710  return *this;
9711  }
9712 
9724  GenericImage Blended( const Bitmap& bitmap,
9725  const Point& point = Point( int_max ), const Rect& rect = Rect( 0 ) ) const
9726  {
9727  GenericImage result( *this, Bounds(), 0, m_numberOfChannels-1 );
9728  (void)result.Blend( bitmap, point, rect );
9729  return result;
9730  }
9731 
9732 #endif // !__PCL_IMAGE_NO_BITMAP
9733 
9734  // -------------------------------------------------------------------------
9735 
9746  template <typename T>
9747  GenericImage& Move( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9748  {
9749  return Apply( scalar, ImageOp::Mov, rect, firstChannel, lastChannel );
9750  }
9751 
9755  template <typename T>
9756  GenericImage& Mov( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9757  {
9758  return Move( scalar, rect, firstChannel, lastChannel );
9759  }
9760 
9771  template <typename T>
9772  GenericImage& Add( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9773  {
9774  return Apply( scalar, ImageOp::Add, rect, firstChannel, lastChannel );
9775  }
9776 
9780  template <typename T>
9781  GenericImage& operator +=( T scalar )
9782  {
9783  return Add( scalar );
9784  }
9785 
9796  template <typename T>
9797  GenericImage Added( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9798  {
9799  GenericImage result( *this, rect, firstChannel, lastChannel );
9800  (void)result.Add( scalar );
9801  return result;
9802  }
9803 
9814  template <typename T>
9815  GenericImage& Subtract( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9816  {
9817  return Apply( scalar, ImageOp::Sub, rect, firstChannel, lastChannel );
9818  }
9819 
9823  template <typename T>
9824  GenericImage& Sub( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9825  {
9826  return Subtract( scalar, rect, firstChannel, lastChannel );
9827  }
9828 
9832  template <typename T>
9833  GenericImage& operator -=( T scalar )
9834  {
9835  return Subtract( scalar );
9836  }
9837 
9848  template <typename T>
9849  GenericImage Subtracted( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9850  {
9851  GenericImage result( *this, rect, firstChannel, lastChannel );
9852  (void)result.Subtract( scalar );
9853  return result;
9854  }
9855 
9866  template <typename T>
9867  GenericImage& Multiply( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9868  {
9869  return Apply( scalar, ImageOp::Mul, rect, firstChannel, lastChannel );
9870  }
9871 
9875  template <typename T>
9876  GenericImage& Mul( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9877  {
9878  return Multiply( scalar, rect, firstChannel, lastChannel );
9879  }
9880 
9884  template <typename T>
9885  GenericImage& operator *=( T scalar )
9886  {
9887  return Multiply( scalar );
9888  }
9889 
9900  template <typename T>
9901  GenericImage Multiplied( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9902  {
9903  GenericImage result( *this, rect, firstChannel, lastChannel );
9904  (void)result.Multiply( scalar );
9905  return result;
9906  }
9907 
9921  template <typename T>
9922  GenericImage& Divide( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9923  {
9924  return Apply( scalar, ImageOp::Div, rect, firstChannel, lastChannel );
9925  }
9926 
9930  template <typename T>
9931  GenericImage& Div( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9932  {
9933  return Divide( scalar, rect, firstChannel, lastChannel );
9934  }
9935 
9939  template <typename T>
9940  GenericImage& operator /=( T scalar )
9941  {
9942  return Divide( scalar );
9943  }
9944 
9958  template <typename T>
9959  GenericImage Divided( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9960  {
9961  GenericImage result( *this, rect, firstChannel, lastChannel );
9962  (void)result.Divide( scalar );
9963  return result;
9964  }
9965 
9976  template <typename T>
9977  GenericImage& Raise( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9978  {
9979  return Apply( scalar, ImageOp::Pow, rect, firstChannel, lastChannel );
9980  }
9981 
9985  template <typename T>
9986  GenericImage& Pow( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9987  {
9988  return Raise( scalar, rect, firstChannel, lastChannel );
9989  }
9990 
9994  template <typename T>
9995  GenericImage& operator ^=( T scalar )
9996  {
9997  return Raise( scalar );
9998  }
9999 
10010  template <typename T>
10011  GenericImage Raised( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
10012  {
10013  GenericImage result( *this, rect, firstChannel, lastChannel );
10014  (void)result.Raise( scalar );
10015  return result;
10016  }
10017 
10029  template <typename T>
10030  GenericImage& SetAbsoluteDifference( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10031  {
10032  return Apply( scalar, ImageOp::Dif, rect, firstChannel, lastChannel );
10033  }
10034 
10038  template <typename T>
10039  GenericImage& Dif( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10040  {
10041  return SetAbsoluteDifference( scalar, rect, firstChannel, lastChannel );
10042  }
10043 
10055  template <typename T>
10056  GenericImage AbsoluteDifference( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
10057  {
10058  GenericImage result( *this, rect, firstChannel, lastChannel );
10059  (void)result.SetAbsoluteDifference( scalar );
10060  return result;
10061  }
10062 
10073  template <typename T>
10074  GenericImage& SetMinimum( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10075  {
10076  return Apply( scalar, ImageOp::Min, rect, firstChannel, lastChannel );
10077  }
10078 
10082  template <typename T>
10083  GenericImage& Min( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10084  {
10085  return SetMinimum( scalar, rect, firstChannel, lastChannel );
10086  }
10087 
10099  template <typename T>
10100  GenericImage Minimum( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
10101  {
10102  GenericImage result( *this, rect, firstChannel, lastChannel );
10103  (void)result.SetMinimum( scalar );
10104  return result;
10105  }
10106 
10117  template <typename T>
10118  GenericImage& SetMaximum( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10119  {
10120  return Apply( scalar, ImageOp::Max, rect, firstChannel, lastChannel );
10121  }
10122 
10126  template <typename T>
10127  GenericImage& Max( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10128  {
10129  return SetMaximum( scalar, rect, firstChannel, lastChannel );
10130  }
10131 
10143  template <typename T>
10144  GenericImage Maximum( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
10145  {
10146  GenericImage result( *this, rect, firstChannel, lastChannel );
10147  (void)result.SetMaximum( scalar );
10148  return result;
10149  }
10150 
10162  template <typename T>
10163  GenericImage& Or( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10164  {
10165  return Apply( scalar, ImageOp::Or, rect, firstChannel, lastChannel );
10166  }
10167 
10179  template <typename T>
10180  GenericImage& And( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10181  {
10182  return Apply( scalar, ImageOp::And, rect, firstChannel, lastChannel );
10183  }
10184 
10196  template <typename T>
10197  GenericImage& Xor( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10198  {
10199  return Apply( scalar, ImageOp::Xor, rect, firstChannel, lastChannel );
10200  }
10201 
10213  template <typename T>
10214  GenericImage& Nor( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10215  {
10216  return Apply( scalar, ImageOp::Nor, rect, firstChannel, lastChannel );
10217  }
10218 
10230  template <typename T>
10231  GenericImage& Nand( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10232  {
10233  return Apply( scalar, ImageOp::Nand, rect, firstChannel, lastChannel );
10234  }
10235 
10247  template <typename T>
10248  GenericImage& Xnor( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10249  {
10250  return Apply( scalar, ImageOp::Xnor, rect, firstChannel, lastChannel );
10251  }
10252 
10253  // -------------------------------------------------------------------------
10254 
10265  template <class P1>
10267  const Point& point = Point( int_max ), int channel = -1,
10268  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10269  {
10270  return Apply( image, ImageOp::Mov, point, channel, rect, firstChannel, lastChannel );
10271  }
10272 
10276  template <class P1>
10278  const Point& point = Point( int_max ), int channel = -1,
10279  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10280  {
10281  return Move( image, point, channel, rect, firstChannel, lastChannel );
10282  }
10283 
10294  template <class P1>
10296  const Point& point = Point( int_max ), int channel = -1,
10297  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10298  {
10299  return Apply( image, ImageOp::Add, point, channel, rect, firstChannel, lastChannel );
10300  }
10301 
10305  template <class P1>
10306  GenericImage& operator +=( const GenericImage<P1>& image )
10307  {
10308  return Add( image );
10309  }
10310 
10321  template <class P1>
10323  const Point& point = Point( int_max ), int channel = -1,
10324  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10325  {
10326  return Apply( image, ImageOp::Sub, point, channel, rect, firstChannel, lastChannel );
10327  }
10328 
10332  template <class P1>
10334  const Point& point = Point( int_max ), int channel = -1,
10335  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10336  {
10337  return Subtract( image, point, channel, rect, firstChannel, lastChannel );
10338  }
10339 
10343  template <class P1>
10344  GenericImage& operator -=( const GenericImage<P1>& image )
10345  {
10346  return Subtract( image );
10347  }
10348 
10359  template <class P1>
10361  const Point& point = Point( int_max ), int channel = -1,
10362  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10363  {
10364  return Apply( image, ImageOp::Mul, point, channel, rect, firstChannel, lastChannel );
10365  }
10366 
10370  template <class P1>
10372  const Point& point = Point( int_max ), int channel = -1,
10373  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10374  {
10375  return Multiply( image, point, channel, rect, firstChannel, lastChannel );
10376  }
10377 
10381  template <class P1>
10382  GenericImage& operator *=( const GenericImage<P1>& image )
10383  {
10384  return Multiply( image );
10385  }
10386 
10401  template <class P1>
10403  const Point& point = Point( int_max ), int channel = -1,
10404  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10405  {
10406  return Apply( image, ImageOp::Div, point, channel, rect, firstChannel, lastChannel );
10407  }
10408 
10412  template <class P1>
10414  const Point& point = Point( int_max ), int channel = -1,
10415  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10416  {
10417  return Divide( image, point, channel, rect, firstChannel, lastChannel );
10418  }
10419 
10423  template <class P1>
10424  GenericImage& operator /=( const GenericImage<P1>& image )
10425  {
10426  return Divide( image );
10427  }
10428 
10440  template <class P1>
10442  const Point& point = Point( int_max ), int channel = -1,
10443  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10444  {
10445  return Apply( image, ImageOp::Pow, point, channel, rect, firstChannel, lastChannel );
10446  }
10447 
10451  template <class P1>
10453  const Point& point = Point( int_max ), int channel = -1,
10454  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10455  {
10456  return Raise( image, point, channel, rect, firstChannel, lastChannel );
10457  }
10458 
10462  template <class P1>
10463  GenericImage& operator ^=( const GenericImage<P1>& image )
10464  {
10465  return Raise( image );
10466  }
10467 
10479  template <class P1>
10481  const Point& point = Point( int_max ), int channel = -1,
10482  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10483  {
10484  return Apply( image, ImageOp::Dif, point, channel, rect, firstChannel, lastChannel );
10485  }
10486 
10490  template <class P1>
10492  const Point& point = Point( int_max ), int channel = -1,
10493  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10494  {
10495  return SetAbsoluteDifference( image, point, channel, rect, firstChannel, lastChannel );
10496  }
10497 
10509  template <class P1>
10511  const Point& point = Point( int_max ), int channel = -1,
10512  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10513  {
10514  return Apply( image, ImageOp::Min, point, channel, rect, firstChannel, lastChannel );
10515  }
10516 
10520  template <class P1>
10522  const Point& point = Point( int_max ), int channel = -1,
10523  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10524  {
10525  return SetMinimum( image, point, channel, rect, firstChannel, lastChannel );
10526  }
10527 
10539  template <class P1>
10541  const Point& point = Point( int_max ), int channel = -1,
10542  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10543  {
10544  return Apply( image, ImageOp::Max, point, channel, rect, firstChannel, lastChannel );
10545  }
10546 
10550  template <class P1>
10552  const Point& point = Point( int_max ), int channel = -1,
10553  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10554  {
10555  return SetMaximum( image, point, channel, rect, firstChannel, lastChannel );
10556  }
10557 
10569  template <class P1>
10571  const Point& point = Point( int_max ), int channel = -1,
10572  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10573  {
10574  return Apply( image, ImageOp::Or, point, channel, rect, firstChannel, lastChannel );
10575  }
10576 
10588  template <class P1>
10590  const Point& point = Point( int_max ), int channel = -1,
10591  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10592  {
10593  return Apply( image, ImageOp::And, point, channel, rect, firstChannel, lastChannel );
10594  }
10595 
10607  template <class P1>
10609  const Point& point = Point( int_max ), int channel = -1,
10610  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10611  {
10612  return Apply( image, ImageOp::Xor, point, channel, rect, firstChannel, lastChannel );
10613  }
10614 
10626  template <class P1>
10628  const Point& point = Point( int_max ), int channel = -1,
10629  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10630  {
10631  return Apply( image, ImageOp::Nor, point, channel, rect, firstChannel, lastChannel );
10632  }
10633 
10645  template <class P1>
10647  const Point& point = Point( int_max ), int channel = -1,
10648  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10649  {
10650  return Apply( image, ImageOp::Nand, point, channel, rect, firstChannel, lastChannel );
10651  }
10652 
10664  template <class P1>
10666  const Point& point = Point( int_max ), int channel = -1,
10667  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10668  {
10669  return Apply( image, ImageOp::Xnor, point, channel, rect, firstChannel, lastChannel );
10670  }
10671 
10672  // -------------------------------------------------------------------------
10673 
10711  template <class P1>
10713  const Point& point = Point( int_max ), int channel = -1,
10714  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10715  {
10716  Rect r = rect;
10717  if ( !image.ParseSelection( r, firstChannel, lastChannel ) )
10718  return *this;
10719 
10720  if ( !ParseChannel( channel ) )
10721  return *this;
10722 
10723  Point p = point;
10724  if ( p.x == int_max || p.y == int_max )
10725  p = m_point;
10726 
10727  if ( p.x < 0 )
10728  {
10729  if ( (r.x0 -= p.x) >= r.x1 )
10730  return *this;
10731  p.x = 0;
10732  }
10733  else if ( p.x >= m_width )
10734  return *this;
10735 
10736  if ( p.y < 0 )
10737  {
10738  if ( (r.y0 -= p.y) >= r.y1 )
10739  return *this;
10740  p.y = 0;
10741  }
10742  else if ( p.y >= m_height )
10743  return *this;
10744 
10745  r.ResizeTo( pcl::Min( m_width - p.x, r.Width() ),
10746  pcl::Min( m_height - p.y, r.Height() ) );
10747 
10748  lastChannel = pcl::Min( lastChannel, firstChannel + m_numberOfChannels - channel - 1 );
10749 
10750  EnsureUnique();
10751  image.EnsureUnique();
10752 
10753  size_type N = size_type( r.Width() )*size_type( r.Height() );
10754  if ( m_status.IsInitializationEnabled() )
10755  m_status.Initialize( "Exchanging pixel samples", N*(1 + lastChannel - firstChannel) );
10756 
10757  if ( r == Bounds() && r == image.Bounds() )
10758  for ( int i = channel, j = firstChannel; j <= lastChannel; ++i, ++j, m_status += N )
10759  {
10760  sample* __restrict__ f = m_pixelData[i];
10761  typename P1::sample* __restrict__ g = image[j];
10762  PCL_IVDEP
10763  for ( size_type k = 0; k < N; ++k, ++f, ++g )
10764  {
10765  sample t = *f;
10766  P1::FromSample( *f, *g );
10767  P::FromSample( *g, t );
10768  }
10769  }
10770  else
10771  for ( int i = channel, j = firstChannel, w = r.Width(), h = r.Height(); j <= lastChannel; ++i, ++j, m_status += N )
10772  {
10773  sample* __restrict__ f = PixelAddress( p, i );
10774  typename P1::sample* __restrict__ g = image.PixelAddress( r.LeftTop(), j );
10775  PCL_IVDEP
10776  for ( int k = 0; k < h; ++k, f += m_width-w, g += image.Width()-w )
10777  {
10778  PCL_IVDEP
10779  for ( int l = 0; l < w; ++l, ++f, ++g )
10780  {
10781  sample t = *f;
10782  P1::FromSample( *f, *g );
10783  P::FromSample( *g, t );
10784  }
10785  }
10786  }
10787 
10788  return *this;
10789  }
10790 
10794  template <class P1>
10796  const Point& point = Point( int_max ), int channel = -1,
10797  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10798  {
10799  return Exchange( image, point, channel, rect, firstChannel, lastChannel );
10800  }
10801 
10802  // -------------------------------------------------------------------------
10803 
10823  sample MinimumSampleValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
10824  int maxProcessors = 0 ) const
10825  {
10826  Rect r = rect;
10827  if ( !ParseSelection( r, firstChannel, lastChannel ) )
10828  return 0;
10829 
10830  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
10831  if ( m_status.IsInitializationEnabled() )
10832  m_status.Initialize( "Computing minimum pixel sample value", N );
10833 
10834  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
10835  bool useAffinity = m_parallel && Thread::IsRootThread();
10836  ReferenceArray<MinThread> threads;
10837  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
10838  threads.Add( new MinThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
10839  if ( threads.Length() > 1 )
10840  {
10841  int n = 0;
10842  for ( MinThread& thread : threads )
10843  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
10844  for ( MinThread& thread : threads )
10845  thread.Wait();
10846  }
10847  else
10848  threads[0].Run();
10849 
10850  sample min = P::MinSampleValue();
10851  for ( size_type i = 0; i < threads.Length(); ++i )
10852  if ( threads[i].count > 0 )
10853  {
10854  min = threads[i].min;
10855  while ( ++i < threads.Length() )
10856  if ( threads[i].count > 0 )
10857  if ( threads[i].min < min )
10858  min = threads[i].min;
10859  break;
10860  }
10861 
10862  threads.Destroy();
10863  m_status += N;
10864  return min;
10865  }
10866 
10872  sample MinimumPixelValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
10873  int maxProcessors = 0 ) const
10874  {
10875  return MinimumSampleValue( rect, firstChannel, lastChannel, maxProcessors );
10876  }
10877 
10897  sample MaximumSampleValue( const Rect& rect = Rect( 0 ),
10898  int firstChannel = -1, int lastChannel = -1, int maxProcessors = 0 ) const
10899  {
10900  Rect r = rect;
10901  if ( !ParseSelection( r, firstChannel, lastChannel ) )
10902  return 0;
10903 
10904  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
10905  if ( m_status.IsInitializationEnabled() )
10906  m_status.Initialize( "Computing maximum pixel sample value", N );
10907 
10908  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
10909  bool useAffinity = m_parallel && Thread::IsRootThread();
10910  ReferenceArray<MaxThread> threads;
10911  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
10912  threads.Add( new MaxThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
10913  if ( threads.Length() > 1 )
10914  {
10915  int n = 0;
10916  for ( MaxThread& thread : threads )
10917  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
10918  for ( MaxThread& thread : threads )
10919  thread.Wait();
10920  }
10921  else
10922  threads[0].Run();
10923 
10924  sample max = P::MinSampleValue();
10925  for ( size_type i = 0; i < threads.Length(); ++i )
10926  if ( threads[i].count > 0 )
10927  {
10928  max = threads[i].max;
10929  while ( ++i < threads.Length() )
10930  if ( threads[i].count > 0 )
10931  if ( max < threads[i].max )
10932  max = threads[i].max;
10933  break;
10934  }
10935 
10936  threads.Destroy();
10937  m_status += N;
10938  return max;
10939  }
10940 
10946  sample MaximumPixelValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
10947  int maxProcessors = 0 ) const
10948  {
10949  return MaximumSampleValue( rect, firstChannel, lastChannel, maxProcessors );
10950  }
10951 
10978  template <typename T>
10979  void GetExtremeSampleValues( T& min, T& max,
10980  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
10981  int maxProcessors = 0 ) const
10982  {
10983  Rect r = rect;
10984  if ( !ParseSelection( r, firstChannel, lastChannel ) )
10985  {
10986  // ### Required for compatibility with PCL 1.x
10987  P::FromSample( min, P::MinSampleValue() );
10988  max = min;
10989  return;
10990  }
10991 
10992  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
10993  if ( m_status.IsInitializationEnabled() )
10994  m_status.Initialize( "Computing extreme pixel sample values", N );
10995 
10996  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
10997  bool useAffinity = m_parallel && Thread::IsRootThread();
10999  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11000  threads.Add( new MinMaxThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
11001  if ( threads.Length() > 1 )
11002  {
11003  int n = 0;
11004  for ( MinMaxThread& thread : threads )
11005  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11006  for ( MinMaxThread& thread : threads )
11007  thread.Wait();
11008  }
11009  else
11010  threads[0].Run();
11011 
11012  sample vmin = P::MinSampleValue();
11013  sample vmax = P::MinSampleValue();
11014  for ( size_type i = 0; i < threads.Length(); ++i )
11015  if ( threads[i].count > 0 )
11016  {
11017  vmin = threads[i].min;
11018  vmax = threads[i].max;
11019  while ( ++i < threads.Length() )
11020  if ( threads[i].count > 0 )
11021  {
11022  if ( threads[i].min < vmin )
11023  vmin = threads[i].min;
11024  if ( vmax < threads[i].max )
11025  vmax = threads[i].max;
11026  }
11027  break;
11028  }
11029 
11030  threads.Destroy();
11031  m_status += N;
11032  P::FromSample( min, vmin );
11033  P::FromSample( max, vmax );
11034  }
11035 
11042  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11043  int maxProcessors = 0 ) const
11044  {
11045  GetExtremeSampleValues( min, max, rect, firstChannel, lastChannel, maxProcessors );
11046  }
11047 
11074  sample LocateMinimumSampleValue( int& xmin, int& ymin,
11075  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11076  int maxProcessors = 0 ) const
11077  {
11078  Rect r = rect;
11079  if ( !ParseSelection( r, firstChannel, lastChannel ) )
11080  {
11081  // ### Required for compatibility with PCL 1.x
11082  xmin = ymin = 0;
11083  return P::MinSampleValue();
11084  }
11085 
11086  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
11087  if ( m_status.IsInitializationEnabled() )
11088  m_status.Initialize( "Locating minimum pixel sample value", N );
11089 
11090  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
11091  bool useAffinity = m_parallel && Thread::IsRootThread();
11093  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11094  threads.Add( new MinPosThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
11095  if ( threads.Length() > 1 )
11096  {
11097  int n = 0;
11098  for ( MinPosThread& thread : threads )
11099  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11100  for ( MinPosThread& thread : threads )
11101  thread.Wait();
11102  }
11103  else
11104  threads[0].Run();
11105 
11106  xmin = ymin = -1;
11107  sample min = P::MinSampleValue();
11108  for ( size_type i = 0; i < threads.Length(); ++i )
11109  if ( threads[i].count > 0 )
11110  {
11111  min = threads[i].min;
11112  xmin = threads[i].pmin.x;
11113  ymin = threads[i].pmin.y;
11114  while ( ++i < threads.Length() )
11115  if ( threads[i].count > 0 )
11116  if ( threads[i].min < min )
11117  {
11118  min = threads[i].min;
11119  xmin = threads[i].pmin.x;
11120  ymin = threads[i].pmin.y;
11121  }
11122  break;
11123  }
11124 
11125  threads.Destroy();
11126  m_status += N;
11127  return min;
11128  }
11129 
11153  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11154  int maxProcessors = 0 ) const
11155  {
11156  return LocateMinimumSampleValue( pmin.x, pmin.y, rect, firstChannel, lastChannel, maxProcessors );
11157  }
11158 
11164  sample LocateMinimumPixelValue( int& xmin, int& ymin,
11165  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11166  int maxProcessors = 0 ) const
11167  {
11168  return LocateMinimumSampleValue( xmin, ymin, rect, firstChannel, lastChannel, maxProcessors );
11169  }
11170 
11177  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11178  int maxProcessors = 0 ) const
11179  {
11180  return LocateMinimumSampleValue( pmin, rect, firstChannel, lastChannel, maxProcessors );
11181  }
11182 
11209  sample LocateMaximumSampleValue( int& xmax, int& ymax,
11210  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11211  int maxProcessors = 0 ) const
11212  {
11213  Rect r = rect;
11214  if ( !ParseSelection( r, firstChannel, lastChannel ) )
11215  {
11216  // ### Required for compatibility with PCL 1.x
11217  xmax = ymax = 0;
11218  return P::MaxSampleValue();
11219  }
11220 
11221  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
11222  if ( m_status.IsInitializationEnabled() )
11223  m_status.Initialize( "Locating maximum pixel sample value", N );
11224 
11225  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
11226  bool useAffinity = m_parallel && Thread::IsRootThread();
11228  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11229  threads.Add( new MaxPosThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
11230  if ( threads.Length() > 1 )
11231  {
11232  int n = 0;
11233  for ( MaxPosThread& thread : threads )
11234  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11235  for ( MaxPosThread& thread : threads )
11236  thread.Wait();
11237  }
11238  else
11239  threads[0].Run();
11240 
11241  xmax = ymax = -1;
11242  sample max = P::MinSampleValue();
11243  for ( size_type i = 0; i < threads.Length(); ++i )
11244  if ( threads[i].count > 0 )
11245  {
11246  max = threads[i].max;
11247  xmax = threads[i].pmax.x;
11248  ymax = threads[i].pmax.y;
11249  while ( ++i < threads.Length() )
11250  if ( threads[i].count > 0 )
11251  if ( max < threads[i].max )
11252  {
11253  max = threads[i].max;
11254  xmax = threads[i].pmax.x;
11255  ymax = threads[i].pmax.y;
11256  }
11257  break;
11258  }
11259 
11260  threads.Destroy();
11261  m_status += N;
11262  return max;
11263  }
11264 
11288  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11289  int maxProcessors = 0 ) const
11290  {
11291  return LocateMaximumSampleValue( pmax.x, pmax.y, rect, firstChannel, lastChannel, maxProcessors );
11292  }
11293 
11299  sample LocateMaximumPixelValue( int& xmax, int& ymax,
11300  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11301  int maxProcessors = 0 ) const
11302  {
11303  return LocateMaximumSampleValue( xmax, ymax, rect, firstChannel, lastChannel, maxProcessors );
11304  }
11305 
11312  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11313  int maxProcessors = 0 ) const
11314  {
11315  return LocateMaximumSampleValue( pmax, rect, firstChannel, lastChannel, maxProcessors );
11316  }
11317 
11354  template <typename T>
11355  void LocateExtremeSampleValues( int& xmin, int& ymin, T& min,
11356  int& xmax, int& ymax, T& max,
11357  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11358  int maxProcessors = 0 ) const
11359  {
11360  Rect r = rect;
11361  if ( !ParseSelection( r, firstChannel, lastChannel ) )
11362  {
11363  // ### Required for compatibility with PCL 1.x
11364  xmin = ymin = xmax = ymax = 0;
11365  P::FromSample( min, P::MinSampleValue() );
11366  max = min;
11367  return;
11368  }
11369 
11370  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
11371  if ( m_status.IsInitializationEnabled() )
11372  m_status.Initialize( "Locating extreme pixel sample values", N );
11373 
11374  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
11375  bool useAffinity = m_parallel && Thread::IsRootThread();
11377  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11378  threads.Add( new MinMaxPosThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
11379  if ( threads.Length() > 1 )
11380  {
11381  int n = 0;
11382  for ( MinMaxPosThread& thread : threads )
11383  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11384  for ( MinMaxPosThread& thread : threads )
11385  thread.Wait();
11386  }
11387  else
11388  threads[0].Run();
11389 
11390  xmin = ymin = xmax = ymax = -1;
11391  sample vmin = P::MinSampleValue();
11392  sample vmax = P::MinSampleValue();
11393  for ( size_type i = 0; i < threads.Length(); ++i )
11394  if ( threads[i].count > 0 )
11395  {
11396  vmin = threads[i].min;
11397  xmin = threads[i].pmin.x;
11398  ymin = threads[i].pmin.y;
11399  vmax = threads[i].max;
11400  xmax = threads[i].pmax.x;
11401  ymax = threads[i].pmax.y;
11402  while ( ++i < threads.Length() )
11403  if ( threads[i].count > 0 )
11404  {
11405  if ( threads[i].min < vmin )
11406  {
11407  vmin = threads[i].min;
11408  xmin = threads[i].pmin.x;
11409  ymin = threads[i].pmin.y;
11410  }
11411  if ( vmax < threads[i].max )
11412  {
11413  vmax = threads[i].max;
11414  xmax = threads[i].pmax.x;
11415  ymax = threads[i].pmax.y;
11416  }
11417  }
11418  break;
11419  }
11420 
11421  threads.Destroy();
11422  m_status += N;
11423  P::FromSample( min, vmin );
11424  P::FromSample( max, vmax );
11425  }
11426 
11454  template <typename T>
11455  void LocateExtremeSampleValues( Point& pmin, T& min,
11456  Point& pmax, T& max,
11457  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11458  int maxProcessors = 0 ) const
11459  {
11460  LocateExtremeSampleValues( pmin.x, pmin.y, min,
11461  pmax.x, pmax.y, max,
11462  rect, firstChannel, lastChannel, maxProcessors );
11463  }
11464 
11490  size_type Count( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11491  int maxProcessors = 0 ) const
11492  {
11493  Rect r = rect;
11494  if ( !ParseSelection( r, firstChannel, lastChannel ) )
11495  return 0;
11496 
11497  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
11498  if ( m_status.IsInitializationEnabled() )
11499  m_status.Initialize( "Counting pixel samples", N );
11500 
11501  if ( !this->IsRangeClippingEnabled() )
11502  {
11503  m_status += N;
11504  return size_type( r.Width() ) * size_type( r.Height() ) * size_type( 1 + lastChannel - firstChannel );
11505  }
11506 
11507  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
11508  bool useAffinity = m_parallel && Thread::IsRootThread();
11510  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11511  threads.Add( new CountThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
11512  if ( threads.Length() > 1 )
11513  {
11514  int n = 0;
11515  for ( CountThread& thread : threads )
11516  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11517  for ( CountThread& thread : threads )
11518  thread.Wait();
11519  }
11520  else
11521  threads[0].Run();
11522 
11523  size_type count = 0;
11524  for ( const CountThread& thread : threads )
11525  count += thread.count;
11526 
11527  threads.Destroy();
11528  m_status += N;
11529  return count;
11530  }
11531 
11560  double Mean( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11561  int maxProcessors = 0 ) const
11562  {
11563  Rect r = rect;
11564  if ( !ParseSelection( r, firstChannel, lastChannel ) )
11565  return 0;
11566 
11567  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
11568  if ( m_status.IsInitializationEnabled() )
11569  m_status.Initialize( "Computing mean pixel sample value", N );
11570 
11571  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
11572  bool useAffinity = m_parallel && Thread::IsRootThread();
11573  ReferenceArray<SumThread> threads;
11574  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11575  threads.Add( new SumThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
11576  if ( threads.Length() > 1 )
11577  {
11578  int n = 0;
11579  for ( SumThread& thread : threads )
11580  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11581  for ( SumThread& thread : threads )
11582  thread.Wait();
11583  }
11584  else
11585  threads[0].Run();
11586 
11587  double s = 0;
11588  double e = 0;
11589  size_type n = 0;
11590  for ( const SumThread& thread : threads )
11591  {
11592  double y = thread.s - e;
11593  double t = s + y;
11594  e = (t - s) - y;
11595  s = t;
11596  n += thread.n;
11597  }
11598 
11599  threads.Destroy();
11600 
11601  m_status += N;
11602 
11603  if ( n == 0 )
11604  return 0;
11605  return s/n;
11606  }
11607 
11633  double Median( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11634  int maxProcessors = 0 ) const
11635  {
11636  Rect r = rect;
11637  if ( !ParseSelection( r, firstChannel, lastChannel ) )
11638  return 0;
11639 
11640  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
11641  if ( m_status.IsInitializationEnabled() )
11642  m_status.Initialize( "Computing median pixel sample value", N );
11643 
11644  if ( N <= 2560000 )
11645  {
11646  SmpThread S( *this, r, firstChannel, lastChannel, 0, r.Height() );
11647  S.Run();
11648  if ( S.n == 0 )
11649  {
11650  m_status += N;
11651  return 0;
11652  }
11653  double m = double( *pcl::Select( S.samples.Begin(), S.samples.At( S.n ), S.n >> 1 ) )/double( P::MaxSampleValue() );
11654  if ( S.n & 1 )
11655  {
11656  m_status += N;
11657  return m;
11658  }
11659  m = (m + double( *pcl::Select( S.samples.Begin(), S.samples.At( S.n ), (S.n >> 1)-1 ) )/double( P::MaxSampleValue() ))/2;
11660  m_status += N;
11661  return m;
11662  }
11663 
11664  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors, 160*1024/*overheadLimitPx*/ );
11665  bool useAffinity = m_parallel && Thread::IsRootThread();
11666 
11667  double low, high;
11668  size_type count = 0;
11669  {
11671  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11672  threads << new MinMaxThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) );
11673 
11674  if ( threads.Length() > 1 )
11675  {
11676  int i = 0;
11677  for ( MinMaxThread& thread : threads )
11678  thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
11679  for ( MinMaxThread& thread : threads )
11680  thread.Wait();
11681  }
11682  else
11683  threads[0].Run();
11684 
11685  sample slow = 0, shigh = 0;
11686  for ( size_type i = 0; i < threads.Length(); ++i )
11687  if ( threads[i].count > 0 )
11688  {
11689  slow = threads[i].min;
11690  shigh = threads[i].max;
11691  count = threads[i].count;
11692  while ( ++i < threads.Length() )
11693  if ( threads[i].count > 0 )
11694  {
11695  if ( threads[i].min < slow )
11696  slow = threads[i].min;
11697  if ( shigh < threads[i].max )
11698  shigh = threads[i].max;
11699  count += threads[i].count;
11700  }
11701  break;
11702  }
11703 
11704  threads.Destroy();
11705 
11706  low = double( slow );
11707  high = double( shigh );
11708  }
11709 
11710  const double eps = P::IsComplexSample() ? 2*std::numeric_limits<double>::epsilon() :
11711  (P::IsFloatSample() ? 2*std::numeric_limits<typename P::component>::epsilon() :
11712  0.5/Pow2( double( P::BitsPerSample() ) ));
11713  if ( count == 0 )
11714  {
11715  m_status += N;
11716  return 0;
11717  }
11718  if ( high - low < eps )
11719  {
11720  m_status += N;
11721  return low/double( P::MaxSampleValue() );
11722  }
11723 
11725  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11726  threads << new HistogramThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ), low, high );
11727 
11728  double mh = 0, l0 = low, h0 = high;
11729  SzVector H0;
11730 
11731  for ( size_type n = 0, n2 = count >> 1, step = 0, it = 0;; ++it )
11732  {
11733  SzVector H;
11734  if ( it == 0 && step )
11735  H = H0;
11736  else
11737  {
11738  if ( threads.Length() > 1 )
11739  {
11740  int i = 0;
11741  for ( HistogramThread& thread : threads )
11742  thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
11743  for ( HistogramThread& thread : threads )
11744  thread.Wait();
11745  }
11746  else
11747  threads[0].Run();
11748 
11749  H = threads[0].H;
11750  for ( size_type i = 1; i < threads.Length(); ++i )
11751  H += threads[i].H;
11752  if ( it == 0 )
11753  if ( (count & 1) == 0 )
11754  H0 = H;
11755  }
11756 
11757  for ( int i = 0; ; n += H[i++] )
11758  if ( n + H[i] > n2 )
11759  {
11760  double range = high - low;
11761  high = (range * (i + 1))/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
11762  low = (range * i)/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
11763  if ( high - low < eps )
11764  {
11765  if ( count & 1 )
11766  {
11767  threads.Destroy();
11768  m_status += N;
11769  return low/double( P::MaxSampleValue() );
11770  }
11771  if ( step )
11772  {
11773  threads.Destroy();
11774  m_status += N;
11775  return (low + mh)/2/double( P::MaxSampleValue() );
11776  }
11777  mh = low;
11778  low = l0;
11779  high = h0;
11780  n = 0;
11781  --n2;
11782  ++step;
11783  it = 0;
11784  }
11785  break;
11786  }
11787  }
11788  }
11789 
11821  double OrderStatistic( double k,
11822  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11823  int maxProcessors = 0 ) const
11824  {
11825  if ( k < 0 || k > 1 )
11826  return 0;
11827 
11828  Rect r = rect;
11829  if ( !ParseSelection( r, firstChannel, lastChannel ) )
11830  return 0;
11831 
11832  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
11833  if ( m_status.IsInitializationEnabled() )
11834  m_status.Initialize( "Computing order statistic", N );
11835 
11836  if ( N <= 2560000 )
11837  {
11838  SmpThread S( *this, r, firstChannel, lastChannel, 0, r.Height() );
11839  S.Run();
11840  m_status += N;
11841  if ( S.n == 0 )
11842  return 0;
11843  return double( *pcl::Select( S.samples.Begin(), S.samples.At( S.n ), distance_type( k*(S.n - 1) ) ) )/double( P::MaxSampleValue() );
11844  }
11845 
11846  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors, 160*1024/*overheadLimitPx*/ );
11847  bool useAffinity = m_parallel && Thread::IsRootThread();
11848 
11849  double low, high;
11850  size_type count = 0;
11851  {
11853  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11854  threads << new MinMaxThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) );
11855 
11856  if ( threads.Length() > 1 )
11857  {
11858  int i = 0;
11859  for ( MinMaxThread& thread : threads )
11860  thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
11861  for ( MinMaxThread& thread : threads )
11862  thread.Wait();
11863  }
11864  else
11865  threads[0].Run();
11866 
11867  sample slow = 0, shigh = 0;
11868  for ( size_type i = 0; i < threads.Length(); ++i )
11869  if ( threads[i].count > 0 )
11870  {
11871  slow = threads[i].min;
11872  shigh = threads[i].max;
11873  count = threads[i].count;
11874  while ( ++i < threads.Length() )
11875  if ( threads[i].count > 0 )
11876  {
11877  if ( threads[i].min < slow )
11878  slow = threads[i].min;
11879  if ( shigh < threads[i].max )
11880  shigh = threads[i].max;
11881  count += threads[i].count;
11882  }
11883  break;
11884  }
11885 
11886  threads.Destroy();
11887 
11888  low = double( slow );
11889  high = double( shigh );
11890  }
11891 
11892  const double eps = P::IsComplexSample() ? 2*std::numeric_limits<double>::epsilon() :
11893  (P::IsFloatSample() ? 2*std::numeric_limits<typename P::component>::epsilon() :
11894  0.5/Pow2( double( P::BitsPerSample() ) ));
11895  if ( count == 0 )
11896  {
11897  m_status += N;
11898  return 0;
11899  }
11900  if ( k == 0 || high - low < eps )
11901  {
11902  m_status += N;
11903  return low/double( P::MaxSampleValue() );
11904  }
11905  if ( k == 1 )
11906  {
11907  m_status += N;
11908  return high/double( P::MaxSampleValue() );
11909  }
11910 
11911  size_type index = size_type( k*(count - 1) );
11912 
11914  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11915  threads << new HistogramThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ), low, high );
11916 
11917  for ( size_type n = 0;; )
11918  {
11919  if ( threads.Length() > 1 )
11920  {
11921  int i = 0;
11922  for ( HistogramThread& thread : threads )
11923  thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
11924  for ( HistogramThread& thread : threads )
11925  thread.Wait();
11926  }
11927  else
11928  threads[0].Run();
11929 
11930  SzVector H = threads[0].H;
11931  for ( size_type i = 1; i < threads.Length(); ++i )
11932  H += threads[i].H;
11933 
11934  for ( int i = 0; ; n += H[i++] )
11935  if ( n + H[i] > index )
11936  {
11937  double range = high - low;
11938  high = (range * (i + 1))/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
11939  low = (range * i)/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
11940  if ( high - low < eps )
11941  {
11942  threads.Destroy();
11943  m_status += N;
11944  return low/double( P::MaxSampleValue() );
11945  }
11946  break;
11947  }
11948  }
11949  }
11950 
11985  double Variance( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
11986  int maxProcessors = 0 ) const
11987  {
11988  Rect r = rect;
11989  if ( !ParseSelection( r, firstChannel, lastChannel ) )
11990  return 0;
11991 
11992  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
11993  if ( m_status.IsInitializationEnabled() )
11994  m_status.Initialize( "Computing variance", N );
11995 
11996  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
11997  bool useAffinity = m_parallel && Thread::IsRootThread();
11998  ReferenceArray<SumThread> sumThreads;
11999  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12000  sumThreads.Add( new SumThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
12001  if ( sumThreads.Length() > 1 )
12002  {
12003  int n = 0;
12004  for ( SumThread& thread : sumThreads )
12005  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12006  for ( SumThread& thread : sumThreads )
12007  thread.Wait();
12008  }
12009  else
12010  sumThreads[0].Run();
12011 
12012  double s = 0;
12013  double e = 0;
12014  size_type n = 0;
12015  for ( const SumThread& thread : sumThreads )
12016  {
12017  double y = thread.s - e;
12018  double t = s + y;
12019  e = (t - s) - y;
12020  s = t;
12021  n += thread.n;
12022  }
12023 
12024  sumThreads.Destroy();
12025 
12026  if ( n < 2 )
12027  return 0;
12028  double mean = s/n;
12029 
12030  ReferenceArray<VarThread> varThreads;
12031  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12032  varThreads.Add( new VarThread( *this, mean, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
12033  if ( varThreads.Length() > 1 )
12034  {
12035  int n = 0;
12036  for ( VarThread& thread : varThreads )
12037  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12038  for ( VarThread& thread : varThreads )
12039  thread.Wait();
12040  }
12041  else
12042  varThreads[0].Run();
12043 
12044  double var = 0, eps = 0;
12045  for ( const VarThread& thread : varThreads )
12046  var += thread.var, eps += thread.eps;
12047 
12048  varThreads.Destroy();
12049  m_status += N;
12050  return (var - eps*eps/n)/(n - 1);
12051  }
12052 
12085  double StdDev( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
12086  int maxProcessors = 0 ) const
12087  {
12088  return pcl::Sqrt( Variance( rect, firstChannel, lastChannel, maxProcessors ) );
12089  }
12090 
12130  double AvgDev( double center,
12131  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
12132  int maxProcessors = 0 ) const
12133  {
12134  Rect r = rect;
12135  if ( !ParseSelection( r, firstChannel, lastChannel ) )
12136  return 0;
12137 
12138  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
12139  if ( m_status.IsInitializationEnabled() )
12140  m_status.Initialize( "Computing average absolute deviation", N );
12141 
12142  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
12143  bool useAffinity = m_parallel && Thread::IsRootThread();
12145  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12146  threads.Add( new SumAbsDevThread( *this, center, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
12147  if ( threads.Length() > 1 )
12148  {
12149  int n = 0;
12150  for ( SumAbsDevThread& thread : threads )
12151  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12152  for ( SumAbsDevThread& thread : threads )
12153  thread.Wait();
12154  }
12155  else
12156  threads[0].Run();
12157 
12158  double s = 0;
12159  double e = 0;
12160  size_type n = 0;
12161  for ( const SumAbsDevThread& thread : threads )
12162  {
12163  double y = thread.s - e;
12164  double t = s + y;
12165  e = (t - s) - y;
12166  s = t;
12167  n += thread.n;
12168  }
12169 
12170  threads.Destroy();
12171 
12172  m_status += N;
12173 
12174  if ( n == 0 )
12175  return 0;
12176  return s/n;
12177  }
12178 
12200  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
12201  int maxProcessors = 0 ) const
12202  {
12203  Rect r = rect;
12204  if ( !ParseSelection( r, firstChannel, lastChannel ) )
12205  return 0;
12206 
12207  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
12208  if ( m_status.IsInitializationEnabled() )
12209  m_status.Initialize( "Computing two-sided average absolute deviation", N );
12210 
12211  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
12212  bool useAffinity = m_parallel && Thread::IsRootThread();
12214  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12215  threads.Add( new TwoSidedSumAbsDevThread( *this, center, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
12216  if ( threads.Length() > 1 )
12217  {
12218  int n = 0;
12219  for ( TwoSidedSumAbsDevThread& thread : threads )
12220  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12221  for ( TwoSidedSumAbsDevThread& thread : threads )
12222  thread.Wait();
12223  }
12224  else
12225  threads[0].Run();
12226 
12227  double s0 = 0, s1 = 0;
12228  double e0 = 0, e1 = 0;
12229  size_type n0 = 0, n1 = 0;
12230  for ( const TwoSidedSumAbsDevThread& thread : threads )
12231  {
12232  double y = thread.s0 - e0;
12233  double t = s0 + y;
12234  e0 = (t - s0) - y;
12235  s0 = t;
12236  n0 += thread.n0;
12237  y = thread.s1 - e1;
12238  t = s1 + y;
12239  e1 = (t - s1) - y;
12240  s1 = t;
12241  n1 += thread.n1;
12242  }
12243 
12244  threads.Destroy();
12245 
12246  m_status += N;
12247 
12248  return { (n0 > 0) ? s0/n0 : 0.0,
12249  (n1 > 0) ? s1/n1 : 0.0 };
12250  }
12251 
12286  double MAD( double center,
12287  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
12288  int maxProcessors = 0 ) const
12289  {
12290  Rect r = rect;
12291  if ( !ParseSelection( r, firstChannel, lastChannel ) )
12292  return 0;
12293 
12294  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
12295  if ( m_status.IsInitializationEnabled() )
12296  m_status.Initialize( "Computing median absolute deviation", N );
12297 
12298  if ( N <= 2560000 )
12299  {
12300  AbsDevSmpThread S( *this, center, r, firstChannel, lastChannel, 0, r.Height() );
12301  S.Run();
12302  if ( S.n == 0 )
12303  {
12304  m_status += N;
12305  return 0;
12306  }
12307  double m = *pcl::Select( S.values.Begin(), S.values.At( S.n ), S.n >> 1 );
12308  if ( S.n & 1 )
12309  {
12310  m_status += N;
12311  return m;
12312  }
12313  m = (m + *pcl::Select( S.values.Begin(), S.values.At( S.n ), (S.n >> 1)-1 ))/2;
12314  m_status += N;
12315  return m;
12316  }
12317 
12318  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors, 160*1024/*overheadLimitPx*/ );
12319  bool useAffinity = m_parallel && Thread::IsRootThread();
12320 
12321  double low, high;
12322  size_type count = 0;
12323  {
12325  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12326  threads << new ExtremeAbsDevThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ), center );
12327 
12328  if ( threads.Length() > 1 )
12329  {
12330  int n = 0;
12331  for ( ExtremeAbsDevThread& thread : threads )
12332  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12333  for ( ExtremeAbsDevThread& thread : threads )
12334  thread.Wait();
12335  }
12336  else
12337  threads[0].Run();
12338 
12339  for ( size_type i = 0; i < threads.Length(); ++i )
12340  if ( threads[i].count > 0 )
12341  {
12342  low = threads[i].minAbsDev;
12343  high = threads[i].maxAbsDev;
12344  count += threads[i].count;
12345  while ( ++i < threads.Length() )
12346  if ( threads[i].count > 0 )
12347  {
12348  if ( threads[i].minAbsDev < low )
12349  low = threads[i].minAbsDev;
12350  if ( threads[i].maxAbsDev > high )
12351  high = threads[i].maxAbsDev;
12352  count += threads[i].count;
12353  }
12354  break;
12355  }
12356 
12357  threads.Destroy();
12358  }
12359 
12360  const double eps = 2*std::numeric_limits<double>::epsilon();
12361  if ( count == 0 || high - low < eps )
12362  {
12363  m_status += N;
12364  return 0;
12365  }
12366 
12368  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12369  threads << new AbsDevHistogramThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ), center, low, high );
12370 
12371  double mh = 0, l0 = low, h0 = high;
12372  SzVector H0;
12373 
12374  for ( size_type n = 0, n2 = count >> 1, step = 0, it = 0;; ++it )
12375  {
12376  SzVector H;
12377  if ( it == 0 && step )
12378  H = H0;
12379  else
12380  {
12381  if ( threads.Length() > 1 )
12382  {
12383  int i = 0;
12384  for ( AbsDevHistogramThread& thread : threads )
12385  thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
12386  for ( AbsDevHistogramThread& thread : threads )
12387  thread.Wait();
12388  }
12389  else
12390  threads[0].Run();
12391 
12392  H = threads[0].H;
12393  for ( size_type i = 1; i < threads.Length(); ++i )
12394  H += threads[i].H;
12395  if ( it == 0 )
12396  if ( (count & 1) == 0 )
12397  H0 = H;
12398  }
12399 
12400  for ( int i = 0; ; n += H[i++] )
12401  if ( n + H[i] > n2 )
12402  {
12403  double range = high - low;
12404  high = (range * (i + 1))/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
12405  low = (range * i)/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
12406  if ( high - low < eps )
12407  {
12408  if ( count & 1 )
12409  {
12410  threads.Destroy();
12411  m_status += N;
12412  return low;
12413  }
12414  if ( step )
12415  {
12416  threads.Destroy();
12417  m_status += N;
12418  return (low + mh)/2;
12419  }
12420  mh = low;
12421  low = l0;
12422  high = h0;
12423  n = 0;
12424  --n2;
12425  ++step;
12426  it = 0;
12427  }
12428  break;
12429  }
12430  }
12431  }
12432 
12454  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
12455  int maxProcessors = 0 ) const
12456  {
12457  Rect r = rect;
12458  if ( !ParseSelection( r, firstChannel, lastChannel ) )
12459  return 0;
12460 
12461  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
12462  if ( m_status.IsInitializationEnabled() )
12463  m_status.Initialize( "Computing two-sided median absolute deviation", N );
12464 
12465  if ( N <= 2560000 )
12466  {
12467  TwoSidedAbsDevSmpThread S( *this, center, r, firstChannel, lastChannel, 0, r.Height() );
12468  S.Run();
12469  m_status += N;
12470  return { pcl::Median( S.values.Begin(), S.p ),
12471  pcl::Median( S.q, S.values.End() ) };
12472  }
12473 
12474  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors, 160*1024/*overheadLimitPx*/ );
12475  bool useAffinity = m_parallel && Thread::IsRootThread();
12476 
12477  double minLow = 0, minHigh = 0, maxLow = 0, maxHigh = 0;
12478  size_type nLow = 0, nHigh = 0;
12479  {
12481  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12482  threads << new TwoSidedExtremeAbsDevThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ), center );
12483 
12484  if ( threads.Length() > 1 )
12485  {
12486  int n = 0;
12487  for ( TwoSidedExtremeAbsDevThread& thread : threads )
12488  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12489  for ( TwoSidedExtremeAbsDevThread& thread : threads )
12490  thread.Wait();
12491  }
12492  else
12493  threads[0].Run();
12494 
12495  for ( size_type i = 0; i < threads.Length(); ++i )
12496  if ( threads[i].nLow > 0 )
12497  {
12498  minLow = threads[i].minAbsDevLow;
12499  maxLow = threads[i].maxAbsDevLow;
12500  nLow = threads[i].nLow;
12501  while ( ++i < threads.Length() )
12502  if ( threads[i].nLow > 0 )
12503  {
12504  if ( threads[i].minAbsDevLow < minLow )
12505  minLow = threads[i].minAbsDevLow;
12506  if ( threads[i].maxAbsDevLow > maxLow )
12507  maxLow = threads[i].maxAbsDevLow;
12508  nLow += threads[i].nLow;
12509  }
12510  break;
12511  }
12512 
12513  for ( size_type i = 0; i < threads.Length(); ++i )
12514  if ( threads[i].nHigh > 0 )
12515  {
12516  minHigh = threads[i].minAbsDevHigh;
12517  maxHigh = threads[i].maxAbsDevHigh;
12518  nHigh = threads[i].nHigh;
12519  while ( ++i < threads.Length() )
12520  if ( threads[i].nHigh > 0 )
12521  {
12522  if ( threads[i].minAbsDevHigh < minHigh )
12523  minHigh = threads[i].minAbsDevHigh;
12524  if ( threads[i].maxAbsDevHigh > maxHigh )
12525  maxHigh = threads[i].maxAbsDevHigh;
12526  nHigh += threads[i].nHigh;
12527  }
12528  break;
12529  }
12530 
12531  threads.Destroy();
12532  }
12533 
12534  int side;
12535  double sideLow, sideHigh;
12537  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12538  threads << new TwoSidedAbsDevHistogramThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ), center, side, sideLow, sideHigh );
12539 
12540  const double eps = 2*std::numeric_limits<double>::epsilon();
12541  double mad[ 2 ];
12542  for ( side = 0; side < 2; ++side )
12543  {
12544  size_type n = side ? nHigh : nLow;
12545  if ( n < 2 )
12546  {
12547  mad[side] = 0;
12548  continue;
12549  }
12550 
12551  sideLow = side ? minHigh : minLow;
12552  sideHigh = side ? maxHigh : maxLow;
12553  if ( sideHigh - sideLow < eps )
12554  {
12555  mad[side] = 0;
12556  continue;
12557  }
12558 
12559  double mh = 0, h0 = sideHigh;
12560  SzVector H0;
12561 
12562  for ( size_type count = 0, n2 = n >> 1, step = 0, it = 0;; ++it )
12563  {
12564  SzVector H;
12565  if ( it == 0 && step )
12566  H = H0;
12567  else
12568  {
12569  if ( threads.Length() > 1 )
12570  {
12571  int i = 0;
12572  for ( TwoSidedAbsDevHistogramThread& thread : threads )
12573  thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
12574  for ( TwoSidedAbsDevHistogramThread& thread : threads )
12575  thread.Wait();
12576  }
12577  else
12578  threads[0].Run();
12579 
12580  H = threads[0].H;
12581  for ( size_type i = 1; i < threads.Length(); ++i )
12582  H += threads[i].H;
12583  if ( it == 0 )
12584  if ( (n & 1) == 0 )
12585  H0 = H;
12586  }
12587 
12588  for ( int i = 0; ; count += H[i++] )
12589  if ( count + H[i] > n2 )
12590  {
12591  double range = sideHigh - sideLow;
12592  sideHigh = (range * (i + 1))/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + sideLow;
12593  sideLow = (range * i)/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + sideLow;
12594  if ( sideHigh - sideLow < eps )
12595  {
12596  if ( n & 1 )
12597  {
12598  mad[side] = sideLow;
12599  goto __madNextSide;
12600  }
12601  if ( step )
12602  {
12603  mad[side] = (sideLow + mh)/2;
12604  goto __madNextSide;
12605  }
12606  mh = sideLow;
12607  sideLow = 0;
12608  sideHigh = h0;
12609  count = 0;
12610  --n2;
12611  ++step;
12612  it = 0;
12613  }
12614  break;
12615  }
12616  }
12617 
12618 __madNextSide:
12619 ;
12620  }
12621 
12622  threads.Destroy();
12623  m_status += N;
12624  return { mad[0], mad[1] };
12625  }
12626 
12671  double BiweightMidvariance( double center, double sigma, int k = 9, bool reducedLength = false,
12672  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
12673  int maxProcessors = 0 ) const
12674  {
12675  Rect r = rect;
12676  if ( !ParseSelection( r, firstChannel, lastChannel ) )
12677  return 0;
12678 
12679  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
12680  double kd = k * sigma;
12681  if ( kd < 0 || 1 + kd == 1 )
12682  {
12683  m_status += N;
12684  return 0;
12685  }
12686 
12687  if ( m_status.IsInitializationEnabled() )
12688  m_status.Initialize( "Computing biweight midvariance", N );
12689 
12690  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
12691  bool useAffinity = m_parallel && Thread::IsRootThread();
12693  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12694  threads.Add( new BWMVThread( *this, center, kd, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
12695  if ( threads.Length() > 1 )
12696  {
12697  int n = 0;
12698  for ( BWMVThread& thread : threads )
12699  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12700  for ( BWMVThread& thread : threads )
12701  thread.Wait();
12702  }
12703  else
12704  threads[0].Run();
12705 
12706  double num = 0, den = 0;
12707  size_type n = 0, nr = 0;
12708  for ( const BWMVThread& thread : threads )
12709  {
12710  num += thread.num;
12711  den += thread.den;
12712  n += thread.n;
12713  nr += thread.nr;
12714  }
12715 
12716  threads.Destroy();
12717 
12718  m_status += N;
12719  den *= den;
12720  return (n >= 2 && 1 + den != 1) ? (reducedLength ? nr : n)*num/den : 0.0;
12721  }
12722 
12751  TwoSidedEstimate TwoSidedBiweightMidvariance( double center, const TwoSidedEstimate& sigma, int k = 9, bool reducedLength = false,
12752  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
12753  int maxProcessors = 0 ) const
12754  {
12755  Rect r = rect;
12756  if ( !ParseSelection( r, firstChannel, lastChannel ) )
12757  return 0;
12758 
12759  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
12760  double kd0 = k * sigma.low;
12761  double kd1 = k * sigma.high;
12762  if ( kd0 < 0 || 1 + kd0 == 1 || kd1 < 0 || 1 + kd1 == 1 )
12763  {
12764  m_status += N;
12765  return 0;
12766  }
12767 
12768  if ( m_status.IsInitializationEnabled() )
12769  m_status.Initialize( "Computing two-sided biweight midvariance", N );
12770 
12771  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
12772  bool useAffinity = m_parallel && Thread::IsRootThread();
12774  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12775  threads.Add( new TwoSidedBWMVThread( *this, center, kd0, kd1, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
12776  if ( threads.Length() > 1 )
12777  {
12778  int n = 0;
12779  for ( TwoSidedBWMVThread& thread : threads )
12780  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12781  for ( TwoSidedBWMVThread& thread : threads )
12782  thread.Wait();
12783  }
12784  else
12785  threads[0].Run();
12786 
12787  double num0 = 0, den0 = 0, num1 = 0, den1 = 0;
12788  size_type n0 = 0, n1 = 0, nr0 = 0, nr1 = 0;
12789  for ( const TwoSidedBWMVThread& thread : threads )
12790  {
12791  num0 += thread.num0;
12792  den0 += thread.den0;
12793  num1 += thread.num1;
12794  den1 += thread.den1;
12795  n0 += thread.n0;
12796  n1 += thread.n1;
12797  nr0 += thread.nr0;
12798  nr1 += thread.nr1;
12799  }
12800 
12801  threads.Destroy();
12802 
12803  m_status += N;
12804 
12805  den0 *= den0;
12806  den1 *= den1;
12807  return { (n0 >= 2 && 1 + den0 != 1) ? (reducedLength ? nr0 : n0)*num0/den0 : 0.0,
12808  (n1 >= 2 && 1 + den1 != 1) ? (reducedLength ? nr1 : n1)*num1/den1 : 0.0 };
12809  }
12810 
12854  double BendMidvariance( double center, double beta = 0.2,
12855  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
12856  int maxProcessors = 0 ) const
12857  {
12858  Rect r = rect;
12859  if ( !ParseSelection( r, firstChannel, lastChannel ) )
12860  return 0;
12861 
12862  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
12863  if ( m_status.IsInitializationEnabled() )
12864  m_status.Initialize( "Computing percentage bend midvariance", N );
12865 
12866  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
12867  bool useAffinity = m_parallel && Thread::IsRootThread();
12869  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12870  threads.Add( new DSmpThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
12871  if ( threads.Length() > 1 )
12872  {
12873  int n = 0;
12874  for ( DSmpThread& thread : threads )
12875  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12876  for ( DSmpThread& thread : threads )
12877  thread.Wait();
12878  }
12879  else
12880  threads[0].Run();
12881 
12882  Array<double> values;
12883  for ( DSmpThread& thread : threads )
12884  if ( !thread.values.IsEmpty() )
12885  {
12886  values.Add( thread.values.Begin(), thread.values.At( thread.n ) );
12887  thread.values.Clear();
12888  }
12889 
12890  threads.Destroy();
12891 
12892  double pbmv = pcl::BendMidvariance( values.Begin(), values.End(), center, beta );
12893  m_status += N;
12894  return pbmv;
12895  }
12896 
12940  double Sn( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1, int maxProcessors = 0 ) const
12941  {
12942  Rect r = rect;
12943  if ( !ParseSelection( r, firstChannel, lastChannel ) )
12944  return 0;
12945 
12946  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
12947  if ( m_status.IsInitializationEnabled() )
12948  m_status.Initialize( "Computing Sn scale estimate", N );
12949 
12950  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
12951  bool useAffinity = m_parallel && Thread::IsRootThread();
12953  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12954  threads.Add( new DSmpThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
12955  if ( threads.Length() > 1 )
12956  {
12957  int n = 0;
12958  for ( DSmpThread& thread : threads )
12959  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12960  for ( DSmpThread& thread : threads )
12961  thread.Wait();
12962  }
12963  else
12964  threads[0].Run();
12965 
12966  Array<double> values;
12967  for ( DSmpThread& thread : threads )
12968  if ( !thread.values.IsEmpty() )
12969  {
12970  values.Add( thread.values.Begin(), thread.values.At( thread.n ) );
12971  thread.values.Clear();
12972  }
12973 
12974  threads.Destroy();
12975 
12976  double sn = pcl::Sn( values.Begin(), values.End() );
12977  m_status += N;
12978  return sn;
12979  }
12980 
13023  double Qn( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1, int maxProcessors = 0 ) const
13024  {
13025  Rect r = rect;
13026  if ( !ParseSelection( r, firstChannel, lastChannel ) )
13027  return 0;
13028 
13029  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
13030  if ( m_status.IsInitializationEnabled() )
13031  m_status.Initialize( "Computing Qn scale estimate", N );
13032 
13033  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
13034  bool useAffinity = m_parallel && Thread::IsRootThread();
13036  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13037  threads.Add( new DSmpThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
13038  if ( threads.Length() > 1 )
13039  {
13040  int n = 0;
13041  for ( DSmpThread& thread : threads )
13042  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13043  for ( DSmpThread& thread : threads )
13044  thread.Wait();
13045  }
13046  else
13047  threads[0].Run();
13048 
13049  Array<double> values;
13050  for ( DSmpThread& thread : threads )
13051  if ( !thread.values.IsEmpty() )
13052  {
13053  values.Add( thread.values.Begin(), thread.values.At( thread.n ) );
13054  thread.values.Clear();
13055  }
13056 
13057  threads.Destroy();
13058 
13059  double qn = pcl::Qn( values.Begin(), values.End() );
13060  m_status += N;
13061  return qn;
13062  }
13063 
13101  double Norm( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
13102  int maxProcessors = 0 ) const
13103  {
13104  Rect r = rect;
13105  if ( !ParseSelection( r, firstChannel, lastChannel ) )
13106  return 0;
13107 
13108  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
13109  if ( m_status.IsInitializationEnabled() )
13110  m_status.Initialize( "Computing norm", N );
13111 
13112  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
13113  bool useAffinity = m_parallel && Thread::IsRootThread();
13114  ReferenceArray<SumThread> threads;
13115  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13116  threads.Add( new SumThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
13117  if ( threads.Length() > 1 )
13118  {
13119  int n = 0;
13120  for ( SumThread& thread : threads )
13121  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13122  for ( SumThread& thread : threads )
13123  thread.Wait();
13124  }
13125  else
13126  threads[0].Run();
13127 
13128  double s = 0;
13129  double e = 0;
13130  for ( const SumThread& thread : threads )
13131  {
13132  double y = thread.s - e;
13133  double t = s + y;
13134  e = (t - s) - y;
13135  s = t;
13136  }
13137 
13138  threads.Destroy();
13139  m_status += N;
13140  return (1 + s != 1) ? s : 0.0; // don't return insignificant nonzero values
13141  }
13142 
13173  double Modulus( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
13174  int maxProcessors = 0 ) const
13175  {
13176  Rect r = rect;
13177  if ( !ParseSelection( r, firstChannel, lastChannel ) )
13178  return 0;
13179 
13180  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
13181  if ( m_status.IsInitializationEnabled() )
13182  m_status.Initialize( "Computing modulus", N );
13183 
13184  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
13185  bool useAffinity = m_parallel && Thread::IsRootThread();
13187  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13188  threads.Add( new SumAbsThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
13189  if ( threads.Length() > 1 )
13190  {
13191  int n = 0;
13192  for ( SumAbsThread& thread : threads )
13193  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13194  for ( SumAbsThread& thread : threads )
13195  thread.Wait();
13196  }
13197  else
13198  threads[0].Run();
13199 
13200  double s = 0;
13201  double e = 0;
13202  for ( const SumAbsThread& thread : threads )
13203  {
13204  double y = thread.s - e;
13205  double t = s + y;
13206  e = (t - s) - y;
13207  s = t;
13208  }
13209 
13210  threads.Destroy();
13211  m_status += N;
13212  return (1 + s != 1) ? s : 0.0; // don't return insignificant nonzero values
13213  }
13214 
13243  double SumOfSquares( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
13244  int maxProcessors = 0 ) const
13245  {
13246  Rect r = rect;
13247  if ( !ParseSelection( r, firstChannel, lastChannel ) )
13248  return 0;
13249 
13250  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
13251  if ( m_status.IsInitializationEnabled() )
13252  m_status.Initialize( "Computing sum of squares", N );
13253 
13254  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
13255  bool useAffinity = m_parallel && Thread::IsRootThread();
13257  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13258  threads.Add( new SumSqrThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
13259  if ( threads.Length() > 1 )
13260  {
13261  int n = 0;
13262  for ( SumSqrThread& thread : threads )
13263  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13264  for ( SumSqrThread& thread : threads )
13265  thread.Wait();
13266  }
13267  else
13268  threads[0].Run();
13269 
13270  double s = 0;
13271  double e = 0;
13272  for ( const SumSqrThread& thread : threads )
13273  {
13274  double y = thread.s - e;
13275  double t = s + y;
13276  e = (t - s) - y;
13277  s = t;
13278  }
13279 
13280  threads.Destroy();
13281  m_status += N;
13282  return (1 + s != 1) ? s : 0.0; // don't return insignificant nonzero values
13283  }
13284 
13313  double MeanOfSquares( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
13314  int maxProcessors = 0 ) const
13315  {
13316  Rect r = rect;
13317  if ( !ParseSelection( r, firstChannel, lastChannel ) )
13318  return 0;
13319 
13320  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
13321  if ( m_status.IsInitializationEnabled() )
13322  m_status.Initialize( "Computing mean of squares", N );
13323 
13324  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
13325  bool useAffinity = m_parallel && Thread::IsRootThread();
13327  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13328  threads.Add( new SumSqrThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
13329  if ( threads.Length() > 1 )
13330  {
13331  int n = 0;
13332  for ( SumSqrThread& thread : threads )
13333  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13334  for ( SumSqrThread& thread : threads )
13335  thread.Wait();
13336  }
13337  else
13338  threads[0].Run();
13339 
13340  double s = 0;
13341  double e = 0;
13342  size_type n = 0;
13343  for ( const SumSqrThread& thread : threads )
13344  {
13345  double y = thread.s - e;
13346  double t = s + y;
13347  e = (t - s) - y;
13348  s = t;
13349  n += thread.n;
13350  }
13351 
13352  threads.Destroy();
13353 
13354  m_status += N;
13355 
13356  if ( n < 1 )
13357  return 0;
13358  return s/n;
13359  }
13360 
13398  Vector Norms( int maxDegree = 2, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
13399  int maxProcessors = 0 ) const
13400  {
13401  PCL_PRECONDITION( maxDegree > 0 )
13402  maxDegree = pcl::Max( 1, maxDegree );
13403 
13404  Rect r = rect;
13405  if ( !ParseSelection( r, firstChannel, lastChannel ) )
13406  return 0;
13407 
13408  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
13409  if ( m_status.IsInitializationEnabled() )
13410  m_status.Initialize( "Computing norms", N );
13411 
13412  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
13413  bool useAffinity = m_parallel && Thread::IsRootThread();
13415  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13416  threads.Add( new NormThread( *this, maxDegree, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
13417  if ( threads.Length() > 1 )
13418  {
13419  int n = 0;
13420  for ( NormThread& thread : threads )
13421  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13422  for ( NormThread& thread : threads )
13423  thread.Wait();
13424  }
13425  else
13426  threads[0].Run();
13427 
13428  Vector R( 0.0, maxDegree );
13429  Vector e( 0.0, maxDegree );
13430  for ( const NormThread& thread : threads )
13431  for ( int i = 0; i < maxDegree; ++i )
13432  {
13433  double y = thread.R[i] - e[i];
13434  double t = R[i] + y;
13435  e[i] = (t - R[i]) - y;
13436  R[i] = t;
13437  }
13438  for ( int i = 0; i < maxDegree; ++i )
13439  if ( 1 + R[i] == 1 ) // don't return insignificant nonzero values
13440  R[i] = 0;
13441 
13442  threads.Destroy();
13443  m_status += N;
13444  return R;
13445  }
13446 
13459  uint64 Hash64( int channel = -1, uint64 seed = 0 ) const noexcept
13460  {
13461  if ( !ParseChannel( channel ) )
13462  return 0;
13463  return pcl::Hash64( m_channelData( channel ), ChannelSize(), seed );
13464  }
13465 
13478  uint32 Hash32( int channel = -1, uint32 seed = 0 ) const noexcept
13479  {
13480  if ( !ParseChannel( channel ) )
13481  return 0;
13482  return pcl::Hash32( m_channelData( channel ), ChannelSize(), seed );
13483  }
13484 
13489  uint64 Hash( int channel = -1, uint64 seed = 0 ) const noexcept
13490  {
13491  return Hash64( channel, seed );
13492  }
13493 
13494  // -------------------------------------------------------------------------
13495 
13513  GenericImage& Write( File& file, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
13514  {
13515  Rect r = rect;
13516  if ( !ParseSelection( r, firstChannel, lastChannel ) )
13517  return const_cast<GenericImage&>( *this );
13518 
13519  size_type N = size_type( r.Width() )*size_type( r.Height() );
13520  int numberOfChannels = 1 + lastChannel - firstChannel;
13521 
13522  if ( m_status.IsInitializationEnabled() )
13523  m_status.Initialize( "Writing to raw-storage image stream", N*numberOfChannels );
13524 
13525  file.WriteUI32( r.Width() );
13526  file.WriteUI32( r.Height() );
13527  file.WriteUI32( numberOfChannels );
13528  file.WriteUI32( (firstChannel == 0 && lastChannel >= 2) ? m_colorSpace : ColorSpace::Gray );
13529 
13530  if ( r == Bounds() )
13531  {
13532  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
13533  file.Write( (const void*)m_pixelData[i], fsize_type( ChannelSize() ) );
13534  }
13535  else
13536  {
13537  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i )
13538  {
13539  const sample* p = PixelAddress( r.LeftTop(), i );
13540  for ( int j = 0; j < h; ++j, p += m_width, m_status += w )
13541  file.Write( (const void*)p, w*BytesPerSample() );
13542  }
13543  }
13544 
13545  return const_cast<GenericImage&>( *this );
13546  }
13547 
13558  GenericImage& Write( const String& filePath,
13559  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
13560  {
13561  File file = File::CreateFileForWriting( filePath );
13562  return Write( file, rect, firstChannel, lastChannel );
13563  }
13564 
13602  {
13603  int width, height, numberOfChannels, colorSpace;
13604  file.ReadUI32( width );
13605  file.ReadUI32( height );
13606  file.ReadUI32( numberOfChannels );
13607  file.ReadUI32( colorSpace );
13608 
13609  AllocateData( width, height, numberOfChannels, color_space( colorSpace ) );
13610 
13611  ResetSelections();
13612 
13613  size_type N = NumberOfPixels();
13614  if ( N > 0 )
13615  {
13616  if ( m_status.IsInitializationEnabled() )
13617  m_status.Initialize( "Reading from raw-storage image stream", N*m_numberOfChannels );
13618  for ( int i = 0; i < m_numberOfChannels; ++i, m_status += N )
13619  file.Read( (void*)m_pixelData[i], fsize_type( ChannelSize() ) );
13620  }
13621 
13622  return *this;
13623  }
13624 
13636  GenericImage& Read( const String& filePath )
13637  {
13638  File file = File::OpenFileForReading( filePath );
13639  return Read( file );
13640  }
13641 
13642  // -------------------------------------------------------------------------
13643 
13674  template <typename T>
13675  GenericImage& CropBy( int left, int top, int right, int bottom, const GenericVector<T>& fillValues )
13676  {
13677  if ( left == 0 && top == 0 && right == 0 && bottom == 0 )
13678  return *this;
13679 
13680  if ( m_width+left+right <= 0 || m_height+top+bottom <= 0 )
13681  {
13682  FreeData();
13683  return *this;
13684  }
13685 
13686  Rect r( -left, -top, m_width+right, m_height+bottom );
13687  int width = r.Width();
13688  int height = r.Height();
13689 
13690  if ( !Intersects( r ) )
13691  return AllocateData( width, height, m_numberOfChannels, m_colorSpace ).Fill( fillValues );
13692 
13693  size_type N = size_type( width )*size_type( height );
13694 
13695  EnsureUnique();
13696 
13697  if ( m_status.IsInitializationEnabled() )
13698  m_status.Initialize( String().Format( "Crop margins: %+d, %+d, %+d, %+d",
13699  left, top, right, bottom ), N*m_numberOfChannels );
13700 
13701  sample** newData = nullptr;
13702 
13703  try
13704  {
13705  newData = m_allocator.AllocateChannelSlots( m_numberOfChannels );
13706 
13707  for ( int c = 0; c < m_numberOfChannels; ++c, m_status += N )
13708  {
13709  sample* __restrict__ f = newData[c] = m_allocator.AllocatePixels( N );
13710  sample v = (c < fillValues.Length()) ? P::ToSample( fillValues[c] ) : P::MinSampleValue();
13711 
13712  for ( int i = r.y0, j; i < r.y1; )
13713  {
13714  for ( ; i < 0; ++i )
13715  {
13716  PCL_IVDEP
13717  for ( int j = 0; j < width; ++j )
13718  *f++ = v;
13719  }
13720 
13721  PCL_IVDEP
13722  for ( j = r.x0; j < 0; ++j )
13723  *f++ = v;
13724 
13725  for ( const sample* f0 = PixelAddress( j, i, c ); j < r.x1; )
13726  {
13727  *f++ = *f0++;
13728  if ( ++j == m_width )
13729  {
13730  PCL_IVDEP
13731  for ( ; j < r.x1; ++j )
13732  *f++ = v;
13733  }
13734  }
13735 
13736  if ( ++i == m_height )
13737  for ( ; i < r.y1; ++i )
13738  {
13739  PCL_IVDEP
13740  for ( int j = 0; j < width; ++j )
13741  *f++ = v;
13742  }
13743  }
13744  }
13745 
13746  try
13747  {
13748  for ( int c = 0; c < m_numberOfChannels; ++c )
13749  {
13750  m_allocator.Deallocate( m_pixelData[c] );
13751  m_pixelData[c] = newData[c];
13752  }
13753  m_allocator.Deallocate( newData );
13754  newData = nullptr;
13755 
13756  m_allocator.SetSharedGeometry( m_width = width, m_height = height, m_numberOfChannels );
13757 
13758  ResetPoint();
13759  ResetSelection();
13760  return *this;
13761  }
13762  catch ( ... )
13763  {
13764  m_data->Deallocate();
13765  ResetSelections();
13766  throw;
13767  }
13768  }
13769  catch ( ... )
13770  {
13771  if ( newData != nullptr )
13772  {
13773  for ( int i = 0; i < m_numberOfChannels; ++i )
13774  if ( newData[i] != nullptr )
13775  m_allocator.Deallocate( newData[i] ), newData[i] = nullptr;
13776  m_allocator.Deallocate( newData );
13777  }
13778  throw;
13779  }
13780  }
13781 
13793  GenericImage& CropBy( int left, int top, int right, int bottom )
13794  {
13795  return CropBy( left, top, right, bottom, sample_vector() );
13796  }
13797 
13808  template <typename T>
13809  GenericImage& CropTo( const Rect& rect, const GenericVector<T>& fillValues )
13810  {
13811  Rect r = rect.Ordered();
13812  return CropBy( -r.x0, -r.y0, r.x1 - m_width, r.y1 - m_height, fillValues );
13813  }
13814 
13826  GenericImage& CropTo( const Rect& rect )
13827  {
13828  return CropTo( rect, sample_vector() );
13829  }
13830 
13841  template <typename T>
13842  GenericImage& CropTo( int x0, int y0, int x1, int y1, const GenericVector<T>& fillValues )
13843  {
13844  return CropTo( Rect( x0, y0, x1, y1 ), fillValues );
13845  }
13846 
13858  GenericImage& CropTo( int x0, int y0, int x1, int y1 )
13859  {
13860  return CropTo( x0, y0, x1, y1, sample_vector() );
13861  }
13862 
13873  template <typename T>
13874  GenericImage& Crop( const GenericVector<T>& fillValues )
13875  {
13876  return CropTo( m_rectangle, fillValues );
13877  }
13878 
13891  {
13892  return Crop( sample_vector() );
13893  }
13894 
13916  template <typename T>
13917  GenericImage& ShiftBy( int dx, int dy, const GenericVector<T>& fillValues )
13918  {
13919  return CropBy( dx, dy, -dx, -dy, fillValues );
13920  }
13921 
13933  GenericImage& ShiftBy( int dx, int dy )
13934  {
13935  return ShiftBy( dx, dy, sample_vector() );
13936  }
13937 
13944  template <typename T>
13945  GenericImage& ShiftTo( int x, int y, const GenericVector<T>& fillValues )
13946  {
13947  return ShiftBy( x, y, fillValues );
13948  }
13949 
13961  GenericImage& ShiftTo( int x, int y )
13962  {
13963  return ShiftTo( x, y, sample_vector() );
13964  }
13965 
13976  template <typename T>
13977  GenericImage& ShiftTo( const Point& p, const GenericVector<T>& fillValues )
13978  {
13979  return ShiftBy( p.x, p.y, fillValues );
13980  }
13981 
13994  {
13995  return ShiftTo( p, sample_vector() );
13996  }
13997 
14002  template <typename T>
14003  GenericImage& ShiftToCenter( int width, int height, const GenericVector<T>& fillValues )
14004  {
14005  int dx2 = (width - m_width) >> 1;
14006  int dy2 = (height - m_height) >> 1;
14007  return CropBy( dx2, dy2, width-m_width-dx2, height-m_height-dy2, fillValues );
14008  }
14009 
14022  GenericImage& ShiftToCenter( int width, int height )
14023  {
14024  return ShiftToCenter( width, height, sample_vector() );
14025  }
14026 
14031  template <typename T>
14032  GenericImage& ShiftToTopLeft( int width, int height, const GenericVector<T>& fillValues )
14033  {
14034  int dx = width - m_width;
14035  int dy = height - m_height;
14036  return CropBy( 0, 0, dx, dy, fillValues );
14037  }
14038 
14051  GenericImage& ShiftToTopLeft( int width, int height )
14052  {
14053  return ShiftToTopLeft( width, height, sample_vector() );
14054  }
14055 
14060  template <typename T>
14061  GenericImage& ShiftToTopRight( int width, int height, const GenericVector<T>& fillValues )
14062  {
14063  int dx = width - m_width;
14064  int dy = height - m_height;
14065  return CropBy( dx, 0, 0, dy, fillValues );
14066  }
14067 
14080  GenericImage& ShiftToTopRight( int width, int height )
14081  {
14082  return ShiftToTopRight( width, height, sample_vector() );
14083  }
14084 
14089  template <typename T>
14090  GenericImage& ShiftToBottomLeft( int width, int height, const GenericVector<T>& fillValues )
14091  {
14092  int dx = width - m_width;
14093  int dy = height - m_height;
14094  return CropBy( 0, dy, dx, 0, fillValues );
14095  }
14096 
14109  GenericImage& ShiftToBottomLeft( int width, int height )
14110  {
14111  return ShiftToBottomLeft( width, height, sample_vector() );
14112  }
14113 
14118  template <typename T>
14119  GenericImage& ShiftToBottomRight( int width, int height, const GenericVector<T>& fillValues )
14120  {
14121  int dx = width - m_width;
14122  int dy = height - m_height;
14123  return CropBy( dx, dy, 0, 0, fillValues );
14124  }
14125 
14138  GenericImage& ShiftToBottomRight( int width, int height )
14139  {
14140  return ShiftToBottomRight( width, height, sample_vector() );
14141  }
14142 
14153  template <typename T>
14154  GenericImage& Shift( const GenericVector<T>& fillValues )
14155  {
14156  return ShiftTo( m_point, fillValues );
14157  }
14158 
14171  {
14172  return Shift( sample_vector() );
14173  }
14174 
14175  // -------------------------------------------------------------------------
14176 
14210  GenericImage& SetColorSpace( color_space colorSpace, int maxProcessors = 0 )
14211  {
14212  size_type N = NumberOfPixels();
14213  if ( N == 0 )
14214  return *this;
14215 
14216  if ( colorSpace == m_colorSpace )
14217  {
14218  m_status += N;
14219  return *this;
14220  }
14221 
14222  EnsureUnique();
14223 
14224  if ( m_status.IsInitializationEnabled() )
14225  m_status.Initialize( "In-place color space conversion: "
14226  + ColorSpace::Name( m_colorSpace )
14227  + " -> "
14228  + ColorSpace::Name( colorSpace ), N );
14229 
14230  int n = m_numberOfChannels;
14231 
14232  if ( m_colorSpace == ColorSpace::Gray )
14233  {
14234  sample** oldData = m_pixelData;
14235  sample** newData = nullptr;
14236 
14237  try
14238  {
14239  // Make room for the G and B channels.
14240  newData = m_allocator.AllocateChannelSlots( 2+n );
14241 
14242  // Put the nominal gray channel into the R slot
14243  newData[0] = oldData[0];
14244 
14245  // Allocate and copy the G and B channels
14246  newData[1] = m_allocator.AllocatePixels( N );
14247  ::memcpy( newData[1], oldData[0], ChannelSize() );
14248  newData[2] = m_allocator.AllocatePixels( N );
14249  ::memcpy( newData[2], oldData[0], ChannelSize() );
14250 
14251  // Put existing alpha channels in their corresponding slots
14252  for ( int i = 1; i < n; ++i )
14253  newData[i+2] = oldData[i];
14254 
14255  try
14256  {
14257  m_pixelData = newData;
14258  newData = nullptr;
14259  m_numberOfChannels += 2;
14260  m_colorSpace = ColorSpace::RGB;
14261  m_data->UpdateSharedImage();
14262 
14263  ResetChannelRange();
14264 
14265  m_allocator.Deallocate( oldData );
14266  }
14267  catch ( ... )
14268  {
14269  m_data->Deallocate();
14270  ResetSelections();
14271  throw;
14272  }
14273  }
14274  catch ( ... )
14275  {
14276  if ( newData != nullptr )
14277  {
14278  newData[0] = nullptr;
14279  if ( newData[1] != nullptr )
14280  m_allocator.Deallocate( newData[1] ), newData[1] = nullptr;
14281  if ( newData[2] != nullptr )
14282  m_allocator.Deallocate( newData[2] ), newData[2] = nullptr;
14283  m_allocator.Deallocate( newData );
14284  throw;
14285  }
14286  }
14287 
14288  if ( colorSpace == ColorSpace::RGB )
14289  {
14290  m_status += N;
14291  return *this;
14292  }
14293 
14294  n += 2;
14295  }
14296 
14297  Array<size_type> L = Thread::OptimalThreadLoads( N,
14298  16u/*overheadLimit*/,
14299  m_parallel ? ((maxProcessors > 0) ? maxProcessors : m_maxProcessors) : 1 );
14300  ThreadData data( *this, N );
14302  for ( size_type i = 0, n = 0; i < L.Length(); n += L[i++] )
14303  threads.Add( new ColorSpaceConversionThread( *this, data, colorSpace, n, n + L[i] ) );
14304  RunThreads( threads, data );
14305  threads.Destroy();
14306 
14307  m_status = data.status;
14308 
14309  if ( colorSpace == ColorSpace::Gray )
14310  {
14311  sample** oldData = m_pixelData;
14312  sample** newData = nullptr;
14313 
14314  try
14315  {
14316  newData = m_allocator.AllocateChannelSlots( n-2 );
14317  newData[0] = oldData[0];
14318  for ( int i = 3; i < n; ++i )
14319  newData[i-2] = oldData[i];
14320 
14321  m_pixelData = newData;
14322  newData = nullptr;
14323  m_numberOfChannels -= 2;
14324  m_colorSpace = ColorSpace::Gray;
14325  m_data->UpdateSharedImage();
14326 
14327  ResetChannelRange();
14328 
14329  m_allocator.Deallocate( oldData[1] );
14330  m_allocator.Deallocate( oldData[2] );
14331  m_allocator.Deallocate( oldData );
14332  }
14333  catch ( ... )
14334  {
14335  m_data->Deallocate();
14336  ResetSelections();
14337  if ( newData != nullptr )
14338  m_allocator.Deallocate( newData );
14339  throw;
14340  }
14341  }
14342  else
14343  {
14344  m_allocator.SetSharedColor( m_colorSpace = colorSpace, m_RGBWS );
14345  }
14346 
14347  return *this;
14348  }
14349 
14350  // -------------------------------------------------------------------------
14351 
14417  template <class P1>
14418  void GetLuminance( GenericImage<P1>& Y, const Rect& rect = Rect( 0 ), int maxProcessors = 0 ) const
14419  {
14420  Rect r = rect;
14421  if ( !ParseRect( r ) )
14422  {
14423  Y.FreeData();
14424  return;
14425  }
14426 
14427  Y.AllocateData( r );
14428  if ( !Y.IsShared() )
14429  Y.SetRGBWorkingSpace( m_RGBWS );
14430 
14431  size_type N = Y.NumberOfPixels();
14432 
14433  if ( m_colorSpace == ColorSpace::Gray || m_colorSpace == ColorSpace::CIEXYZ )
14434  {
14435  if ( m_status.IsInitializationEnabled() )
14436  m_status.Initialize( "Transferring pixel data", N );
14437 
14438  typename GenericImage<P1>::sample* __restrict__ g = *Y;
14439  int cY = (m_colorSpace == ColorSpace::Gray) ? 0 : 1;
14440  if ( r == Bounds() )
14441  {
14442  const sample* __restrict__ f = m_pixelData[cY];
14443  P1::Copy( g, f, N );
14444  }
14445  else
14446  {
14447  const sample* __restrict__ f = PixelAddress( r.LeftTop(), cY );
14448  for ( int i = 0; i < Y.Height(); ++i, f += m_width, g += Y.Width() )
14449  P1::Copy( g, f, Y.Width() );
14450  }
14451 
14452  m_status += N;
14453  }
14454  else
14455  {
14456  if ( m_status.IsInitializationEnabled() )
14457  m_status.Initialize( "Computing CIE Y component", N );
14458 
14459  Array<size_type> L = OptimalThreadRows( Y.Height(), Y.Width(), maxProcessors );
14460  ThreadData data( *this, N );
14462  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
14463  threads.Add( new GetLuminanceThread<P1>( Y, *this, data, r, n, n + int( L[i] ) ) );
14464  RunThreads( threads, data );
14465  threads.Destroy();
14466 
14467  m_status = data.status;
14468  }
14469  }
14470 
14480  void GetLuminance( ImageVariant& Y, const Rect& rect = Rect( 0 ), int maxProcessors = 0 ) const;
14481  // Implemented in pcl/ImageVariant.h
14482 
14549  template <class P1>
14550  void GetLightness( GenericImage<P1>& L, const Rect& rect = Rect( 0 ), int maxProcessors = 0 ) const
14551  {
14552  Rect r = rect;
14553  if ( !ParseRect( r ) )
14554  {
14555  L.FreeData();
14556  return;
14557  }
14558 
14559  L.AllocateData( r );
14560  if ( !L.IsShared() )
14561  L.SetRGBWorkingSpace( m_RGBWS );
14562 
14563  size_type N = L.NumberOfPixels();
14564 
14565  if ( m_colorSpace == ColorSpace::Gray || m_colorSpace == ColorSpace::CIELab || m_colorSpace == ColorSpace::CIELch )
14566  {
14567  if ( m_status.IsInitializationEnabled() )
14568  m_status.Initialize( "Transferring pixel data", N );
14569 
14570  typename GenericImage<P1>::sample* g = *L;
14571  if ( r == Bounds() )
14572  {
14573  const sample* __restrict__ f = *m_pixelData;
14574  P1::Copy( g, f, N );
14575  }
14576  else
14577  {
14578  const sample* __restrict__ f = PixelAddress( r.LeftTop() );
14579  for ( int i = 0; i < L.Height(); ++i, f += m_width, g += L.Width() )
14580  P1::Copy( g, f, L.Width() );
14581  }
14582 
14583  m_status += N;
14584  }
14585  else
14586  {
14587  if ( m_status.IsInitializationEnabled() )
14588  m_status.Initialize( "Computing CIE L* component", N );
14589 
14590  Array<size_type> R = OptimalThreadRows( L.Height(), L.Width(), maxProcessors );
14591  ThreadData data( *this, N );
14593  for ( int i = 0, n = 0; i < int( R.Length() ); n += int( R[i++] ) )
14594  threads.Add( new GetLightnessThread<P1>( L, *this, data, r, n, n + int( R[i] ) ) );
14595  RunThreads( threads, data );
14596  threads.Destroy();
14597 
14598  m_status = data.status;
14599  }
14600  }
14601 
14611  void GetLightness( ImageVariant& L, const Rect& rect = Rect( 0 ), int maxProcessors = 0 ) const;
14612  // Implemented in pcl/ImageVariant.h
14613 
14672  template <class P1>
14673  void GetIntensity( GenericImage<P1>& I, const Rect& rect = Rect( 0 ), int maxProcessors = 0 ) const
14674  {
14675  Rect r = rect;
14676  if ( !ParseRect( r ) )
14677  {
14678  I.FreeData();
14679  return;
14680  }
14681 
14682  I.AllocateData( r );
14683  if ( !I.IsShared() )
14684  I.SetRGBWorkingSpace( m_RGBWS );
14685 
14686  size_type N = I.NumberOfPixels();
14687 
14688  if ( m_colorSpace == ColorSpace::Gray || m_colorSpace == ColorSpace::HSI )
14689  {
14690  if ( m_status.IsInitializationEnabled() )
14691  m_status.Initialize( "Transferring pixel data", N );
14692 
14693  typename GenericImage<P1>::sample* __restrict__ g = *I;
14694  int cI = (m_colorSpace == ColorSpace::Gray) ? 0 : 2;
14695  if ( r == Bounds() )
14696  {
14697  const sample* __restrict__ f = m_pixelData[cI];
14698  P1::Copy( g, f, N );
14699  }
14700  else
14701  {
14702  const sample* __restrict__ f = PixelAddress( r.LeftTop(), cI );
14703  for ( int i = 0; i < I.Height(); ++i, f += m_width, g += I.Width() )
14704  P1::Copy( g, f, I.Width() );
14705  }
14706 
14707  m_status += N;
14708  }
14709  else
14710  {
14711  if ( m_status.IsInitializationEnabled() )
14712  m_status.Initialize( "Computing intensity component", N );
14713 
14714  Array<size_type> L = OptimalThreadRows( I.Height(), I.Width(), maxProcessors );
14715  ThreadData data( *this, N );
14717  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
14718  threads.Add( new GetIntensityThread<P1>( I, *this, data, r, n, n + int( L[i] ) ) );
14719  RunThreads( threads, data );
14720  threads.Destroy();
14721 
14722  m_status = data.status;
14723  }
14724  }
14725 
14735  void GetIntensity( ImageVariant& I, const Rect& rect = Rect( 0 ), int maxProcessors = 0 ) const;
14736  // Implemented in pcl/ImageVariant.h
14737 
14738  // -------------------------------------------------------------------------
14739 
14798  template <class P1>
14800  const Point& point = Point( int_max ), const Rect& rect = Rect( 0 ),
14801  int maxProcessors = 0 )
14802  {
14803  Rect r = rect;
14804  if ( !Y.ParseRect( r ) )
14805  return *this;
14806 
14807  Point p = point;
14808  if ( p.x == int_max || p.y == int_max )
14809  p = m_point;
14810 
14811  if ( p.x < 0 )
14812  {
14813  if ( (r.x0 -= p.x) >= r.x1 )
14814  return *this;
14815  p.x = 0;
14816  }
14817  else if ( p.x >= m_width )
14818  return *this;
14819 
14820  if ( p.y < 0 )
14821  {
14822  if ( (r.y0 -= p.y) >= r.y1 )
14823  return *this;
14824  p.y = 0;
14825  }
14826  else if ( p.y >= m_height )
14827  return *this;
14828 
14829  r.ResizeTo( pcl::Min( m_width - p.x, r.Width() ),
14830  pcl::Min( m_height - p.y, r.Height() ) );
14831 
14832  size_type N = size_type( r.Width() )*size_type( r.Height() );
14833 
14834  EnsureUnique();
14835 
14836  if ( m_colorSpace == ColorSpace::Gray &&
14837  (Y.ColorSpace() == ColorSpace::Gray || Y.ColorSpace() == ColorSpace::CIEXYZ) )
14838  {
14839  if ( m_status.IsInitializationEnabled() )
14840  m_status.Initialize( "Transferring pixel data", N );
14841 
14842  int c0 = (Y.ColorSpace() == ColorSpace::Gray) ? 0 : 1;
14843  const typename GenericImage<P1>::sample* __restrict__ g = Y.PixelAddress( r.LeftTop(), c0 );
14844  sample* __restrict__ f = PixelAddress( p );
14845  for ( int i = 0, w = r.Width(), h = r.Height(); i < h; ++i, f += m_width, g += Y.Width(), m_status += w )
14846  P::Copy( f, g, w );
14847  }
14848  else
14849  {
14850  if ( m_status.IsInitializationEnabled() )
14851  m_status.Initialize( "Importing CIE Y component", N );
14852 
14853  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
14854  ThreadData data( *this, N );
14856  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
14857  threads.Add( new SetLuminanceThread<P1>( *this, Y, data, p, r, n, n + int( L[i] ) ) );
14858  RunThreads( threads, data );
14859  threads.Destroy();
14860 
14861  m_status = data.status;
14862  }
14863 
14864  return *this;
14865  }
14866 
14876  GenericImage& SetLuminance( const ImageVariant& Y,
14877  const Point& point = Point( int_max ), const Rect& rect = Rect( 0 ),
14878  int maxProcessors = 0 );
14879  // Implemented in pcl/ImageVariant.h
14880 
14939  template <class P1>
14941  const Point& point = Point( int_max ), const Rect& rect = Rect( 0 ),
14942  int maxProcessors = 0 )
14943  {
14944  Rect r = rect;
14945  if ( !L.ParseRect( r ) )
14946  return *this;
14947 
14948  Point p = point;
14949  if ( p.x == int_max || p.y == int_max )
14950  p = m_point;
14951 
14952  if ( p.x < 0 )
14953  {
14954  if ( (r.x0 -= p.x) >= r.x1 )
14955  return *this;
14956  p.x = 0;
14957  }
14958  else if ( p.x >= m_width )
14959  return *this;
14960 
14961  if ( p.y < 0 )
14962  {
14963  if ( (r.y0 -= p.y) >= r.y1 )
14964  return *this;
14965  p.y = 0;
14966  }
14967  else if ( p.y >= m_height )
14968  return *this;
14969 
14970  r.ResizeTo( pcl::Min( m_width - p.x, r.Width() ),
14971  pcl::Min( m_height - p.y, r.Height() ) );
14972 
14973  size_type N = size_type( r.Width() )*size_type( r.Height() );
14974 
14975  EnsureUnique();
14976 
14977  if ( m_colorSpace == ColorSpace::Gray &&
14978  (L.ColorSpace() == ColorSpace::Gray ||
14979  L.ColorSpace() == ColorSpace::CIELab || L.ColorSpace() == ColorSpace::CIELch) )
14980  {
14981  if ( m_status.IsInitializationEnabled() )
14982  m_status.Initialize( "Transferring pixel data", N );
14983 
14984  const typename GenericImage<P1>::sample* __restrict__ g = L.PixelAddress( r.LeftTop() );
14985  sample* __restrict__ f = PixelAddress( p );
14986  for ( int i = 0, w = r.Width(), h = r.Height(); i < h; ++i, f += m_width, g += L.Width(), m_status += w )
14987  P::Copy( f, g, w );
14988  }
14989  else
14990  {
14991  if ( m_status.IsInitializationEnabled() )
14992  m_status.Initialize( "Importing CIE L* component", N );
14993 
14994  Array<size_type> R = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
14995  ThreadData data( *this, N );
14997  for ( int i = 0, n = 0; i < int( R.Length() ); n += int( R[i++] ) )
14998  threads.Add( new SetLightnessThread<P1>( *this, L, data, p, r, n, n + int( R[i] ) ) );
14999  RunThreads( threads, data );
15000  threads.Destroy();
15001 
15002  m_status = data.status;
15003  }
15004 
15005  return *this;
15006  }
15007 
15017  GenericImage& SetLightness( const ImageVariant& L,
15018  const Point& point = Point( int_max ), const Rect& rect = Rect( 0 ),
15019  int maxProcessors = 0 );
15020  // Implemented in pcl/ImageVariant.h
15021 
15061  const Rect& rect = Rect( 0 ), int channel = -1,
15062  Compression::Performance* perf = nullptr ) const
15063  {
15064  Rect r = rect;
15065  if ( !ParseSelection( r, channel ) )
15066  return Compression::subblock_list();
15067  if ( r == Bounds() )
15068  return compressor.Compress( m_channelData( channel ), ChannelSize(), perf );
15069  GenericImage<P> subimage( *this, r, channel, channel );
15070  return compressor.Compress( subimage[0], subimage.ChannelSize(), perf );
15071  }
15072 
15073  // -------------------------------------------------------------------------
15074 
15075 private:
15076 
15082  struct Data : public ReferenceCounter
15083  {
15091  sample** data = nullptr;
15092 
15103  pixel_allocator allocator;
15104 
15108  Geometry geometry;
15109 
15113  Color color;
15114 
15118  Data( GenericImage* image )
15119  {
15120  LinkWithClientImage( image );
15121  }
15122 
15126  Data( GenericImage* image, void* handle )
15127  : allocator( handle )
15128  {
15129  SynchronizeWithSharedImage();
15130  LinkWithClientImage( image );
15131  }
15132 
15136  Data( GenericImage* image, int width, int height, int numberOfChannels, int colorSpace )
15137  : allocator( width, height, numberOfChannels, colorSpace )
15138  {
15139  SynchronizeWithSharedImage();
15140  LinkWithClientImage( image );
15141  }
15142 
15143  void Attach( GenericImage* image )
15144  {
15145  ReferenceCounter::Attach();
15146  LinkWithClientImage( image );
15147  }
15148 
15149  ~Data()
15150  {
15151  if ( IsShared() )
15152  Reset();
15153  else
15154  Deallocate();
15155  }
15156 
15157  bool IsShared() const noexcept
15158  {
15159  return allocator.IsShared();
15160  }
15161 
15162  bool IsEmpty() const noexcept
15163  {
15164  return data == nullptr;
15165  }
15166 
15167  void Allocate( int width, int height, int numberOfChannels, color_space colorSpace )
15168  {
15169  if ( width <= 0 || height <= 0 || numberOfChannels <= 0 )
15170  {
15171  Deallocate();
15172  return;
15173  }
15174 
15175  if ( numberOfChannels < ColorSpace::NumberOfNominalChannels( colorSpace ) )
15176  throw Error( "GenericImage::Data::Allocate(): Insufficient number of channels" );
15177 
15178  if ( data != nullptr )
15179  {
15180  if ( size_type( width )*size_type( height ) == geometry.NumberOfPixels() )
15181  {
15182  if ( numberOfChannels != geometry.numberOfChannels )
15183  {
15184  sample** newData = nullptr;
15185  int m = pcl::Min( geometry.numberOfChannels, numberOfChannels );
15186 
15187  try
15188  {
15189  newData = allocator.AllocateChannelSlots( numberOfChannels );
15190  for ( int i = 0; i < m; ++i )
15191  newData[i] = data[i];
15192  for ( int i = m; i < numberOfChannels; ++i )
15193  newData[i] = allocator.AllocatePixels( width, height );
15194 
15195  try
15196  {
15197  for ( int i = m; i < geometry.numberOfChannels; ++i )
15198  if ( data[i] != nullptr )
15199  allocator.Deallocate( data[i] ), data[i] = nullptr;
15200  allocator.Deallocate( data );
15201  data = newData;
15202  newData = nullptr;
15203  }
15204  catch ( ... )
15205  {
15206  Deallocate();
15207  throw;
15208  }
15209  }
15210  catch ( ... )
15211  {
15212  if ( newData != nullptr )
15213  {
15214  for ( int i = m; i < numberOfChannels; ++i )
15215  if ( newData[i] != nullptr )
15216  allocator.Deallocate( newData[i] ), newData[i] = nullptr;
15217  allocator.Deallocate( newData );
15218  }
15219  throw;
15220  }
15221  }
15222  }
15223  else
15224  {
15225  sample** newData = nullptr;
15226 
15227  try
15228  {
15229  newData = allocator.AllocateChannelSlots( numberOfChannels );
15230  for ( int i = 0; i < numberOfChannels; ++i )
15231  newData[i] = allocator.AllocatePixels( width, height );
15232 
15233  try
15234  {
15235  for ( int i = 0; i < geometry.numberOfChannels; ++i )
15236  if ( data[i] != nullptr )
15237  allocator.Deallocate( data[i] ), data[i] = nullptr;
15238  allocator.Deallocate( data );
15239  data = newData;
15240  newData = nullptr;
15241  }
15242  catch ( ... )
15243  {
15244  Deallocate();
15245  throw;
15246  }
15247  }
15248  catch ( ... )
15249  {
15250  if ( newData != nullptr )
15251  {
15252  for ( int i = 0; i < numberOfChannels; ++i )
15253  if ( newData[i] != nullptr )
15254  allocator.Deallocate( newData[i] ), newData[i] = nullptr;
15255  allocator.Deallocate( newData );
15256  }
15257  throw;
15258  }
15259  }
15260  }
15261  else
15262  {
15263  try
15264  {
15265  data = allocator.AllocateChannelSlots( numberOfChannels );
15266  for ( int i = 0; i < numberOfChannels; ++i )
15267  data[i] = allocator.AllocatePixels( width, height );
15268  }
15269  catch ( ... )
15270  {
15271  if ( data != nullptr )
15272  {
15273  for ( int i = 0; i < numberOfChannels; ++i )
15274  if ( data[i] != nullptr )
15275  allocator.Deallocate( data[i] ), data[i] = nullptr;
15276  allocator.Deallocate( data );
15277  Reset();
15278  }
15279  throw;
15280  }
15281  }
15282 
15283  geometry.width = width;
15284  geometry.height = height;
15285  geometry.numberOfChannels = numberOfChannels;
15286 
15287  color.colorSpace = colorSpace;
15288 
15289  UpdateSharedImage();
15290  }
15291 
15292  void Import( sample** newData, int width, int height, int numberOfChannels, color_space colorSpace )
15293  {
15294  if ( newData != data )
15295  {
15296  Deallocate();
15297 
15298  if ( newData != nullptr && width > 0 && height > 0 && numberOfChannels > 0 )
15299  {
15300  if ( numberOfChannels < ColorSpace::NumberOfNominalChannels( colorSpace ) )
15301  throw Error( "GenericImage::Data::Import(): Insufficient number of channels" );
15302 
15303  data = newData;
15304 
15305  geometry.width = width;
15306  geometry.height = height;
15307  geometry.numberOfChannels = numberOfChannels;
15308 
15309  color.colorSpace = colorSpace;
15310 
15311  UpdateSharedImage();
15312  }
15313  }
15314  }
15315 
15316  sample** Release()
15317  {
15318  sample** oldData = data;
15319  Reset();
15320  UpdateSharedImage();
15321  return oldData;
15322  }
15323 
15324  void Deallocate()
15325  {
15326  if ( data != nullptr )
15327  {
15328  for ( int i = 0; i < geometry.numberOfChannels; ++i )
15329  if ( data[i] != nullptr )
15330  allocator.Deallocate( data[i] ), data[i] = nullptr;
15331  allocator.Deallocate( data );
15332  Reset();
15333  UpdateSharedImage();
15334  }
15335  }
15336 
15337  Data* Clone( GenericImage* image ) const
15338  {
15339  Data* clone = nullptr;
15340  try
15341  {
15342  clone = new Data;
15343 
15344  if ( !IsEmpty() )
15345  {
15346  clone->data = clone->allocator.AllocateChannelSlots( geometry.numberOfChannels );
15347  for ( int i = 0; i < geometry.numberOfChannels; ++i )
15348  {
15349  clone->data[i] = clone->allocator.AllocatePixels( geometry.width, geometry.height );
15350  P::Copy( clone->data[i], data[i], geometry.NumberOfPixels() );
15351  }
15352 
15353  clone->geometry.Assign( geometry );
15354  clone->color.Assign( color );
15355  }
15356 
15357  clone->LinkWithClientImage( image );
15358  return clone;
15359  }
15360  catch ( ... )
15361  {
15362  if ( clone != nullptr )
15363  {
15364  clone->Deallocate();
15365  delete clone;
15366  }
15367  throw;
15368  }
15369  }
15370 
15371  void Reset()
15372  {
15373  data = nullptr;
15374  geometry.Reset();
15375  color.Reset();
15376  }
15377 
15378  void UpdateSharedImage()
15379  {
15380  allocator.SetSharedData( data );
15381  allocator.SetSharedGeometry( geometry.width, geometry.height, geometry.numberOfChannels );
15382  allocator.SetSharedColor( color.colorSpace, color.RGBWS );
15383  }
15384 
15385  void SynchronizeWithSharedImage()
15386  {
15387  data = allocator.GetSharedData();
15388  allocator.GetSharedGeometry( geometry.width, geometry.height, geometry.numberOfChannels );
15389  allocator.GetSharedColor( color.colorSpace, color.RGBWS );
15390  }
15391 
15392  private:
15393 
15394  Data() = default;
15395 
15396  void LinkWithClientImage( GenericImage* image )
15397  {
15398  if ( image != nullptr )
15399  {
15400  image->m_geometry = &geometry;
15401  image->m_color = &color;
15402  }
15403  }
15404  };
15405 
15410  Data* m_data = nullptr;
15411 
15416  void DetachFromData()
15417  {
15418  if ( !m_data->Detach() )
15419  delete m_data;
15420  }
15421 
15422  // -------------------------------------------------------------------------
15423 
15424  class RectThreadBase : public Thread
15425  {
15426  public:
15427 
15428  RectThreadBase( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15429  : m_image( image )
15430  , m_rect( rect )
15431  , m_ch1( ch1 )
15432  , m_ch2( ch2 )
15433  , m_firstRow( firstRow )
15434  , m_endRow( endRow )
15435  {
15436  }
15437 
15438  virtual void Run() = 0;
15439 
15440  protected:
15441 
15442  const GenericImage& m_image;
15443  const Rect& m_rect;
15444  int m_ch1, m_ch2;
15445  int m_firstRow, m_endRow;
15446 
15447  template <class F> void Execute( F process ) noexcept
15448  {
15449  int w = m_rect.Width();
15450  int dw = m_image.Width() - w;
15451 
15452  if ( m_image.IsLowRangeClippingEnabled() )
15453  {
15454  sample clipLow = P::ToSample( m_image.RangeClipLow() );
15455  if ( m_image.IsHighRangeClippingEnabled() )
15456  {
15457  sample clipHigh = P::ToSample( m_image.RangeClipHigh() );
15458  for ( int i = m_ch1; i <= m_ch2; ++i )
15459  {
15460  const sample* __restrict__ f = m_image.PixelAddress( m_rect.x0, m_rect.y0+m_firstRow, i );
15461  for ( int j = m_firstRow; j < m_endRow; ++j, f += dw )
15462  {
15463  PCL_IVDEP
15464  for ( int k = 0; k < w; ++k, ++f )
15465  if ( clipLow < *f )
15466  if ( *f < clipHigh )
15467  process( f );
15468  }
15469  }
15470  }
15471  else
15472  {
15473  for ( int i = m_ch1; i <= m_ch2; ++i )
15474  {
15475  const sample* __restrict__ f = m_image.PixelAddress( m_rect.x0, m_rect.y0+m_firstRow, i );
15476  for ( int j = m_firstRow; j < m_endRow; ++j, f += dw )
15477  {
15478  PCL_IVDEP
15479  for ( int k = 0; k < w; ++k, ++f )
15480  if ( clipLow < *f )
15481  process( f );
15482  }
15483  }
15484  }
15485  }
15486  else if ( m_image.IsHighRangeClippingEnabled() )
15487  {
15488  sample clipHigh = P::ToSample( m_image.RangeClipHigh() );
15489  for ( int i = m_ch1; i <= m_ch2; ++i )
15490  {
15491  const sample* __restrict__ f = m_image.PixelAddress( m_rect.x0, m_rect.y0+m_firstRow, i );
15492  for ( int j = m_firstRow; j < m_endRow; ++j, f += dw )
15493  {
15494  PCL_IVDEP
15495  for ( int k = 0; k < w; ++k, ++f )
15496  if ( *f < clipHigh )
15497  process( f );
15498  }
15499  }
15500  }
15501  else
15502  {
15503  for ( int i = m_ch1; i <= m_ch2; ++i )
15504  {
15505  const sample* __restrict__ f = m_image.PixelAddress( m_rect.x0, m_rect.y0+m_firstRow, i );
15506  for ( int j = m_firstRow; j < m_endRow; ++j, f += dw )
15507  {
15508  PCL_IVDEP
15509  for ( int k = 0; k < w; ++k, ++f )
15510  process( f );
15511  }
15512  }
15513  }
15514  }
15515  };
15516 
15517  // -------------------------------------------------------------------------
15518 
15519  class CountThread : public RectThreadBase
15520  {
15521  public:
15522 
15523  size_type count = 0;
15524 
15525  CountThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15526  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15527  {
15528  }
15529 
15530  void Run() final
15531  {
15532  /*
15533  * N.B. These threads are only used when range clipping is enabled.
15534  */
15535  int w = this->m_rect.Width();
15536  int dw = this->m_image.Width() - w;
15537 
15538  if ( this->m_image.IsLowRangeClippingEnabled() )
15539  {
15540  sample clipLow = P::ToSample( this->m_image.RangeClipLow() );
15541  if ( this->m_image.IsHighRangeClippingEnabled() )
15542  {
15543  sample clipHigh = P::ToSample( this->m_image.RangeClipHigh() );
15544  for ( int i = this->m_ch1; i <= this->m_ch2; ++i )
15545  {
15546  const sample* __restrict__ f = this->m_image.PixelAddress( this->m_rect.x0, this->m_rect.y0+this->m_firstRow, i );
15547  for ( int j = this->m_firstRow; j < this->m_endRow; ++j, f += dw )
15548  {
15549  PCL_IVDEP
15550  for ( int k = 0; k < w; ++k, ++f )
15551  if ( clipLow < *f )
15552  if ( *f < clipHigh )
15553  ++count;
15554  }
15555  }
15556  }
15557  else
15558  {
15559  for ( int i = this->m_ch1; i <= this->m_ch2; ++i )
15560  {
15561  const sample* __restrict__ f = this->m_image.PixelAddress( this->m_rect.x0, this->m_rect.y0+this->m_firstRow, i );
15562  for ( int j = this->m_firstRow; j < this->m_endRow; ++j, f += dw )
15563  {
15564  PCL_IVDEP
15565  for ( int k = 0; k < w; ++k, ++f )
15566  if ( clipLow < *f )
15567  ++count;
15568  }
15569  }
15570  }
15571  }
15572  else if ( this->m_image.IsHighRangeClippingEnabled() )
15573  {
15574  sample clipHigh = P::ToSample( this->m_image.RangeClipHigh() );
15575  for ( int i = this->m_ch1; i <= this->m_ch2; ++i )
15576  {
15577  const sample* __restrict__ f = this->m_image.PixelAddress( this->m_rect.x0, this->m_rect.y0+this->m_firstRow, i );
15578  for ( int j = this->m_firstRow; j < this->m_endRow; ++j, f += dw )
15579  {
15580  PCL_IVDEP
15581  for ( int k = 0; k < w; ++k, ++f )
15582  if ( *f < clipHigh )
15583  ++count;
15584  }
15585  }
15586  }
15587  else // ?! this should not happen
15588  count = size_type( 1 + this->m_ch2 - this->m_ch1 ) * size_type( w ) * size_type( this->m_rect.Height() );
15589  }
15590  };
15591 
15592  // -------------------------------------------------------------------------
15593 
15594  class MinThread : public RectThreadBase
15595  {
15596  public:
15597 
15598  sample min;
15599  size_type count;
15600 
15601  MinThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15602  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15603  {
15604  }
15605 
15606  void Run() final
15607  {
15608  min = P::HighestSampleValue();
15609  count = 0;
15610  this->Execute( [=]( const sample* f )
15611  {
15612  if ( *f < min )
15613  min = *f;
15614  ++count;
15615  } );
15616  }
15617  };
15618 
15619  // -------------------------------------------------------------------------
15620 
15621  class MaxThread : public RectThreadBase
15622  {
15623  public:
15624 
15625  sample max;
15626  size_type count;
15627 
15628  MaxThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15629  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15630  {
15631  }
15632 
15633  void Run() final
15634  {
15635  max = P::LowestSampleValue();
15636  count = 0;
15637  this->Execute( [=]( const sample* f )
15638  {
15639  if ( max < *f )
15640  max = *f;
15641  ++count;
15642  } );
15643  }
15644  };
15645 
15646  // -------------------------------------------------------------------------
15647 
15648  class MinMaxThread : public RectThreadBase
15649  {
15650  public:
15651 
15652  sample min;
15653  sample max;
15654  size_type count;
15655 
15656  MinMaxThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15657  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15658  {
15659  }
15660 
15661  void Run() final
15662  {
15663  min = P::HighestSampleValue();
15664  max = P::LowestSampleValue();
15665  count = 0;
15666  this->Execute( [=]( const sample* f )
15667  {
15668  if ( *f < min )
15669  min = *f;
15670  if ( max < *f )
15671  max = *f;
15672  ++count;
15673  } );
15674  }
15675  };
15676 
15677  // -------------------------------------------------------------------------
15678 
15679  class ExtremePosThreadBase : public RectThreadBase
15680  {
15681  public:
15682 
15683  int cmin, cmax;
15684  Point pmin, pmax;
15685  size_type count;
15686 
15687  ExtremePosThreadBase( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15688  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15689  {
15690  }
15691 
15692  void Run() final
15693  {
15694  count = 0;
15695  m_amin = m_amax = nullptr;
15696  DoExecute();
15697 
15698  if ( count > 0 )
15699  {
15700  if ( m_amin != 0 )
15701  for ( int i = this->m_ch1; i <= this->m_ch2; ++i )
15702  if ( m_amin >= this->m_image[i] && m_amin < (this->m_image[i] + this->m_image.NumberOfPixels()) )
15703  {
15704  cmin = i;
15705  pmin.x = (m_amin - this->m_image[i]) % this->m_image.Width();
15706  pmin.y = (m_amin - this->m_image[i]) / this->m_image.Width();
15707  break;
15708  }
15709  if ( m_amax != 0 )
15710  for ( int i = this->m_ch1; i <= this->m_ch2; ++i )
15711  if ( m_amax >= this->m_image[i] && m_amax < (this->m_image[i] + this->m_image.NumberOfPixels()) )
15712  {
15713  cmax = i;
15714  pmax.x = (m_amax - this->m_image[i]) % this->m_image.Width();
15715  pmax.y = (m_amax - this->m_image[i]) / this->m_image.Width();
15716  break;
15717  }
15718  }
15719  }
15720 
15721  protected:
15722 
15723  const sample* m_amin;
15724  const sample* m_amax;
15725 
15726  virtual void DoExecute() = 0;
15727  };
15728 
15729  // -------------------------------------------------------------------------
15730 
15731  class MinPosThread : public ExtremePosThreadBase
15732  {
15733  public:
15734 
15735  sample min;
15736 
15737  MinPosThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15738  : ExtremePosThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15739  {
15740  }
15741 
15742  private:
15743 
15744  void DoExecute() override
15745  {
15746  min = P::HighestSampleValue();
15747  this->Execute( [=]( const sample* f )
15748  {
15749  if ( *f < min )
15750  min = *(this->m_amin = f);
15751  ++this->count;
15752  } );
15753  }
15754  };
15755 
15756  // -------------------------------------------------------------------------
15757 
15758  class MaxPosThread : public ExtremePosThreadBase
15759  {
15760  public:
15761 
15762  sample max;
15763 
15764  MaxPosThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15765  : ExtremePosThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15766  {
15767  }
15768 
15769  private:
15770 
15771  void DoExecute() override
15772  {
15773  max = P::LowestSampleValue();
15774  this->Execute( [=]( const sample* f )
15775  {
15776  if ( max < *f )
15777  max = *(this->m_amax = f);
15778  ++this->count;
15779  } );
15780  }
15781  };
15782 
15783  // -------------------------------------------------------------------------
15784 
15785  class MinMaxPosThread : public ExtremePosThreadBase
15786  {
15787  public:
15788 
15789  sample min, max;
15790 
15791  MinMaxPosThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15792  : ExtremePosThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15793  {
15794  }
15795 
15796  private:
15797 
15798  void DoExecute() override
15799  {
15800  min = P::HighestSampleValue();
15801  max = P::LowestSampleValue();
15802  this->Execute( [=]( const sample* f )
15803  {
15804  if ( *f < min )
15805  min = *(this->m_amin = f);
15806  if ( max < *f )
15807  max = *(this->m_amax = f);
15808  ++this->count;
15809  } );
15810  }
15811  };
15812 
15813  // -------------------------------------------------------------------------
15814 
15815  class SumThread : public RectThreadBase
15816  {
15817  public:
15818 
15819  double s;
15820  size_type n;
15821 
15822  SumThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15823  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15824  {
15825  }
15826 
15827  void Run() final
15828  {
15829  s = e = 0;
15830  n = 0;
15831  DoExecute();
15832  }
15833 
15834  protected:
15835 
15836  double e;
15837 
15838  void SumStep( double x ) noexcept
15839  {
15840  double y = x - e;
15841  double t = s + y;
15842  e = (t - s) - y;
15843  s = t;
15844  ++n;
15845  }
15846 
15847  virtual void DoExecute()
15848  {
15849  this->Execute( [=]( const sample* f )
15850  {
15851  double v; P::FromSample( v, *f );
15852  SumStep( v );
15853  } );
15854  }
15855  };
15856 
15857  // -------------------------------------------------------------------------
15858 
15859  class SumSqrThread : public SumThread
15860  {
15861  public:
15862 
15863  SumSqrThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15864  : SumThread( image, rect, ch1, ch2, firstRow, endRow )
15865  {
15866  }
15867 
15868  private:
15869 
15870  void DoExecute() override
15871  {
15872  this->Execute( [=]( const sample* f )
15873  {
15874  double v; P::FromSample( v, *f );
15875  this->SumStep( v*v );
15876  } );
15877  }
15878  };
15879 
15880  // -------------------------------------------------------------------------
15881 
15882  class SumAbsThread : public SumThread
15883  {
15884  public:
15885 
15886  SumAbsThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15887  : SumThread( image, rect, ch1, ch2, firstRow, endRow )
15888  {
15889  }
15890 
15891  private:
15892 
15893  void DoExecute() override
15894  {
15895  this->Execute( [=]( const sample* f )
15896  {
15897  double v; P::FromSample( v, *f );
15898  this->SumStep( pcl::Abs( v ) );
15899  } );
15900  }
15901  };
15902 
15903  // -------------------------------------------------------------------------
15904 
15905  class NormThread : public RectThreadBase
15906  {
15907  public:
15908 
15909  Vector R;
15910  size_type n;
15911 
15912  NormThread( const GenericImage& image, int degree, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
15913  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15914  , R( degree )
15915  , e( degree )
15916  {
15917  }
15918 
15919  void Run() final
15920  {
15921  R = e = 0.0;
15922  n = 0;
15923  this->Execute( [=]( const sample* f )
15924  {
15925  double v; P::FromSample( v, *f );
15926  for ( int i = 0;; )
15927  {
15928  NormStep( i, v );
15929  if ( ++i == R.Length() )
15930  break;
15931  v *= v;
15932  }
15933  ++n;
15934  } );
15935  }
15936 
15937  protected:
15938 
15939  Vector e;
15940 
15941  void NormStep( int i, double x ) noexcept
15942  {
15943  double y = x - e[i];
15944  double t = R[i] + y;
15945  e[i] = (t - R[i]) - y;
15946  R[i] = t;
15947  }
15948  };
15949 
15950  // -------------------------------------------------------------------------
15951 
15952  class HistogramThread : public RectThreadBase
15953  {
15954  public:
15955 
15956  SzVector H;
15957 
15958  HistogramThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow,
15959  const double& low, const double& high )
15960  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15961  , H( __PCL_MEDIAN_HISTOGRAM_LENGTH )
15962  , m_low( low )
15963  , m_high( high )
15964  {
15965  }
15966 
15967  void Run() final
15968  {
15969  H = size_type( 0 );
15970  m_range = m_high - m_low;
15971 // Workaround for clang compiler bug on macOS:
15972 // https://pixinsight.com/forum/index.php?threads/pi-always-crash-when-stf.15830/
15973 #ifdef __PCL_MACOSX
15974  if ( 1 + m_range != 1 )
15975 #endif
15976  this->Execute( [=]( const sample* f )
15977  {
15978  if ( *f >= m_low )
15979  if ( *f <= m_high )
15980  ++H[TruncInt( (__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) * (double( *f ) - m_low)/m_range )];
15981  } );
15982  }
15983 
15984  private:
15985 
15986  const double& m_low;
15987  const double& m_high;
15988  double m_range;
15989  };
15990 
15991  // -------------------------------------------------------------------------
15992 
15993  class ExtremeAbsDevThread : public RectThreadBase
15994  {
15995  public:
15996 
15997  double minAbsDev, maxAbsDev;
15998  size_type count;
15999 
16000  ExtremeAbsDevThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow, double center )
16001  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16002  , m_center( center )
16003  {
16004  }
16005 
16006  void Run() final
16007  {
16008  minAbsDev = std::numeric_limits<double>::max();
16009  maxAbsDev = 0;
16010  count = 0;
16011  this->Execute( [=]( const sample* f )
16012  {
16013  double d; P::FromSample( d, *f );
16014  d = pcl::Abs( d - m_center );
16015  if ( d < minAbsDev )
16016  minAbsDev = d;
16017  if ( d > maxAbsDev )
16018  maxAbsDev = d;
16019  ++count;
16020  } );
16021  }
16022 
16023  private:
16024 
16025  double m_center;
16026  };
16027 
16028  // -------------------------------------------------------------------------
16029 
16030  class TwoSidedExtremeAbsDevThread : public RectThreadBase
16031  {
16032  public:
16033 
16034  double minAbsDevLow, minAbsDevHigh;
16035  double maxAbsDevLow, maxAbsDevHigh;
16036  size_type nLow, nHigh;
16037 
16038  TwoSidedExtremeAbsDevThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow, double center )
16039  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16040  , m_center( center )
16041  {
16042  }
16043 
16044  void Run() final
16045  {
16046  minAbsDevLow = minAbsDevHigh = std::numeric_limits<double>::max();
16047  maxAbsDevLow = maxAbsDevHigh = 0;
16048  nLow = nHigh = 0;
16049  this->Execute( [=]( const sample* f )
16050  {
16051  double x; P::FromSample( x, *f );
16052  if ( x <= m_center )
16053  {
16054  double d = m_center - x;
16055  if ( d < minAbsDevLow )
16056  minAbsDevLow = d;
16057  if ( d > maxAbsDevLow )
16058  maxAbsDevLow = d;
16059  ++nLow;
16060  }
16061  else
16062  {
16063  double d = x - m_center;
16064  if ( d < minAbsDevHigh )
16065  minAbsDevHigh = d;
16066  if ( d > maxAbsDevHigh )
16067  maxAbsDevHigh = d;
16068  ++nHigh;
16069  }
16070  } );
16071  }
16072 
16073  private:
16074 
16075  double m_center;
16076  };
16077 
16078  // -------------------------------------------------------------------------
16079 
16080  class AbsDevHistogramThread : public RectThreadBase
16081  {
16082  public:
16083 
16084  SzVector H;
16085 
16086  AbsDevHistogramThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow,
16087  double center, const double& low, const double& high )
16088  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16089  , H( __PCL_MEDIAN_HISTOGRAM_LENGTH )
16090  , m_center( center )
16091  , m_low( low )
16092  , m_high( high )
16093  {
16094  }
16095 
16096  void Run() final
16097  {
16098  H = size_type( 0 );
16099  m_range = m_high - m_low;
16100 // Workaround for clang compiler bug on macOS:
16101 // https://pixinsight.com/forum/index.php?threads/pi-always-crash-when-stf.15830/
16102 #ifdef __PCL_MACOSX
16103  if ( 1 + m_range != 1 )
16104 #endif
16105  this->Execute( [=]( const sample* f )
16106  {
16107  double d; P::FromSample( d, *f );
16108  d = pcl::Abs( d - m_center );
16109  if ( d >= m_low )
16110  if ( d <= m_high )
16111  ++H[TruncInt( (__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) * (d - m_low)/m_range )];
16112  } );
16113  }
16114 
16115  private:
16116 
16117  double m_center;
16118  const double& m_low;
16119  const double& m_high;
16120  double m_range;
16121  };
16122 
16123  // -------------------------------------------------------------------------
16124 
16125  class TwoSidedAbsDevHistogramThread : public RectThreadBase
16126  {
16127  public:
16128 
16129  SzVector H;
16130 
16131  TwoSidedAbsDevHistogramThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow,
16132  double center, const int& side, const double& low, const double& high )
16133  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16134  , H( __PCL_MEDIAN_HISTOGRAM_LENGTH )
16135  , m_center( center )
16136  , m_side( side )
16137  , m_low( low )
16138  , m_high( high )
16139  {
16140  }
16141 
16142  void Run() final
16143  {
16144  H = size_type( 0 );
16145  m_range = m_high - m_low;
16146 // Workaround for clang compiler bug on macOS:
16147 // https://pixinsight.com/forum/index.php?threads/pi-always-crash-when-stf.15830/
16148 #ifdef __PCL_MACOSX
16149  if ( 1 + m_range != 1 )
16150 #endif
16151  this->Execute( [=]( const sample* f )
16152  {
16153  double x; P::FromSample( x, *f );
16154  if ( m_side > 0 == x > m_center )
16155  {
16156  double d = m_side ? x - m_center : m_center - x;
16157  if ( d >= m_low )
16158  if ( d <= m_high )
16159  ++H[TruncInt( (__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) * (d - m_low)/m_range )];
16160  }
16161  } );
16162  }
16163 
16164  private:
16165 
16166  double m_center;
16167  const int& m_side;
16168  const double& m_low;
16169  const double& m_high;
16170  double m_range;
16171  };
16172 
16173  // -------------------------------------------------------------------------
16174 
16175  class VarThread : public RectThreadBase
16176  {
16177  public:
16178 
16179  double var, eps;
16180 
16181  VarThread( const GenericImage& image, double mean, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
16182  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16183  , m_mean( mean )
16184  {
16185  }
16186 
16187  void Run() final
16188  {
16189  var = eps = 0;
16190  this->Execute( [=]( const sample* f )
16191  {
16192  double d; P::FromSample( d, *f );
16193  d -= m_mean;
16194  var += d*d;
16195  eps += d;
16196  } );
16197  }
16198 
16199  private:
16200 
16201  double m_mean;
16202  };
16203 
16204  // -------------------------------------------------------------------------
16205 
16206  class SumAbsDevThread : public SumThread
16207  {
16208  public:
16209 
16210  SumAbsDevThread( const GenericImage& image, double center, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
16211  : SumThread( image, rect, ch1, ch2, firstRow, endRow )
16212  , m_center( center )
16213  {
16214  }
16215 
16216  private:
16217 
16218  double m_center;
16219 
16220  void DoExecute() override
16221  {
16222  this->Execute( [=]( const sample* f )
16223  {
16224  double v; P::FromSample( v, *f );
16225  this->SumStep( pcl::Abs( v - m_center ) );
16226  } );
16227  }
16228  };
16229 
16230  // -------------------------------------------------------------------------
16231 
16232  class TwoSidedSumAbsDevThread : public RectThreadBase
16233  {
16234  public:
16235 
16236  double s0, s1;
16237  size_type n0, n1;
16238 
16239  TwoSidedSumAbsDevThread( const GenericImage& image, double center,
16240  const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
16241  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16242  , m_center( center )
16243  {
16244  }
16245 
16246  void Run() final
16247  {
16248  s0 = s1 = 0;
16249  n0 = n1 = 0;
16250  this->Execute( [=]( const sample* f )
16251  {
16252  double v; P::FromSample( v, *f );
16253  if ( v <= m_center )
16254  {
16255  s0 += m_center - v;
16256  ++n0;
16257  }
16258  else
16259  {
16260  s1 += v - m_center;
16261  ++n1;
16262  }
16263  } );
16264  }
16265 
16266  private:
16267 
16268  double m_center;
16269  };
16270 
16271  // -------------------------------------------------------------------------
16272 
16273  class BWMVThread : public RectThreadBase
16274  {
16275  public:
16276 
16277  double num, den;
16278  size_type n, nr;
16279 
16280  BWMVThread( const GenericImage& image, double center, double kd,
16281  const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
16282  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16283  , m_center( center )
16284  , m_kd( kd )
16285  {
16286  }
16287 
16288  void Run() final
16289  {
16290  num = den = 0;
16291  n = nr = 0;
16292  this->Execute( [=]( const sample* f )
16293  {
16294  ++n;
16295  double xc; P::FromSample( xc, *f ); xc -= m_center;
16296  double y = xc/m_kd;
16297  if ( pcl::Abs( y ) < 1 )
16298  {
16299  double y2 = y*y;
16300  double y21 = 1 - y2;
16301  num += xc*xc * y21*y21*y21*y21;
16302  den += y21 * (1 - 5*y2);
16303  ++nr;
16304  }
16305  } );
16306  }
16307 
16308  private:
16309 
16310  double m_center;
16311  double m_kd;
16312  };
16313 
16314  // -------------------------------------------------------------------------
16315 
16316  class TwoSidedBWMVThread : public RectThreadBase
16317  {
16318  public:
16319 
16320  double num0, den0;
16321  double num1, den1;
16322  size_type n0, n1, nr0, nr1;
16323 
16324  TwoSidedBWMVThread( const GenericImage& image, double center, double kd0, double kd1,
16325  const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
16326  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16327  , m_center( center )
16328  , m_kd0( kd0 )
16329  , m_kd1( kd1 )
16330  {
16331  }
16332 
16333  void Run() final
16334  {
16335  num0 = den0 = num1 = den1 = 0;
16336  n0 = n1 = nr0 = nr1 = 0;
16337  this->Execute( [=]( const sample* f )
16338  {
16339  double xc; P::FromSample( xc, *f ); xc -= m_center;
16340  bool low = xc <= 0;
16341  if ( low )
16342  ++n0;
16343  else
16344  ++n1;
16345 
16346  double y = xc/(low ? m_kd0 : m_kd1);
16347  if ( pcl::Abs( y ) < 1 )
16348  {
16349  double y2 = y*y;
16350  double y21 = 1 - y2;
16351  double num = xc*xc * y21*y21*y21*y21;
16352  double den = y21 * (1 - 5*y2);
16353  if ( low )
16354  {
16355  num0 += num;
16356  den0 += den;
16357  ++nr0;
16358  }
16359  else
16360  {
16361  num1 += num;
16362  den1 += den;
16363  ++nr1;
16364  }
16365  }
16366  } );
16367  }
16368 
16369  private:
16370 
16371  double m_center;
16372  double m_kd0;
16373  double m_kd1;
16374  };
16375 
16376  // -------------------------------------------------------------------------
16377 
16378  class SmpThread : public RectThreadBase
16379  {
16380  public:
16381 
16382  Array<sample> samples;
16383  size_type n;
16384 
16385  SmpThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
16386  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16387  {
16388  size_type N = size_type( this->m_rect.Width() )
16389  * size_type( this->m_endRow - this->m_firstRow )
16390  * (1 + this->m_ch2 - this->m_ch1);
16391  samples = Array<sample>( N );
16392  }
16393 
16394  void Run() final
16395  {
16396  n = 0;
16397  this->Execute( [=]( const sample* f )
16398  {
16399  samples[n++] = *f;
16400  } );
16401  }
16402  };
16403 
16404  // -------------------------------------------------------------------------
16405 
16406  class DSmpThread : public RectThreadBase
16407  {
16408  public:
16409 
16410  Array<double> values;
16411  size_type n;
16412 
16413  DSmpThread( const GenericImage& image, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
16414  : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16415  {
16416  size_type N = size_type( this->m_rect.Width() )
16417  * size_type( this->m_endRow - this->m_firstRow )
16418  * (1 + this->m_ch2 - this->m_ch1);
16419  values = Array<double>( N );
16420  }
16421 
16422  void Run() final
16423  {
16424  n = 0;
16425  DoExecute();
16426  }
16427 
16428  protected:
16429 
16430  virtual void DoExecute()
16431  {
16432  this->Execute( [=]( const sample* f )
16433  {
16434  P::FromSample( values[n++], *f );
16435  } );
16436  }
16437  };
16438 
16439  // -------------------------------------------------------------------------
16440 
16441  class AbsDevSmpThread : public DSmpThread
16442  {
16443  public:
16444 
16445  AbsDevSmpThread( const GenericImage& image, double center, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
16446  : DSmpThread( image, rect, ch1, ch2, firstRow, endRow )
16447  , m_center( center )
16448  {
16449  }
16450 
16451  private:
16452 
16453  double m_center;
16454 
16455  void DoExecute() override
16456  {
16457  this->Execute( [=]( const sample* f )
16458  {
16459  double d; P::FromSample( d, *f );
16460  this->values[this->n++] = pcl::Abs( d - m_center );
16461  } );
16462  }
16463  };
16464 
16465  // -------------------------------------------------------------------------
16466 
16467  class TwoSidedAbsDevSmpThread : public DSmpThread
16468  {
16469  public:
16470 
16472 
16473  TwoSidedAbsDevSmpThread( const GenericImage& image, double center, const Rect& rect, int ch1, int ch2, int firstRow, int endRow )
16474  : DSmpThread( image, rect, ch1, ch2, firstRow, endRow )
16475  , m_center( center )
16476  {
16477  }
16478 
16479  private:
16480 
16481  double m_center;
16482 
16483  void DoExecute() override
16484  {
16485  p = this->values.Begin();
16486  q = this->values.End();
16487  this->Execute( [=]( const sample* f )
16488  {
16489  double x; P::FromSample( x, *f );
16490  if ( x <= m_center )
16491  *p++ = m_center - x;
16492  else
16493  *--q = x - m_center;
16494  ++this->n;
16495  } );
16496  }
16497  };
16498 
16499  // -------------------------------------------------------------------------
16500 
16501  class ColorSpaceConversionThread : public Thread
16502  {
16503  public:
16504 
16505  ColorSpaceConversionThread( GenericImage& image, ThreadData& data,
16506  color_space toColorSpace, size_type begin, size_type end )
16507  : m_image( image )
16508  , m_data( data )
16509  , m_toColorSpace( toColorSpace )
16510  , m_begin( begin )
16511  , m_end( end )
16512  {
16513  }
16514 
16515  void Run() final
16516  {
16518 
16519  const RGBColorSystem& rgbws = m_image.RGBWorkingSpace();
16520 
16521  typename P::sample* f0 = m_image[0] + m_begin;
16522  typename P::sample* f1 = m_image[1] + m_begin;
16523  typename P::sample* f2 = m_image[2] + m_begin;
16524  typename P::sample* fN = m_image[0] + m_end;
16525 
16526  for ( ; f0 < fN; ++f0, ++f1, ++f2 )
16527  {
16528  RGBColorSystem::sample r0, r1, r2;
16529  P::FromSample( r0, *f0 );
16530  P::FromSample( r1, *f1 );
16531  P::FromSample( r2, *f2 );
16532 
16533  switch ( m_image.ColorSpace() )
16534  {
16535  case ColorSpace::RGB :
16536  switch ( m_toColorSpace )
16537  {
16538  case ColorSpace::Gray :
16539  rgbws.RGBToGray( r0, r0, r1, r2 );
16540  break;
16541  case ColorSpace::HSV :
16542  rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16543  break;
16544  case ColorSpace::HSI :
16545  rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16546  break;
16547  case ColorSpace::CIEXYZ :
16548  rgbws.RGBToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16549  break;
16550  case ColorSpace::CIELab :
16551  rgbws.RGBToCIELab( r0, r1, r2, r0, r1, r2 );
16552  break;
16553  case ColorSpace::CIELch :
16554  rgbws.RGBToCIELch( r0, r1, r2, r0, r1, r2 );
16555  break;
16556  default:
16557  break;
16558  }
16559  break;
16560  case ColorSpace::HSV :
16561  rgbws.HSVToRGB( r0, r1, r2, r0, r1, r2 );
16562  switch ( m_toColorSpace )
16563  {
16564  case ColorSpace::Gray :
16565  rgbws.RGBToGray( r0, r0, r1, r2 );
16566  break;
16567  case ColorSpace::RGB :
16568  break;
16569  case ColorSpace::HSI :
16570  rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16571  break;
16572  case ColorSpace::CIEXYZ :
16573  rgbws.RGBToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16574  break;
16575  case ColorSpace::CIELab :
16576  rgbws.RGBToCIELab( r0, r1, r2, r0, r1, r2 );
16577  break;
16578  case ColorSpace::CIELch :
16579  rgbws.RGBToCIELch( r0, r1, r2, r0, r1, r2 );
16580  break;
16581  default:
16582  break;
16583  }
16584  break;
16585  case ColorSpace::HSI :
16586  rgbws.HSIToRGB( r0, r1, r2, r0, r1, r2 );
16587  switch ( m_toColorSpace )
16588  {
16589  case ColorSpace::Gray :
16590  rgbws.RGBToGray( r0, r0, r1, r2 );
16591  break;
16592  case ColorSpace::RGB :
16593  break;
16594  case ColorSpace::HSV :
16595  rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16596  break;
16597  case ColorSpace::CIEXYZ :
16598  rgbws.RGBToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16599  break;
16600  case ColorSpace::CIELab :
16601  rgbws.RGBToCIELab( r0, r1, r2, r0, r1, r2 );
16602  break;
16603  case ColorSpace::CIELch :
16604  rgbws.RGBToCIELch( r0, r1, r2, r0, r1, r2 );
16605  break;
16606  default:
16607  break;
16608  }
16609  break;
16610  case ColorSpace::CIEXYZ :
16611  switch ( m_toColorSpace )
16612  {
16613  case ColorSpace::Gray :
16614  rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16615  rgbws.RGBToGray( r0, r0, r1, r2 );
16616  break;
16617  case ColorSpace::RGB :
16618  rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16619  break;
16620  case ColorSpace::HSV :
16621  rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16622  rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16623  break;
16624  case ColorSpace::HSI :
16625  rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16626  rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16627  break;
16628  case ColorSpace::CIELab :
16629  rgbws.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
16630  break;
16631  case ColorSpace::CIELch :
16632  rgbws.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
16633  rgbws.CIELabToCIELch( r0, r1, r2, r0, r1, r2 );
16634  break;
16635  default:
16636  break;
16637  }
16638  break;
16639  case ColorSpace::CIELab :
16640  switch ( m_toColorSpace )
16641  {
16642  case ColorSpace::Gray :
16643  rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16644  rgbws.RGBToGray( r0, r0, r1, r2 );
16645  break;
16646  case ColorSpace::RGB :
16647  rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16648  break;
16649  case ColorSpace::HSV :
16650  rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16651  rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16652  break;
16653  case ColorSpace::HSI :
16654  rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16655  rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16656  break;
16657  case ColorSpace::CIEXYZ :
16658  rgbws.CIELabToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16659  break;
16660  case ColorSpace::CIELch :
16661  rgbws.CIELabToCIELch( r0, r1, r2, r0, r1, r2 );
16662  break;
16663  default:
16664  break;
16665  }
16666  break;
16667  case ColorSpace::CIELch :
16668  switch ( m_toColorSpace )
16669  {
16670  case ColorSpace::Gray :
16671  rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16672  rgbws.RGBToGray( r0, r0, r1, r2 );
16673  break;
16674  case ColorSpace::RGB :
16675  rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16676  break;
16677  case ColorSpace::HSV :
16678  rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16679  rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16680  break;
16681  case ColorSpace::HSI :
16682  rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16683  rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16684  break;
16685  case ColorSpace::CIEXYZ :
16686  rgbws.CIELchToCIELab( r0, r1, r2, r0, r1, r2 );
16687  rgbws.CIELabToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16688  break;
16689  case ColorSpace::CIELab :
16690  rgbws.CIELchToCIELab( r0, r1, r2, r0, r1, r2 );
16691  break;
16692  default:
16693  break;
16694  }
16695  break;
16696  default:
16697  break;
16698  }
16699 
16700  *f0 = P::ToSample( r0 );
16701 
16702  if ( m_toColorSpace != ColorSpace::Gray )
16703  {
16704  *f1 = P::ToSample( r1 );
16705  *f2 = P::ToSample( r2 );
16706  }
16707 
16708  UPDATE_THREAD_MONITOR( 65536 )
16709  }
16710  }
16711 
16712  private:
16713 
16714  GenericImage& m_image;
16715  ThreadData& m_data;
16716  color_space m_toColorSpace;
16717  size_type m_begin, m_end;
16718  };
16719 
16720  // -------------------------------------------------------------------------
16721 
16722  template <class P1>
16723  class GetLuminanceThread : public Thread
16724  {
16725  public:
16726 
16727  GetLuminanceThread( GenericImage<P1>& luminance, const GenericImage& image, ThreadData& data,
16728  const Rect& rect, int firstRow, int endRow )
16729  : m_luminance( luminance )
16730  , m_image( image )
16731  , m_data( data )
16732  , m_rect( rect )
16733  , m_firstRow( firstRow )
16734  , m_endRow( endRow )
16735  {
16736  }
16737 
16738  void Run() final
16739  {
16741 
16742  const RGBColorSystem& rgbws = m_image.RGBWorkingSpace();
16743 
16744  const typename P::sample* f0 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
16745  const typename P::sample* f1 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
16746  const typename P::sample* f2 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
16747 
16748  typename P1::sample* fY = m_luminance.ScanLine( m_firstRow );
16749 
16750  for ( int y = m_firstRow, dw = m_image.Width()-m_rect.Width();
16751  y < m_endRow;
16752  ++y, f0 += dw, f1 += dw, f2 += dw )
16753  {
16754  const typename P::sample* fN = f0 + m_rect.Width();
16755 
16756  for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fY )
16757  {
16758  RGBColorSystem::sample r0, r1, r2, rY;
16759  P::FromSample( r0, *f0 );
16760  P::FromSample( r1, *f1 );
16761  P::FromSample( r2, *f2 );
16762 
16763  switch ( m_image.ColorSpace() )
16764  {
16765  case ColorSpace::RGB:
16766  case ColorSpace::HSV:
16767  case ColorSpace::HSI:
16768  switch ( m_image.ColorSpace() )
16769  {
16770  case ColorSpace::HSV:
16771  rgbws.HSVToRGB( r0, r1, r2, r0, r1, r2 );
16772  break;
16773  case ColorSpace::HSI:
16774  rgbws.HSIToRGB( r0, r1, r2, r0, r1, r2 );
16775  break;
16776  default:
16777  break;
16778  }
16779  rY = rgbws.CIEY( r0, r1, r2 );
16780  break;
16781 
16782  case ColorSpace::CIELch:
16783  rgbws.CIELchToCIELab( r0, r1, r2, r0, r1, r2 );
16784  // fall through
16785  case ColorSpace::CIELab:
16786  rgbws.CIELabToCIEXYZ( r0, rY, r2, r0, r1, r2 );
16787  break;
16788 
16789  default: // ?!
16790  rY = 0;
16791  break;
16792  }
16793 
16794  *fY = P1::ToSample( rY );
16795 
16796  UPDATE_THREAD_MONITOR( 65536 )
16797  }
16798  }
16799  }
16800 
16801  private:
16802 
16803  GenericImage<P1>& m_luminance;
16804  const GenericImage& m_image;
16805  ThreadData& m_data;
16806  const Rect& m_rect;
16807  int m_firstRow, m_endRow;
16808  };
16809 
16810  // -------------------------------------------------------------------------
16811 
16812  template <class P1>
16813  class GetLightnessThread : public Thread
16814  {
16815  public:
16816 
16817  GetLightnessThread( GenericImage<P1>& lightness, const GenericImage& image, ThreadData& data,
16818  const Rect& rect, int firstRow, int endRow )
16819  : m_lightness( lightness )
16820  , m_image( image )
16821  , m_data( data )
16822  , m_rect( rect )
16823  , m_firstRow( firstRow )
16824  , m_endRow( endRow )
16825  {
16826  }
16827 
16828  void Run() final
16829  {
16831 
16832  const RGBColorSystem& rgbws = m_image.RGBWorkingSpace();
16833 
16834  const typename P::sample* f0 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
16835  const typename P::sample* f1 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
16836  const typename P::sample* f2 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
16837 
16838  typename P1::sample* fL = m_lightness.ScanLine( m_firstRow );
16839 
16840  for ( int y = m_firstRow, dw = m_image.Width()-m_rect.Width();
16841  y < m_endRow;
16842  ++y, f0 += dw, f1 += dw, f2 += dw )
16843  {
16844  const typename P::sample* fN = f0 + m_rect.Width();
16845 
16846  for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fL )
16847  {
16848  RGBColorSystem::sample r0, r1, r2, rL;
16849  P::FromSample( r0, *f0 );
16850  P::FromSample( r1, *f1 );
16851  P::FromSample( r2, *f2 );
16852 
16853  switch ( m_image.ColorSpace() )
16854  {
16855  case ColorSpace::RGB:
16856  case ColorSpace::HSV:
16857  case ColorSpace::HSI:
16858  case ColorSpace::CIEXYZ:
16859  switch ( m_image.ColorSpace() )
16860  {
16861  case ColorSpace::HSV:
16862  rgbws.HSVToRGB( r0, r1, r2, r0, r1, r2 );
16863  break;
16864  case ColorSpace::HSI:
16865  rgbws.HSIToRGB( r0, r1, r2, r0, r1, r2 );
16866  break;
16867  case ColorSpace::CIEXYZ:
16868  rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16869  break;
16870  default:
16871  break;
16872  }
16873  rL = rgbws.CIEL( r0, r1, r2 );
16874  break;
16875 
16876  default: // ?!
16877  rL = 0;
16878  break;
16879  }
16880 
16881  *fL = P1::ToSample( rL );
16882 
16883  UPDATE_THREAD_MONITOR( 65536 )
16884  }
16885  }
16886  }
16887 
16888  private:
16889 
16890  GenericImage<P1>& m_lightness;
16891  const GenericImage& m_image;
16892  ThreadData& m_data;
16893  const Rect& m_rect;
16894  int m_firstRow, m_endRow;
16895  };
16896 
16897  // -------------------------------------------------------------------------
16898 
16899  template <class P1>
16900  class GetIntensityThread : public Thread
16901  {
16902  public:
16903 
16904  GetIntensityThread( GenericImage<P1>& luminance, const GenericImage& image, ThreadData& data,
16905  const Rect& rect, int firstRow, int endRow )
16906  : m_intensity( luminance )
16907  , m_image( image )
16908  , m_data( data )
16909  , m_rect( rect )
16910  , m_firstRow( firstRow )
16911  , m_endRow( endRow )
16912  {
16913  }
16914 
16915  void Run() final
16916  {
16918 
16919  const RGBColorSystem& rgbws = m_image.RGBWorkingSpace();
16920 
16921  const typename P::sample* f0 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
16922  const typename P::sample* f1 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
16923  const typename P::sample* f2 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
16924 
16925  typename P1::sample* fI = m_intensity.ScanLine( m_firstRow );
16926 
16927  for ( int y = m_firstRow, dw = m_image.Width()-m_rect.Width();
16928  y < m_endRow;
16929  ++y, f0 += dw, f1 += dw, f2 += dw )
16930  {
16931  const typename P::sample* fN = f0 + m_rect.Width();
16932 
16933  for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fI )
16934  {
16935  RGBColorSystem::sample r0, r1, r2;
16936  P::FromSample( r0, *f0 );
16937  P::FromSample( r1, *f1 );
16938  P::FromSample( r2, *f2 );
16939 
16940  switch ( m_image.ColorSpace() )
16941  {
16942  case ColorSpace::RGB:
16943  break;
16944  case ColorSpace::HSV:
16945  rgbws.HSVToRGB( r0, r1, r2, r0, r1, r2 );
16946  break;
16947  case ColorSpace::CIEXYZ:
16948  rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16949  break;
16950  case ColorSpace::CIELab:
16951  rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16952  break;
16953  case ColorSpace::CIELch:
16954  rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16955  break;
16956  default:
16957  break;
16958  }
16959 
16960  *fI = P1::ToSample( rgbws.Intensity( r0, r1, r2 ) );
16961 
16962  UPDATE_THREAD_MONITOR( 65536 )
16963  }
16964  }
16965  }
16966 
16967  private:
16968 
16969  GenericImage<P1>& m_intensity;
16970  const GenericImage& m_image;
16971  ThreadData& m_data;
16972  const Rect& m_rect;
16973  int m_firstRow, m_endRow;
16974  };
16975 
16976  // -------------------------------------------------------------------------
16977 
16978  template <class P1>
16979  class SetLuminanceThread : public Thread
16980  {
16981  public:
16982 
16983  SetLuminanceThread( GenericImage& image, const GenericImage<P1>& luminance, ThreadData& data,
16984  const Point& target, const Rect& rect, int firstRow, int endRow )
16985  : m_image( image )
16986  , m_luminance( luminance )
16987  , m_data( data )
16988  , m_target( target )
16989  , m_rect( rect )
16990  , m_firstRow( firstRow )
16991  , m_endRow( endRow )
16992  {
16993  }
16994 
16995  void Run() final
16996  {
16998 
16999  const RGBColorSystem& sourceRGBWS = m_luminance.RGBWorkingSpace();
17000  const RGBColorSystem& targetRGBWS = m_image.RGBWorkingSpace();
17001 
17002  typename P::sample* f0 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 0 );
17003  typename P::sample* f1 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 1 );
17004  typename P::sample* f2 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 2 );
17005 
17006  if ( m_luminance.ColorSpace() == ColorSpace::Gray || m_luminance.ColorSpace() == ColorSpace::CIEXYZ )
17007  {
17008  int cY = (m_luminance.ColorSpace() == ColorSpace::Gray) ? 0 : 1;
17009  const typename P1::sample* fY = m_luminance.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, cY );
17010 
17011  for ( int y = m_firstRow, dw = m_image.Width()-m_rect.Width(), dwY = m_luminance.Width()-m_rect.Width();
17012  y < m_endRow;
17013  ++y, f0 += dw, f1 += dw, f2 += dw, fY += dwY )
17014  {
17015  const typename P::sample* fN = f0 + m_rect.Width();
17016 
17017  for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fY )
17018  {
17019  RGBColorSystem::sample r0, r1, r2, rY;
17020  P::FromSample( r0, *f0 );
17021  P::FromSample( r1, *f1 );
17022  P::FromSample( r2, *f2 );
17023  P1::FromSample( rY, *fY );
17024 
17025  switch ( m_image.ColorSpace() )
17026  {
17027  case ColorSpace::RGB:
17028  case ColorSpace::HSV:
17029  case ColorSpace::HSI:
17030  switch ( m_image.ColorSpace() )
17031  {
17032  case ColorSpace::HSV:
17033  targetRGBWS.HSVToRGB( r0, r1, r2, r0, r1, r2 );
17034  break;
17035  case ColorSpace::HSI:
17036  targetRGBWS.HSIToRGB( r0, r1, r2, r0, r1, r2 );
17037  break;
17038  default: // RGB
17039  break;
17040  }
17041  targetRGBWS.RGBToCIEab( r1, r2, r0, r1, r2 );
17042  targetRGBWS.CIELabToRGB( r0, r1, r2, sourceRGBWS.CIEYToCIEL( rY ), r1, r2 );
17043  switch ( m_image.ColorSpace() )
17044  {
17045  case ColorSpace::HSV:
17046  targetRGBWS.RGBToHSV( r0, r1, r2, r0, r1, r2 );
17047  break;
17048  case ColorSpace::HSI:
17049  targetRGBWS.RGBToHSI( r0, r1, r2, r0, r1, r2 );
17050  break;
17051  default: // RGB
17052  break;
17053  }
17054  break;
17055 
17056  case ColorSpace::CIEXYZ:
17057  targetRGBWS.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
17058  targetRGBWS.CIELabToCIEXYZ( r0, r1, r2, sourceRGBWS.CIEYToCIEL( rY ), r1, r2 );
17059  break;
17060 
17061  case ColorSpace::CIELab:
17062  case ColorSpace::CIELch:
17063  r0 = sourceRGBWS.CIEYToCIEL( rY );
17064  break;
17065 
17066  default: // ???
17067  break;
17068  }
17069 
17070  *f0 = P::ToSample( r0 );
17071  *f1 = P::ToSample( r1 );
17072  *f2 = P::ToSample( r2 );
17073 
17074  UPDATE_THREAD_MONITOR( 65536 )
17075  }
17076  }
17077  }
17078  else
17079  {
17080  const typename P1::sample* g0 = m_luminance.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
17081  const typename P1::sample* g1 = m_luminance.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
17082  const typename P1::sample* g2 = m_luminance.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
17083 
17084  for ( int y = m_firstRow, dw = m_image.Width()-m_rect.Width(), dwY = m_luminance.Width()-m_rect.Width();
17085  y < m_endRow;
17086  ++y, f0 += dw, f1 += dw, f2 += dw, g0 += dwY, g1 += dwY, g2 += dwY )
17087  {
17088  const typename P::sample* fN = f0 + m_rect.Width();
17089 
17090  for ( ; f0 < fN; ++f0, ++f1, ++f2, ++g0, ++g1, ++g2 )
17091  {
17092  typename RGBColorSystem::sample r0, r1, r2, s0, s1, s2;
17093  P::FromSample( r0, *f0 );
17094  P::FromSample( r1, *f1 );
17095  P::FromSample( r2, *f2 );
17096  P1::FromSample( s0, *g0 );
17097  P1::FromSample( s1, *g1 );
17098  P1::FromSample( s2, *g2 );
17099 
17100  switch ( m_image.ColorSpace() )
17101  {
17102  case ColorSpace::RGB:
17103  case ColorSpace::HSV:
17104  case ColorSpace::HSI:
17105  case ColorSpace::CIEXYZ:
17106  case ColorSpace::CIELab:
17107  case ColorSpace::CIELch:
17108  switch ( m_image.ColorSpace() )
17109  {
17110  case ColorSpace::RGB:
17111  case ColorSpace::HSV:
17112  case ColorSpace::HSI:
17113  switch ( m_image.ColorSpace() )
17114  {
17115  case ColorSpace::HSV:
17116  targetRGBWS.HSVToRGB( r0, r1, r2, r0, r1, r2 );
17117  break;
17118  case ColorSpace::HSI:
17119  targetRGBWS.HSIToRGB( r0, r1, r2, r0, r1, r2 );
17120  break;
17121  default:
17122  break;
17123  }
17124  targetRGBWS.RGBToCIEab( r1, r2, r0, r1, r2 );
17125  break;
17126  case ColorSpace::CIEXYZ:
17127  targetRGBWS.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
17128  break;
17129  case ColorSpace::CIELab: // NOOP
17130  case ColorSpace::CIELch: // NOOP
17131  break;
17132  default: // ?!
17133  break;
17134  }
17135 
17136  switch ( m_luminance.ColorSpace() )
17137  {
17138  case ColorSpace::RGB:
17139  case ColorSpace::HSV:
17140  case ColorSpace::HSI:
17141  switch ( m_luminance.ColorSpace() )
17142  {
17143  case ColorSpace::HSV:
17144  sourceRGBWS.HSVToRGB( s0, s1, s2, s0, s1, s2 );
17145  break;
17146  case ColorSpace::HSI:
17147  sourceRGBWS.HSIToRGB( s0, s1, s2, s0, s1, s2 );
17148  break;
17149  default:
17150  break;
17151  }
17152  r0 = sourceRGBWS.CIEL( s0, s1, s2 );
17153  break;
17154  case ColorSpace::CIEXYZ:
17155  sourceRGBWS.CIEXYZToCIELab( r0, s1, s2, s0, s1, s2 );
17156  break;
17157  case ColorSpace::CIELab:
17158  case ColorSpace::CIELch:
17159  r0 = s0;
17160  break;
17161  default: // ?!
17162  break;
17163  }
17164 
17165  switch ( m_image.ColorSpace() )
17166  {
17167  case ColorSpace::RGB:
17168  case ColorSpace::HSV:
17169  case ColorSpace::HSI:
17170  targetRGBWS.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
17171  switch ( m_image.ColorSpace() )
17172  {
17173  case ColorSpace::HSV:
17174  targetRGBWS.RGBToHSV( r0, r1, r2, r0, r1, r2 );
17175  break;
17176  case ColorSpace::HSI:
17177  targetRGBWS.RGBToHSI( r0, r1, r2, r0, r1, r2 );
17178  break;
17179  default: // RGB
17180  break;
17181  }
17182  break;
17183  case ColorSpace::CIEXYZ:
17184  targetRGBWS.CIELabToCIEXYZ( r0, r1, r2, r0, r1, r2 );
17185  break;
17186  case ColorSpace::CIELab: // NOOP
17187  case ColorSpace::CIELch: // NOOP
17188  break;
17189  default: // ?!
17190  break;
17191  }
17192  break;
17193 
17194  default: // ?!
17195  break;
17196  }
17197 
17198  *f0 = P::ToSample( r0 );
17199  *f1 = P::ToSample( r1 );
17200  *f2 = P::ToSample( r2 );
17201 
17202  UPDATE_THREAD_MONITOR( 65536 )
17203  }
17204  }
17205  }
17206  }
17207 
17208  private:
17209 
17210  GenericImage& m_image;
17211  const GenericImage<P1>& m_luminance;
17212  ThreadData& m_data;
17213  const Point& m_target;
17214  const Rect& m_rect;
17215  int m_firstRow, m_endRow;
17216  };
17217 
17218  // -------------------------------------------------------------------------
17219 
17220  template <class P1>
17221  class SetLightnessThread : public Thread
17222  {
17223  public:
17224 
17225  SetLightnessThread( GenericImage& image, const GenericImage<P1>& lightness, ThreadData& data,
17226  const Point& target, const Rect& rect, int firstRow, int endRow )
17227  : m_image( image )
17228  , m_lightness( lightness )
17229  , m_data( data )
17230  , m_target( target )
17231  , m_rect( rect )
17232  , m_firstRow( firstRow )
17233  , m_endRow( endRow )
17234  {
17235  }
17236 
17237  void Run() final
17238  {
17240 
17241  const RGBColorSystem& sourceRGBWS = m_lightness.RGBWorkingSpace();
17242  const RGBColorSystem& targetRGBWS = m_image.RGBWorkingSpace();
17243 
17244  typename P::sample* f0 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 0 );
17245  typename P::sample* f1 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 1 );
17246  typename P::sample* f2 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 2 );
17247 
17248  if ( m_lightness.ColorSpace() == ColorSpace::Gray ||
17249  m_lightness.ColorSpace() == ColorSpace::CIELab || m_lightness.ColorSpace() == ColorSpace::CIELch )
17250  {
17251  const typename P1::sample* fL = m_lightness.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
17252 
17253  for ( int y = m_firstRow, dw = m_image.Width()-m_rect.Width(), dwL = m_lightness.Width()-m_rect.Width();
17254  y < m_endRow;
17255  ++y, f0 += dw, f1 += dw, f2 += dw, fL += dwL )
17256  {
17257  const typename P::sample* fN = f0 + m_rect.Width();
17258 
17259  for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fL )
17260  {
17261  RGBColorSystem::sample r0, r1, r2, rL;
17262  P::FromSample( r0, *f0 );
17263  P::FromSample( r1, *f1 );
17264  P::FromSample( r2, *f2 );
17265  P1::FromSample( rL, *fL );
17266 
17267  switch ( m_image.ColorSpace() )
17268  {
17269  case ColorSpace::RGB:
17270  case ColorSpace::HSV:
17271  case ColorSpace::HSI:
17272  switch ( m_image.ColorSpace() )
17273  {
17274  case ColorSpace::HSV:
17275  targetRGBWS.HSVToRGB( r0, r1, r2, r0, r1, r2 );
17276  break;
17277  case ColorSpace::HSI:
17278  targetRGBWS.HSIToRGB( r0, r1, r2, r0, r1, r2 );
17279  break;
17280  default:
17281  break;
17282  }
17283  targetRGBWS.RGBToCIEab( r1, r2, r0, r1, r2 );
17284  targetRGBWS.CIELabToRGB( r0, r1, r2, rL, r1, r2 );
17285  switch ( m_image.ColorSpace() )
17286  {
17287  case ColorSpace::HSV:
17288  targetRGBWS.RGBToHSV( r0, r1, r2, r0, r1, r2 );
17289  break;
17290  case ColorSpace::HSI:
17291  targetRGBWS.RGBToHSI( r0, r1, r2, r0, r1, r2 );
17292  break;
17293  default:
17294  break;
17295  }
17296  break;
17297 
17298  case ColorSpace::CIEXYZ:
17299  r1 = targetRGBWS.CIELToCIEY( rL );
17300  break;
17301 
17302  case ColorSpace::CIELab:
17303  case ColorSpace::CIELch:
17304  r0 = rL;
17305  break;
17306 
17307  default: // ???
17308  break;
17309  }
17310 
17311  *f0 = P::ToSample( r0 );
17312  *f1 = P::ToSample( r1 );
17313  *f2 = P::ToSample( r2 );
17314 
17315  UPDATE_THREAD_MONITOR( 65536 )
17316  }
17317  }
17318  }
17319  else
17320  {
17321  const typename P1::sample* g0 = m_lightness.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
17322  const typename P1::sample* g1 = m_lightness.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
17323  const typename P1::sample* g2 = m_lightness.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
17324 
17325  for ( int y = m_firstRow, dw = m_image.Width()-m_rect.Width(), dwL = m_lightness.Width()-m_rect.Width();
17326  y < m_endRow;
17327  ++y, f0 += dw, f1 += dw, f2 += dw, g0 += dwL, g1 += dwL, g2 += dwL )
17328  {
17329  const typename P::sample* fN = f0 + m_rect.Width();
17330 
17331  for ( ; f0 < fN; ++f0, ++f1, ++f2, ++g0, ++g1, ++g2 )
17332  {
17333  typename RGBColorSystem::sample r0, r1, r2, s0, s1, s2;
17334  P::FromSample( r0, *f0 );
17335  P::FromSample( r1, *f1 );
17336  P::FromSample( r2, *f2 );
17337  P1::FromSample( s0, *g0 );
17338  P1::FromSample( s1, *g1 );
17339  P1::FromSample( s2, *g2 );
17340 
17341  switch ( m_image.ColorSpace() )
17342  {
17343  case ColorSpace::RGB:
17344  case ColorSpace::HSV:
17345  case ColorSpace::HSI:
17346  case ColorSpace::CIEXYZ:
17347  case ColorSpace::CIELab:
17348  case ColorSpace::CIELch:
17349  switch ( m_image.ColorSpace() )
17350  {
17351  case ColorSpace::RGB:
17352  case ColorSpace::HSV:
17353  case ColorSpace::HSI:
17354  switch ( m_image.ColorSpace() )
17355  {
17356  case ColorSpace::HSV:
17357  targetRGBWS.HSVToRGB( r0, r1, r2, r0, r1, r2 );
17358  break;
17359  case ColorSpace::HSI:
17360  targetRGBWS.HSIToRGB( r0, r1, r2, r0, r1, r2 );
17361  break;
17362  default:
17363  break;
17364  }
17365  targetRGBWS.RGBToCIEab( r1, r2, r0, r1, r2 );
17366  break;
17367  case ColorSpace::CIEXYZ:
17368  targetRGBWS.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
17369  break;
17370  case ColorSpace::CIELch:
17371  targetRGBWS.CIELchToCIELab( r0, r1, r2, r0, r1, r2 );
17372  break;
17373  default:
17374  break;
17375  }
17376 
17377  switch ( m_lightness.ColorSpace() )
17378  {
17379  case ColorSpace::RGB:
17380  case ColorSpace::HSV:
17381  case ColorSpace::HSI:
17382  switch ( m_lightness.ColorSpace() )
17383  {
17384  case ColorSpace::HSV:
17385  sourceRGBWS.HSVToRGB( s0, s1, s2, s0, s1, s2 );
17386  break;
17387  case ColorSpace::HSI:
17388  sourceRGBWS.HSIToRGB( s0, s1, s2, s0, s1, s2 );
17389  break;
17390  default:
17391  break;
17392  }
17393  r0 = sourceRGBWS.CIEL( s0, s1, s2 );
17394  break;
17395  case ColorSpace::CIEXYZ:
17396  r0 = sourceRGBWS.CIEYToCIEL( s1 );
17397  break;
17398  default: // ???
17399  break;
17400  }
17401 
17402  switch ( m_image.ColorSpace() )
17403  {
17404  case ColorSpace::RGB:
17405  case ColorSpace::HSV:
17406  case ColorSpace::HSI:
17407  targetRGBWS.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
17408  switch ( m_image.ColorSpace() )
17409  {
17410  case ColorSpace::HSV:
17411  targetRGBWS.RGBToHSV( r0, r1, r2, r0, r1, r2 );
17412  break;
17413  case ColorSpace::HSI:
17414  targetRGBWS.RGBToHSI( r0, r1, r2, r0, r1, r2 );
17415  break;
17416  default:
17417  break;
17418  }
17419  break;
17420  case ColorSpace::CIEXYZ:
17421  targetRGBWS.CIELabToCIEXYZ( r0, r1, r2, r0, r1, r2 );
17422  break;
17423  case ColorSpace::CIELch:
17424  targetRGBWS.CIELabToCIELch( r0, r1, r2, r0, r1, r2 );
17425  break;
17426  default:
17427  break;
17428  }
17429 
17430  default: // ???
17431  break;
17432  }
17433 
17434  *f0 = P::ToSample( r0 );
17435  *f1 = P::ToSample( r1 );
17436  *f2 = P::ToSample( r2 );
17437 
17438  UPDATE_THREAD_MONITOR( 65536 )
17439  }
17440  }
17441  }
17442  }
17443 
17444  private:
17445 
17446  GenericImage& m_image;
17447  const GenericImage<P1>& m_lightness;
17448  ThreadData& m_data;
17449  const Point& m_target;
17450  const Rect& m_rect;
17451  int m_firstRow, m_endRow;
17452  };
17453 
17454  // -------------------------------------------------------------------------
17455 
17456 #ifdef __PCL_BUILDING_PIXINSIGHT_APPLICATION
17457  friend class pi::SharedImage;
17458 #endif
17459 };
17460 
17461 #undef m_pixelData
17462 #undef m_channelData
17463 #undef m_allocator
17464 #undef m_width
17465 #undef m_height
17466 #undef m_numberOfChannels
17467 #undef m_colorSpace
17468 #undef m_RGBWS
17469 #undef m_channel
17470 #undef m_lastChannel
17471 #undef m_point
17472 #undef m_rectangle
17473 #undef m_clipLow
17474 #undef m_clipHigh
17475 #undef m_clippedLow
17476 #undef m_clippedHigh
17477 
17478 // ----------------------------------------------------------------------------
17479 
17489 template <class P, typename T> inline
17490 GenericImage<P> operator +( const GenericImage<P>& image, T scalar )
17491 {
17492  GenericImage<P> result( image );
17493  (void)(result += scalar);
17494  return result;
17495 }
17496 
17505 template <class P, typename T> inline
17506 GenericImage<P> operator +( T scalar, const GenericImage<P>& image )
17507 {
17508  return image + scalar;
17509 }
17510 
17516 template <class P, typename T> inline
17517 GenericImage<P> operator -( const GenericImage<P>& image, T scalar )
17518 {
17519  GenericImage<P> result( image );
17520  (void)(result -= scalar);
17521  return result;
17522 }
17523 
17529 template <class P, typename T> inline
17530 GenericImage<P> operator *( const GenericImage<P>& image, T scalar )
17531 {
17532  GenericImage<P> result( image );
17533  (void)(result *= scalar);
17534  return result;
17535 }
17536 
17546 template <class P, typename T> inline
17547 GenericImage<P> operator *( T scalar, const GenericImage<P>& image )
17548 {
17549  return image * scalar;
17550 }
17551 
17557 template <class P, typename T> inline
17558 GenericImage<P> operator /( const GenericImage<P>& image, T scalar )
17559 {
17560  GenericImage<P> result( image );
17561  (void)(result /= scalar);
17562  return result;
17563 }
17564 
17570 template <class P, typename T> inline
17571 GenericImage<P> operator ^( const GenericImage<P>& image, T scalar )
17572 {
17573  GenericImage<P> result( image );
17574  (void)(result ^= scalar);
17575  return result;
17576 }
17577 
17578 // ----------------------------------------------------------------------------
17579 
17596 template <class P1, class P2> inline
17598 {
17599  GenericImage<P1> result( image1 );
17600  (void)(result += image2);
17601  return result;
17602 }
17603 
17616 template <class P1, class P2> inline
17618 {
17619  GenericImage<P1> result( image1 );
17620  (void)(result -= image2);
17621  return result;
17622 }
17623 
17636 template <class P1, class P2> inline
17638 {
17639  GenericImage<P1> result( image1 );
17640  (void)(result *= image2);
17641  return result;
17642 }
17643 
17657 template <class P1, class P2> inline
17659 {
17660  GenericImage<P1> result( image1 );
17661  (void)(result /= image2);
17662  return result;
17663 }
17664 
17678 template <class P1, class P2> inline
17680 {
17681  GenericImage<P1> result( image1 );
17682  (void)(result ^= image2);
17683  return result;
17684 }
17685 
17686 // ----------------------------------------------------------------------------
17687 
17688 #ifndef __PCL_NO_IMAGE_INSTANTIATE
17689 
17701 using FImage = GenericImage<FloatPixelTraits>;
17702 
17710 using DImage = GenericImage<DoublePixelTraits>;
17711 
17720 using FComplexImage = GenericImage<ComplexPixelTraits>;
17721 
17730 using DComplexImage = GenericImage<DComplexPixelTraits>;
17731 
17740 using UInt8Image = GenericImage<UInt8PixelTraits>;
17741 
17750 using UInt16Image = GenericImage<UInt16PixelTraits>;
17751 
17760 using UInt32Image = GenericImage<UInt32PixelTraits>;
17761 
17770 using Image = FImage;
17771 
17780 using ComplexImage = FComplexImage;
17781 
17782 #endif // __PCL_NO_IMAGE_INSTANTIATE
17783 
17784 // ----------------------------------------------------------------------------
17785 
17786 } // pcl
17787 
17788 // ----------------------------------------------------------------------------
17789 
17790 #ifndef __PCL_NO_IMAGE_VARIANT_AUTO
17791 
17792 #ifndef __PCL_ImageVariant_h
17793 #include <pcl/ImageVariant.h>
17794 #endif
17795 
17796 #endif // __PCL_NO_IMAGE_VARIANT_AUTO
17797 
17798 // ----------------------------------------------------------------------------
17799 
17800 #endif // __PCL_Image_h
17801 
17802 // ----------------------------------------------------------------------------
17803 // EOF pcl/Image.h - Released 2024-06-18T15:48:54Z
Base class of all two-dimensional images in PCL.
int LastSelectedChannel() const noexcept
bool IsCompletelySelected() const noexcept
int FirstSelectedChannel() const noexcept
void ResetSelections() const noexcept
StatusMonitor & Status() const noexcept
bool ParseSelection(Rect &rect, int &firstChannel, int &lastChannel) const noexcept
iterator Begin()
Definition: Array.h:426
void Add(const Array &x)
Definition: Array.h:999
iterator End()
Definition: Array.h:451
double * iterator
Definition: Array.h:113
Root base class for bidirectional PCL image transformations.
Client-side interface to a PixInsight Bitmap object.
Definition: Bitmap.h:204
pcl::Rect Bounds() const
Definition: Bitmap.h:536
32-bit floating point complex image.
Generic complex number.
Definition: Complex.h:84
Abstract base class of data compression algorithm implementations.
Definition: Compression.h:84
subblock_list Compress(const void *data, size_type size, Performance *perf=nullptr) const
Image cropping/expansion algorithm
Definition: Crop.h:103
64-bit floating point complex image.
64-bit floating point real image.
A simple exception with an associated error message.
Definition: Exception.h:239
32-bit floating point complex image.
32-bit floating point real image.
A platform-independent interface to the local file system.
Definition: File.h:344
virtual void Write(const void *buffer, fsize_type len)
void ReadUI32(T &x)
Definition: File.h:935
void WriteUI32(const T &x)
Definition: File.h:998
virtual void Read(void *buffer, fsize_type len)
Immutable filter pixel iterator.
Definition: Image.h:5022
const_filter_pixel_iterator(const const_filter_pixel_iterator &)=default
typename image_type::sample sample
Definition: Image.h:5038
const_filter_pixel_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:5250
const_filter_pixel_iterator(const image_type &image, const F &filter)
Definition: Image.h:5061
const_filter_pixel_iterator(const const_pixel_iterator &i, const F &filter)
Definition: Image.h:5070
const filter_type & Filter() const noexcept
Definition: Image.h:5117
typename image_type::pixel_traits pixel_traits
Definition: Image.h:5033
const image_type & Image() const noexcept
Definition: Image.h:5108
const sample * Position(int channel) const noexcept
Definition: Image.h:5135
Immutable filter pixel sample iterator.
Definition: Image.h:2276
const_filter_sample_iterator(const image_type &image, const F &filter, int channel=-1)
Definition: Image.h:2323
const_filter_sample_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:2558
const image_type & Image() const noexcept
Definition: Image.h:2422
const_filter_sample_iterator(const image_type &image, const F &filter, const sample *i, const sample *j)
Definition: Image.h:2346
typename image_type::sample sample
Definition: Image.h:2292
const sample * Position() const noexcept
Definition: Image.h:2449
const filter_type & Filter() const noexcept
Definition: Image.h:2431
const_filter_sample_iterator(const const_filter_sample_iterator &)=default
typename image_type::pixel_traits pixel_traits
Definition: Image.h:2287
const_filter_sample_iterator(const sample_iterator &i, const F &filter)
Definition: Image.h:2355
const_filter_sample_iterator(const filter_sample_iterator< F > &i)
Definition: Image.h:2373
const_filter_sample_iterator(const const_sample_iterator &i, const F &filter)
Definition: Image.h:2364
Immutable pixel iterator.
Definition: Image.h:3747
const image_type & Image() const noexcept
Definition: Image.h:3810
const_pixel_iterator(const image_type &image)
Definition: Image.h:3775
typename image_type::sample sample
Definition: Image.h:3763
const_pixel_iterator(const const_pixel_iterator &)=default
bool IsValid() const noexcept
Definition: Image.h:3801
const_pixel_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:3926
typename image_type::pixel_traits pixel_traits
Definition: Image.h:3758
const sample * Position(int channel) const noexcept
Definition: Image.h:3819
Immutable region-of-interest, filter pixel iterator.
Definition: Image.h:5692
const_roi_filter_pixel_iterator(const const_roi_pixel_iterator &i, const F &filter)
Definition: Image.h:5750
const_roi_filter_pixel_iterator(const image_type &image, const F &filter, const Rect &rect=Rect(0))
Definition: Image.h:5741
const_roi_filter_pixel_iterator(const const_roi_filter_pixel_iterator &)=default
const image_type & Image() const noexcept
Definition: Image.h:5788
const filter_type & Filter() const noexcept
Definition: Image.h:5797
const sample * Position(int channel) const noexcept
Definition: Image.h:5815
typename image_type::pixel_traits pixel_traits
Definition: Image.h:5703
const_roi_filter_pixel_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:5928
Immutable region-of-interest, filter pixel sample iterator.
Definition: Image.h:3109
const sample * Position() const noexcept
Definition: Image.h:3262
const_roi_filter_sample_iterator(const image_type &image, const F &filter, const sample *i, const sample *j)
Definition: Image.h:3188
const_roi_filter_sample_iterator(const const_roi_sample_iterator &i, const F &filter)
Definition: Image.h:3197
const_roi_filter_sample_iterator(const const_roi_filter_sample_iterator &)=default
const filter_type & Filter() const noexcept
Definition: Image.h:3244
typename image_type::pixel_traits pixel_traits
Definition: Image.h:3120
const_roi_filter_sample_iterator(const image_type &image, const F &filter, const Rect &rect=Rect(0), int channel=-1)
Definition: Image.h:3165
const image_type & Image() const noexcept
Definition: Image.h:3235
const_roi_filter_sample_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:3375
Immutable region-of-interest pixel iterator.
Definition: Image.h:4353
typename image_type::sample sample
Definition: Image.h:4369
const_roi_pixel_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:4540
const sample * Position(int channel) const noexcept
Definition: Image.h:4429
const image_type & Image() const noexcept
Definition: Image.h:4420
const_roi_pixel_iterator(const const_roi_pixel_iterator &)=default
const_roi_pixel_iterator(const image_type &image, const Rect &rect=Rect(0))
Definition: Image.h:4392
typename image_type::pixel_traits pixel_traits
Definition: Image.h:4364
Immutable region-of-interest pixel sample iterator.
Definition: Image.h:1454
const_roi_sample_iterator(const const_roi_sample_iterator &)=default
const_roi_sample_iterator(const image_type &image, const Rect &rect=Rect(0), int channel=-1)
Definition: Image.h:1501
const sample * Position() const noexcept
Definition: Image.h:1586
const_roi_sample_iterator(const image_type &image, const sample *i, const sample *j)
Definition: Image.h:1522
const_roi_sample_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:1697
const image_type & Image() const noexcept
Definition: Image.h:1577
const_roi_sample_iterator(const roi_sample_iterator &i)
Definition: Image.h:1535
typename image_type::sample sample
Definition: Image.h:1470
typename image_type::pixel_traits pixel_traits
Definition: Image.h:1465
Immutable pixel sample iterator.
Definition: Image.h:689
const_sample_iterator(const image_type &image, int channel=-1)
Definition: Image.h:725
const_sample_iterator(const sample_iterator &i)
Definition: Image.h:765
typename image_type::sample sample
Definition: Image.h:705
typename image_type::pixel_traits pixel_traits
Definition: Image.h:700
const_sample_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:917
bool IsValid() const noexcept
Definition: Image.h:798
const image_type & Image() const noexcept
Definition: Image.h:807
const_sample_iterator(const image_type &image, const sample *i, const sample *j)
Definition: Image.h:751
const_sample_iterator(const const_sample_iterator &)=default
const sample * Position() const noexcept
Definition: Image.h:816
Mutable filter pixel iterator.
Definition: Image.h:4691
typename image_type::pixel_traits pixel_traits
Definition: Image.h:4702
bool IsValid() const noexcept
Definition: Image.h:4768
filter_pixel_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:4918
sample * Position(int channel) const noexcept
Definition: Image.h:4803
filter_pixel_iterator(const pixel_iterator &i, const F &filter)
Definition: Image.h:4739
filter_pixel_iterator(const filter_pixel_iterator &)=default
typename image_type::sample sample
Definition: Image.h:4707
const filter_type & Filter() const noexcept
Definition: Image.h:4785
filter_type & Filter() noexcept
Definition: Image.h:4794
filter_pixel_iterator(image_type &image, const F &filter)
Definition: Image.h:4730
image_type & Image() const noexcept
Definition: Image.h:4776
Mutable filter pixel sample iterator.
Definition: Image.h:1887
sample * Position() const noexcept
Definition: Image.h:2029
filter_sample_iterator(const sample_iterator &i, const F &filter)
Definition: Image.h:1966
filter_sample_iterator(const filter_sample_iterator &i)=default
filter_sample_iterator(image_type &image, const F &filter, int channel=-1)
Definition: Image.h:1934
filter_type & Filter() noexcept
Definition: Image.h:2021
image_type & Image() const noexcept
Definition: Image.h:2003
filter_sample_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:2138
const filter_type & Filter() const noexcept
Definition: Image.h:2012
filter_sample_iterator(image_type &image, const F &filter, sample *i, sample *j)
Definition: Image.h:1957
typename image_type::sample sample
Definition: Image.h:1903
typename image_type::pixel_traits pixel_traits
Definition: Image.h:1898
Mutable pixel iterator.
Definition: Image.h:3484
typename image_type::pixel_traits pixel_traits
Definition: Image.h:3495
pixel_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:3663
pixel_iterator(image_type &image)
Definition: Image.h:3512
image_type & Image() const noexcept
Definition: Image.h:3547
sample * Position(int channel) const noexcept
Definition: Image.h:3556
pixel_iterator(const pixel_iterator &)=default
typename image_type::sample sample
Definition: Image.h:3500
bool IsValid() const noexcept
Definition: Image.h:3539
Mutable region-of-interest, filter pixel iterator.
Definition: Image.h:5382
roi_filter_pixel_iterator(const roi_filter_pixel_iterator &)=default
sample * Position(int channel) const noexcept
Definition: Image.h:5502
roi_filter_pixel_iterator(const roi_pixel_iterator &i, const F &filter)
Definition: Image.h:5439
roi_filter_pixel_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:5615
filter_type & Filter() noexcept
Definition: Image.h:5493
typename image_type::sample sample
Definition: Image.h:5398
image_type & Image() const noexcept
Definition: Image.h:5475
roi_filter_pixel_iterator(image_type &image, const F &filter, const Rect &rect=Rect(0))
Definition: Image.h:5430
const filter_type & Filter() const noexcept
Definition: Image.h:5484
typename image_type::pixel_traits pixel_traits
Definition: Image.h:5393
Mutable region-of-interest, filter pixel sample iterator.
Definition: Image.h:2734
roi_filter_sample_iterator(const roi_filter_sample_iterator &)=default
roi_filter_sample_iterator(image_type &image, const F &filter, const Rect &rect=Rect(0), int channel=-1)
Definition: Image.h:2790
roi_filter_sample_iterator(image_type &image, const F &filter, sample *i, sample *j)
Definition: Image.h:2813
sample * Position() const noexcept
Definition: Image.h:2885
typename image_type::sample sample
Definition: Image.h:2750
roi_filter_sample_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:2998
const filter_type & Filter() const noexcept
Definition: Image.h:2868
image_type & Image() const noexcept
Definition: Image.h:2859
typename image_type::pixel_traits pixel_traits
Definition: Image.h:2745
roi_filter_sample_iterator(const roi_sample_iterator &i, const F &filter)
Definition: Image.h:2822
Mutable region-of-interest pixel iterator.
Definition: Image.h:4097
roi_pixel_iterator(const roi_pixel_iterator &)=default
sample * Position(int channel) const noexcept
Definition: Image.h:4172
typename image_type::sample sample
Definition: Image.h:4113
roi_pixel_iterator(image_type &image, const Rect &rect=Rect(0))
Definition: Image.h:4136
typename image_type::pixel_traits pixel_traits
Definition: Image.h:4108
image_type & Image() const noexcept
Definition: Image.h:4163
bool IsValid() const noexcept
Definition: Image.h:4155
roi_pixel_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:4283
Mutable region-of-interest pixel sample iterator.
Definition: Image.h:1133
sample * Position() const noexcept
Definition: Image.h:1236
roi_sample_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:1347
roi_sample_iterator(image_type &image, const Rect &rect=Rect(0), int channel=-1)
Definition: Image.h:1180
roi_sample_iterator(const roi_sample_iterator &)=default
typename image_type::pixel_traits pixel_traits
Definition: Image.h:1144
image_type & Image() const noexcept
Definition: Image.h:1228
typename image_type::sample sample
Definition: Image.h:1149
roi_sample_iterator(image_type &image, sample *i, sample *j)
Definition: Image.h:1201
bool IsValid() const noexcept
Definition: Image.h:1220
Mutable pixel sample iterator.
Definition: Image.h:355
sample_iterator(image_type &image, sample *i, sample *j)
Definition: Image.h:418
sample_iterator & MoveBy(int dx, int dy) noexcept
Definition: Image.h:556
typename image_type::sample sample
Definition: Image.h:371
sample * Position() const noexcept
Definition: Image.h:455
sample_iterator(image_type &image, int channel=-1)
Definition: Image.h:391
sample_iterator(const sample_iterator &)=default
typename image_type::pixel_traits pixel_traits
Definition: Image.h:366
bool IsValid() const noexcept
Definition: Image.h:439
image_type & Image() const noexcept
Definition: Image.h:447
Implements a generic, two-dimensional, shared or local image.
Definition: Image.h:278
GenericImage & ShiftToBottomRight(int width, int height, const GenericVector< T > &fillValues)
Definition: Image.h:14119
double Norm(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:13101
const sample * ScanLine(int y, int channel=0) const noexcept
Definition: Image.h:6834
void LocateExtremeSampleValues(Point &pmin, T &min, Point &pmax, T &max, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11455
GenericImage & CropBy(int left, int top, int right, int bottom, const GenericVector< T > &fillValues)
Definition: Image.h:13675
double Sn(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:12940
GenericImage & Write(File &file, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:13513
GenericImage & ShiftToBottomRight(int width, int height)
Definition: Image.h:14138
GenericImage Rescaled(T lowerBound, T upperBound, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8527
GenericImage & Fill(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:7881
GenericImage & Max(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10551
uint32 Hash32(int channel=-1, uint32 seed=0) const noexcept
Definition: Image.h:13478
GenericImage & ShiftToTopLeft(int width, int height, const GenericVector< T > &fillValues)
Definition: Image.h:14032
GenericImage & ShiftTo(const Point &p, const GenericVector< T > &fillValues)
Definition: Image.h:13977
~GenericImage() override
Definition: Image.h:6306
GenericImage Applied(const ImageTransformation &transformation, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:9489
GenericImage & Subtract(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10322
GenericImage Divided(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:9959
GenericImage & FreeData()
Definition: Image.h:6527
GenericImage Added(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:9797
GenericImage & Assign(const GenericImage< P1 > &image, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:7150
GenericImage & SetMinimum(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10074
GenericImage & Xnor(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10248
GenericImage & Transfer(GenericImage &image)
Definition: Image.h:7299
GenericImage & Apply(const GenericImage< P1 > &image, image_op op=ImageOp::Mov, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9231
GenericImage Blended(const Bitmap &bitmap, const Point &point=Point(int_max), const Rect &rect=Rect(0)) const
Definition: Image.h:9724
GenericImage & SetMaximum(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10118
static int BytesPerSample() noexcept
Definition: Image.h:6015
void GetExtremePixelValues(sample &min, sample &max, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11041
GenericImage(const GenericImage< P1 > &image, const Rect &rect, int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:6180
sample & Pixel(int x, int y, int channel=0)
Definition: Image.h:7017
sample & Pixel(const Point &p, int channel=0)
Definition: Image.h:7041
double Qn(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:13023
GenericImage Raised(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:10011
void GetIntensity(GenericImage< P1 > &I, const Rect &rect=Rect(0), int maxProcessors=0) const
Definition: Image.h:14673
GenericImage & ForgetAlphaChannels()
Definition: Image.h:7818
GenericImage & Nor(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10627
GenericImage & Raise(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9977
bool SameSampleType(const GenericImage< P1 > &image) const noexcept
Definition: Image.h:6037
GenericImage & Sub(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9824
GenericImage & ShiftToBottomLeft(int width, int height, const GenericVector< T > &fillValues)
Definition: Image.h:14090
void LocateExtremeSampleValues(int &xmin, int &ymin, T &min, int &xmax, int &ymax, T &max, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11355
const sample * PixelAddress(const Point &p, int channel=0) const noexcept
Definition: Image.h:6919
GenericImage Inverted(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8177
GenericImage Truncated(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8368
GenericImage Subtracted(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:9849
GenericImage & CropTo(int x0, int y0, int x1, int y1, const GenericVector< T > &fillValues)
Definition: Image.h:13842
sample * PixelAddress(int x, int y, int channel=0)
Definition: Image.h:6864
GenericImage & Crop(const GenericVector< T > &fillValues)
Definition: Image.h:13874
GenericImage & Move(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10266
GenericImage & Mov(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9756
double Mean(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11560
size_type ImageSize() const noexcept
Definition: Image.h:6682
GenericImage & Read(File &file)
Definition: Image.h:13601
TwoSidedEstimate TwoSidedAvgDev(double center, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:12199
GenericImage & Or(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10163
void GetLightness(GenericImage< P1 > &L, const Rect &rect=Rect(0), int maxProcessors=0) const
Definition: Image.h:14550
pixel_allocator & Allocator() const noexcept
Definition: Image.h:6434
GenericImage & SetColumn(const T *buffer, int x, int channel=-1)
Definition: Image.h:7546
sample LocateMaximumPixelValue(Point &pmax, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11311
uint64 Hash(int channel=-1, uint64 seed=0) const noexcept
Definition: Image.h:13489
static bool IsComplexSample() noexcept
Definition: Image.h:6006
GenericImage & Nand(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10231
GenericImage & Multiply(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9867
GenericImage Applied(const GenericImage< P1 > &image, image_op op=ImageOp::Mov, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:9420
GenericImage Applied(T scalar, image_op op=ImageOp::Mov, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:9176
GenericImage & SetMinimum(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10510
GenericImage & SetLightness(const GenericImage< P1 > &L, const Point &point=Point(int_max), const Rect &rect=Rect(0), int maxProcessors=0)
Definition: Image.h:14940
GenericImage & Crop()
Definition: Image.h:13890
GenericImage Multiplied(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:9901
sample LocateMinimumPixelValue(int &xmin, int &ymin, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11164
GenericImage Binarized(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8898
double MeanOfSquares(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:13313
GenericImage & White(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8067
GenericImage & ShiftToTopRight(int width, int height, const GenericVector< T > &fillValues)
Definition: Image.h:14061
GenericImage & DeleteAlphaChannel(int channel)
Definition: Image.h:7732
GenericImage & CropTo(int x0, int y0, int x1, int y1)
Definition: Image.h:13858
GenericImage & Binarize(T threshold, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8808
sample Pixel(int x, int y, int channel=0) const noexcept
Definition: Image.h:7029
GenericImage Binarized(T threshold, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8858
GenericImage & SetAbsoluteValue(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8918
GenericImage AbsoluteValue(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8972
GenericImage & ShiftToCenter(int width, int height, const GenericVector< T > &fillValues)
Definition: Image.h:14003
bool SameSampleType(const GenericImage &image) const noexcept
Definition: Image.h:6049
GenericImage & Nor(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10214
bool IsUnique() const noexcept
Definition: Image.h:6348
void GetExtremeSampleValues(T &min, T &max, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:10979
GenericImage & Dif(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10491
GenericImage & CropTo(const Rect &rect)
Definition: Image.h:13826
GenericImage & EnsureLocal()
Definition: Image.h:6365
GenericImage(int width, int height, color_space colorSpace=ColorSpace::Gray)
Definition: Image.h:6204
GenericImage & Sub(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10333
GenericImage & Mov(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10277
GenericImage & Black(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8049
size_type LineSize() const noexcept
Definition: Image.h:6662
static int BitsPerSample() noexcept
Definition: Image.h:6024
GenericImage & SetColorSpace(color_space colorSpace, int maxProcessors=0)
Definition: Image.h:14210
GenericImage & Invert(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8089
GenericImage AbsoluteDifference(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:10056
void GetColumn(T *buffer, int x, int channel=-1) const
Definition: Image.h:7479
double AvgDev(double center, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:12130
bool IsShared() const noexcept
Definition: Image.h:6333
sample * PixelData(int channel=0)
Definition: Image.h:6721
sample LocateMaximumSampleValue(Point &pmax, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11287
GenericImage & CropTo(const Rect &rect, const GenericVector< T > &fillValues)
Definition: Image.h:13809
GenericImage Truncated(T lowerBound, T upperBound, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8324
GenericImage & ReleaseAlphaChannel(GenericImage &image, int channel)
Definition: Image.h:7679
GenericImage(GenericImage &&image)
Definition: Image.h:6113
TwoSidedEstimate TwoSidedMAD(double center, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:12453
double SumOfSquares(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:13243
GenericImage & ShiftTo(int x, int y)
Definition: Image.h:13961
GenericImage & Truncate(T lowerBound, T upperBound, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8262
GenericImage & And(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10589
GenericImage Maximum(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:10144
GenericImage & Divide(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10402
sample MaximumSampleValue(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:10897
sample_vector ColVector(int x, int channel=0) const
Definition: Image.h:7419
GenericImage & Shift()
Definition: Image.h:14170
GenericImage & Raise(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10441
GenericImage & Mul(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9876
sample_vector ColumnVector(int x, int channel=-1) const
Definition: Image.h:7403
size_type Count(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11490
GenericImage & Normalize(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8756
GenericImage & Nand(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10646
GenericImage & Not(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8209
GenericImage & ShiftToTopRight(int width, int height)
Definition: Image.h:14080
GenericImage & Div(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9931
sample MaximumPixelValue(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:10946
GenericImage & SetRow(const T *buffer, int y, int channel=-1)
Definition: Image.h:7514
double Variance(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11985
GenericImage & SetAbsoluteDifference(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10480
void GetRow(T *buffer, int y, int channel=-1) const
Definition: Image.h:7448
GenericImage & Div(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10413
GenericImage & ForgetAlphaChannel(int channel)
Definition: Image.h:7762
GenericImage & EnsureUnique()
Definition: Image.h:6401
GenericImage Minimum(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:10100
typename pixel_traits::sample sample
Definition: Image.h:305
GenericImage(void *handle)
Definition: Image.h:6250
void SetRGBWorkingSpace(const RGBColorSystem &RGBWS) override
Definition: Image.h:7068
GenericImage Filled(const GenericVector< T > &values, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:7990
GenericImage(void *, int width, int height, color_space colorSpace=ColorSpace::Gray)
Definition: Image.h:6283
GenericImage & ImportData(sample **data, int width, int height, int numberOfChannels=1, color_space colorSpace=ColorSpace::Gray)
Definition: Image.h:6597
GenericImage & And(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10180
GenericImage & Mul(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10371
size_type ChannelSize() const noexcept
Definition: Image.h:6671
sample LocateMaximumSampleValue(int &xmax, int &ymax, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11209
GenericImage & Rescale(T lowerBound, T upperBound, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8404
sample ** ReleaseData()
Definition: Image.h:6647
GenericImage & Exchange(GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10712
GenericImage & Blend(const Bitmap &bitmap, const Point &point=Point(int_max), const Rect &rect=Rect(0))
Definition: Image.h:9567
GenericImage & ShiftBy(int dx, int dy)
Definition: Image.h:13933
sample * ScanLine(int y, int channel=0)
Definition: Image.h:6820
GenericImage & ShiftToBottomLeft(int width, int height)
Definition: Image.h:14109
double BiweightMidvariance(double center, double sigma, int k=9, bool reducedLength=false, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:12671
GenericImage & Fill(const GenericVector< T > &values, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:7928
GenericImage & Divide(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9922
GenericImage & Rescale(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8551
GenericImage & Add(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10295
GenericImage & Pow(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10452
GenericImage & SetMaximum(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10540
sample LocateMinimumSampleValue(Point &pmin, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11152
GenericImage & ShiftBy(int dx, int dy, const GenericVector< T > &fillValues)
Definition: Image.h:13917
const sample * PixelData(int channel=0) const noexcept
Definition: Image.h:6734
uint64 Hash64(int channel=-1, uint64 seed=0) const noexcept
Definition: Image.h:13459
GenericImage(const GenericImage< P1 > &image)
Definition: Image.h:6133
GenericImage & Xor(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10608
GenericImage & AllocateData(const Rect &rect, int numberOfChannels=1, color_space colorSpace=ColorSpace::Gray)
Definition: Image.h:6509
GenericImage & Min(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10083
GenericImage & Apply(T scalar, image_op op=ImageOp::Mov, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9119
GenericImage & SetAbsoluteDifference(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10030
static bool IsFloatSample() noexcept
Definition: Image.h:5997
void GetLuminance(GenericImage< P1 > &Y, const Rect &rect=Rect(0), int maxProcessors=0) const
Definition: Image.h:14418
GenericImage & Invert(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8161
GenericImage & One(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8031
sample_vector RowVector(int y, int channel=-1) const
Definition: Image.h:7374
Vector Norms(int maxDegree=2, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:13398
GenericImage & Move(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9747
GenericImage & Xchg(GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10795
double StdDev(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:12085
GenericImage & Subtract(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9815
Compression::subblock_list Compress(const Compression &compressor, const Rect &rect=Rect(0), int channel=-1, Compression::Performance *perf=nullptr) const
Definition: Image.h:15060
GenericImage & AllocateData(int width, int height, int numberOfChannels=1, color_space colorSpace=ColorSpace::Gray)
Definition: Image.h:6484
sample * PixelAddress(const Point &p, int channel=0)
Definition: Image.h:6907
sample MinimumPixelValue(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:10872
GenericImage & SetLuminance(const GenericImage< P1 > &Y, const Point &point=Point(int_max), const Rect &rect=Rect(0), int maxProcessors=0)
Definition: Image.h:14799
sample Pixel(const Point &p, int channel=0) const noexcept
Definition: Image.h:7054
GenericImage & ShiftToCenter(int width, int height)
Definition: Image.h:14022
sample LocateMaximumPixelValue(int &xmax, int &ymax, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11299
GenericImage & Add(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9772
GenericImage & Write(const String &filePath, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:13558
GenericImage Inverted(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8137
GenericImage & CropBy(int left, int top, int right, int bottom)
Definition: Image.h:13793
GenericImage & Min(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10521
GenericImage & Transfer(GenericImage &&image)
Definition: Image.h:7315
double OrderStatistic(double k, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11821
GenericImage & Truncate(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8353
sample MinimumSampleValue(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:10823
GenericImage & ShiftToTopLeft(int width, int height)
Definition: Image.h:14051
GenericImage & Or(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10570
double MAD(double center, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:12286
friend void Swap(GenericImage &x1, GenericImage &x2) noexcept
Definition: Image.h:7346
GenericImage & CreateAlphaChannels(int n)
Definition: Image.h:7571
GenericImage Normalized(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8771
GenericImage(File &stream)
Definition: Image.h:6225
GenericImage & Normalize(T lowerBound, T upperBound, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8608
GenericImage & Max(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10127
GenericImage & Pow(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:9986
double Median(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11633
GenericImage & DeleteAlphaChannels()
Definition: Image.h:7794
size_type NominalSize() const noexcept
Definition: Image.h:6692
GenericImage Filled(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:7971
GenericImage & Read(const String &filePath)
Definition: Image.h:13636
GenericImage & Binarize(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8882
GenericImage & Dif(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10039
GenericImage(const GenericImage &image)
Definition: Image.h:6094
sample LocateMinimumPixelValue(Point &pmin, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11176
GenericImage Normalized(T lowerBound, T upperBound, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8732
GenericImage & Shift(const GenericVector< T > &fillValues)
Definition: Image.h:14154
GenericImage & Xor(T scalar, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10197
sample LocateMinimumSampleValue(int &xmin, int &ymin, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:11074
GenericImage & ShiftTo(int x, int y, const GenericVector< T > &fillValues)
Definition: Image.h:13945
double Modulus(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:13173
GenericImage & AddAlphaChannel(sample *data=nullptr)
Definition: Image.h:7620
const sample * PixelAddress(int x, int y, int channel=0) const noexcept
Definition: Image.h:6879
GenericImage & ShiftTo(const Point &p)
Definition: Image.h:13993
GenericImage & Xnor(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10665
double BendMidvariance(double center, double beta=0.2, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:12854
size_type AlphaSize() const noexcept
Definition: Image.h:6702
GenericImage & Abs(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8957
GenericImage Rescaled(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1) const
Definition: Image.h:8566
GenericImage & Zero(const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:8012
GenericImage & Multiply(const GenericImage< P1 > &image, const Point &point=Point(int_max), int channel=-1, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1)
Definition: Image.h:10360
TwoSidedEstimate TwoSidedBiweightMidvariance(double center, const TwoSidedEstimate &sigma, int k=9, bool reducedLength=false, const Rect &rect=Rect(0), int firstChannel=-1, int lastChannel=-1, int maxProcessors=0) const
Definition: Image.h:12751
A generic point in the two-dimensional space.
Definition: Point.h:100
component x
Abscissa (horizontal, or X-axis coordinate).
Definition: Point.h:111
component y
Ordinate (vertical, or Y-axis coordinate).
Definition: Point.h:112
A generic rectangle in the two-dimensional space.
Definition: Rectangle.h:314
point LeftTop() const noexcept
Definition: Rectangle.h:527
component x1
Horizontal coordinate of the lower right corner.
Definition: Rectangle.h:334
component y1
Vertical coordinate of the lower right corner.
Definition: Rectangle.h:335
bool IsRect() const noexcept
Definition: Rectangle.h:762
void ResizeTo(T1 w, T1 h) noexcept
Definition: Rectangle.h:1476
component y0
Vertical coordinate of the upper left corner.
Definition: Rectangle.h:333
component x0
Horizontal coordinate of the upper left corner.
Definition: Rectangle.h:332
GenericRectangle MovedTo(const pcl::GenericPoint< T1 > &p) const noexcept
Definition: Rectangle.h:1367
GenericRectangle Ordered() const noexcept
Definition: Rectangle.h:794
component Width() const noexcept
Definition: Rectangle.h:635
component Height() const noexcept
Definition: Rectangle.h:644
GenericRectangle Intersection(const GenericRectangle< T1 > &r) const noexcept
Definition: Rectangle.h:1255
Generic vector of arbitrary length.
Definition: Vector.h:107
iterator Begin()
Definition: Vector.h:1900
int Length() const noexcept
Definition: Vector.h:1784
const RGBColorSystem & RGBWorkingSpace() const noexcept
Definition: ImageColor.h:110
color_space ColorSpace() const noexcept
Definition: ImageColor.h:178
int Width() const noexcept
Definition: ImageGeometry.h:90
Rect Bounds() const noexcept
Root base class of all PCL image transformations.
Acts like a union for all types of images in PCL, with optional class-wide ownership of transported i...
Definition: ImageVariant.h:322
32-bit floating point real image.
Manages transparent allocation and deallocation of shared and local pixel data.
32-bit integer point on the plane.
Colorimetrically defined RGB working color space.
32-bit integer rectangle on the plane.
Dynamic array of pointers to objects providing direct iteration and element access by reference.
size_type Length() const
void Destroy(iterator i, size_type n=1)
void Add(const ReferenceArray &x)
Thread-safe reference counter for copy-on-write data structures.
Unicode (UTF-16) string.
Definition: String.h:8113
size_type integer vector.
16-bit unsigned integer image.
32-bit unsigned integer image.
8-bit unsigned integer image.
64-bit floating point real vector.
bool operator==(const Array< T, A > &x1, const Array< T, A > &x2) noexcept
Definition: Array.h:2267
bool operator<(const Array< T, A > &x1, const Array< T, A > &x2) noexcept
Definition: Array.h:2278
const RGBA * ScanLine(int y) const
Complex< T > Sqrt(const Complex< T > &c) noexcept
Definition: Complex.h:674
T Abs(const Complex< T > &c) noexcept
Definition: Complex.h:429
int64 fsize_type
Definition: Defs.h:1185
uint64 Hash64(const void *data, size_type size, uint64 seed=0) noexcept
Definition: Math.h:4750
uint32 Hash32(const void *data, size_type size, uint32 seed=0) noexcept
Definition: Math.h:4904
GenericImage< P1 > operator-(const GenericImage< P1 > &image1, const GenericImage< P2 > &image2)
Definition: Image.h:17617
GenericImage< P1 > operator/(const GenericImage< P1 > &image1, const GenericImage< P2 > &image2)
Definition: Image.h:17658
GenericImage< P1 > operator+(const GenericImage< P1 > &image1, const GenericImage< P2 > &image2)
Definition: Image.h:17597
GenericImage< P1 > operator^(const GenericImage< P1 > &image1, const GenericImage< P2 > &image2)
Definition: Image.h:17679
GenericImage< P1 > operator*(const GenericImage< P1 > &image1, const GenericImage< P2 > &image2)
Definition: Image.h:17637
int TruncInt(T x) noexcept
Definition: Math.h:1132
constexpr T Pow2(T x) noexcept
Definition: Math.h:1717
void Swap(GenericPoint< T > &p1, GenericPoint< T > &p2) noexcept
Definition: Point.h:1459
unsigned long long uint64
Definition: Defs.h:682
unsigned char uint8
Definition: Defs.h:642
unsigned int uint32
Definition: Defs.h:666
uint32 RGBA
Definition: Color.h:92
RI Select(RI i, RI j, distance_type k)
Definition: Selection.h:165
ptrdiff_t distance_type
Definition: Defs.h:615
size_t size_type
Definition: Defs.h:609
double Qn(T *__restrict__ x, T *__restrict__ xn)
Definition: Math.h:4170
double BendMidvariance(const T *__restrict__ x, const T *__restrict__ xn, double center, double beta=0.2)
Definition: Math.h:4480
double Variance(const T *__restrict__ i, const T *__restrict__ j, double center) noexcept
Definition: Math.h:2753
double Median(const T *__restrict__ i, const T *__restrict__ j)
Definition: Math.h:2878
double Sn(T *__restrict__ x, T *__restrict__ xn)
Definition: Math.h:3924
#define INIT_THREAD_MONITOR()
Declares and initializes local variables used for synchronization of thread status monitoring.
#define UPDATE_THREAD_MONITOR(N)
Synchronized status monitoring of a set of image processing threads.
constexpr const T & Min(const T &a, const T &b) noexcept
Definition: Utility.h:90
constexpr const T & Range(const T &x, const T &a, const T &b) noexcept
Definition: Utility.h:190
constexpr const T & Max(const T &a, const T &b) noexcept
Definition: Utility.h:119
void Apply(FI i, FI j, F f) noexcept(noexcept(f))
Definition: Utility.h:249
int NumberOfNominalChannels(int colorSpace)
Definition: ColorSpace.h:102
String Name(int colorSpace)
bool IsBitwiseLogicalOperator(int op) noexcept
Definition: Image.h:183
bool IsPixelCompositionOperator(int op) noexcept
Definition: Image.h:201
String Id(value_type operation)
bool IsArithmeticOperator(int op) noexcept
Definition: Image.h:174
bool IsMoveOperator(int op) noexcept
Definition: Image.h:192
PCL root namespace.
Definition: AbstractImage.h:77
Thread synchronization data for status monitoring of parallel image processing tasks.
StatusMonitor status
Status monitoring object.
Compression/decompression performance measurements.
Definition: Compression.h:103
Two-sided descriptive statistical estimate.
Definition: Math.h:3528
double high
High estimate component.
Definition: Math.h:3530
double low
Low estimate component.
Definition: Math.h:3529