PCL
Image.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.1.19
6 // ----------------------------------------------------------------------------
7 // pcl/Image.h - Released 2019-11-07T10:59:34Z
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-2019 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 (http://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 )
175  {
176  return op >= Add && op <= Dif;
177  }
178 
183  inline bool IsBitwiseLogicalOperator( int op )
184  {
185  return op >= Or && op <= Xnor;
186  }
187 
192  inline bool IsMoveOperator( int op )
193  {
194  return op == Mov || op == Min || op == Max;
195  }
196 
201  inline bool IsPixelCompositionOperator( int op )
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_allocator m_data->allocator
216 
217 #define m_width m_geometry->width
218 #define m_height m_geometry->height
219 #define m_numberOfChannels m_geometry->numberOfChannels
220 
221 #define m_colorSpace m_color->colorSpace
222 #define m_RGBWS m_color->RGBWS
223 
224 #define m_channel m_selected.channel
225 #define m_lastChannel m_selected.lastChannel
226 #define m_point m_selected.point
227 #define m_rectangle m_selected.rectangle
228 #define m_clipLow m_selected.clipLow
229 #define m_clipHigh m_selected.clipHigh
230 #define m_clipped m_selected.clipped
231 
232 // ----------------------------------------------------------------------------
233 
234 class PCL_CLASS ImageVariant;
235 class PCL_CLASS ImageTransformation;
236 class PCL_CLASS BidirectionalImageTransformation;
237 
238 // ----------------------------------------------------------------------------
239 
274 template <class P>
275 class PCL_CLASS GenericImage : public AbstractImage
276 {
277 public:
278 
286  typedef P pixel_traits;
287 
298 
303  typedef typename pixel_traits::sample sample;
304 
310  typedef AbstractImage::color_space color_space;
311 
317 
323  typedef ImageOp::value_type image_op;
324 
329 
334 
335  // -------------------------------------------------------------------------
336 
341  // -------------------------------------------------------------------------
342 
353  {
354  public:
355 
360 
365 
369  typedef typename image_type::sample sample;
370 
375  m_image( nullptr ), m_iterator( nullptr ), m_end( nullptr )
376  {
377  }
378 
392  sample_iterator( image_type& image, int channel = -1 ) :
393  m_image( &image ), m_iterator( nullptr ), m_end( nullptr )
394  {
395  m_image->EnsureUnique();
396  if ( m_image->ParseChannel( channel ) )
397  {
398  m_iterator = (*m_image)[channel];
399  m_end = m_iterator + m_image->NumberOfPixels();
400  }
401  }
402 
419  sample_iterator( image_type& image, sample* i, sample* j ) :
420  m_image( &image ), m_iterator( i ), m_end( j )
421  {
422  }
423 
427  sample_iterator( const sample_iterator& ) = default;
428 
432  sample_iterator& operator =( const sample_iterator& ) = default;
433 
438  bool IsValid() const
439  {
440  return m_image != nullptr && m_iterator != nullptr;
441  }
442 
446  image_type& Image() const
447  {
448  return *m_image;
449  }
450 
454  sample* Position() const
455  {
456  return m_iterator;
457  }
458 
466  operator bool() const
467  {
468  return m_iterator < m_end;
469  }
470 
475  sample& operator *() const
476  {
477  return *m_iterator;
478  }
479 
485  sample_iterator& operator ++()
486  {
487  ++m_iterator;
488  return *this;
489  }
490 
496  sample_iterator operator ++( int )
497  {
498  return sample_iterator( *m_image, m_iterator++, m_end );
499  }
500 
506  sample_iterator& operator --()
507  {
508  --m_iterator;
509  return *this;
510  }
511 
517  sample_iterator operator --( int )
518  {
519  return sample_iterator( *m_image, m_iterator--, m_end );
520  }
521 
529  sample_iterator& operator +=( distance_type delta )
530  {
531  m_iterator += delta;
532  return *this;
533  }
534 
542  sample_iterator& operator -=( distance_type delta )
543  {
544  m_iterator -= delta;
545  return *this;
546  }
547 
555  sample_iterator& MoveBy( int dx, int dy )
556  {
557  m_iterator += distance_type( dy )*m_image->Width() + distance_type( dx );
558  return *this;
559  }
560 
566  {
567  return sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
568  }
569 
575  {
576  return sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
577  }
578 
584  {
585  return sample_iterator( *i.m_image, i.m_iterator - delta, i.m_end );
586  }
587 
593  {
594  return i.m_iterator - j.m_iterator;
595  }
596 
601  friend distance_type operator -( const sample_iterator& i, const sample* j )
602  {
603  return i.m_iterator - j;
604  }
605 
610  friend distance_type operator -( const sample* i, const sample_iterator& j )
611  {
612  return i - j.m_iterator;
613  }
614 
619  friend bool operator ==( const sample_iterator& i, const sample_iterator& j )
620  {
621  return i.m_iterator == j.m_iterator;
622  }
623 
628  friend bool operator ==( const sample_iterator& i, const sample* j )
629  {
630  return i.m_iterator == j;
631  }
632 
637  friend bool operator ==( const sample* i, const sample_iterator& j )
638  {
639  return i == j.m_iterator;
640  }
641 
646  friend bool operator <( const sample_iterator& i, const sample_iterator& j )
647  {
648  return i.m_iterator < j.m_iterator;
649  }
650 
654  friend bool operator <( const sample_iterator& i, const sample* j )
655  {
656  return i.m_iterator < j;
657  }
658 
662  friend bool operator <( const sample* i, const sample_iterator& j )
663  {
664  return i < j.m_iterator;
665  }
666 
667  protected:
668 
669  image_type* m_image;
670  sample* m_iterator;
671  const sample* m_end;
672 
673  friend class const_sample_iterator;
674  };
675 
676  // -------------------------------------------------------------------------
677 
688  {
689  public:
690 
695 
700 
704  typedef typename image_type::sample sample;
705 
710  m_image( nullptr ), m_iterator( nullptr ), m_end( nullptr )
711  {
712  }
713 
727  const_sample_iterator( const image_type& image, int channel = -1 ) :
728  m_image( &image ), m_iterator( nullptr ), m_end( nullptr )
729  {
730  if ( m_image->ParseChannel( channel ) )
731  {
732  m_iterator = (*m_image)[channel];
733  m_end = m_iterator + m_image->NumberOfPixels();
734  }
735  }
736 
753  const_sample_iterator( const image_type& image, const sample* i, const sample* j ) :
754  m_image( &image ), m_iterator( i ), m_end( j )
755  {
756  }
757 
766  m_image( i.m_image ), m_iterator( i.m_iterator ), m_end( i.m_end )
767  {
768  }
769 
773  const_sample_iterator( const const_sample_iterator& ) = default;
774 
779  const_sample_iterator& operator =( const sample_iterator& i )
780  {
781  m_image = i.m_image;
782  m_iterator = i.m_iterator;
783  m_end = i.m_end;
784  return *this;
785  }
786 
790  const_sample_iterator& operator =( const const_sample_iterator& ) = default;
791 
796  bool IsValid() const
797  {
798  return m_image != nullptr && m_iterator != nullptr;
799  }
800 
805  const image_type& Image() const
806  {
807  return *m_image;
808  }
809 
814  const sample* Position() const
815  {
816  return m_iterator;
817  }
818 
826  operator bool() const
827  {
828  return m_iterator < m_end;
829  }
830 
835  const sample& operator *() const
836  {
837  return *m_iterator;
838  }
839 
845  const_sample_iterator& operator ++()
846  {
847  ++m_iterator;
848  return *this;
849  }
850 
856  const_sample_iterator operator ++( int )
857  {
858  return const_sample_iterator( *m_image, m_iterator++, m_end );
859  }
860 
866  const_sample_iterator& operator --()
867  {
868  --m_iterator;
869  return *this;
870  }
871 
877  const_sample_iterator operator --( int )
878  {
879  return const_sample_iterator( *m_image, m_iterator--, m_end );
880  }
881 
889  const_sample_iterator& operator +=( distance_type delta )
890  {
891  m_iterator += delta;
892  return *this;
893  }
894 
902  const_sample_iterator& operator -=( distance_type delta )
903  {
904  m_iterator -= delta;
905  return *this;
906  }
907 
915  const_sample_iterator& MoveBy( int dx, int dy )
916  {
917  m_iterator += distance_type( dy )*m_image->Width() + distance_type( dx );
918  return *this;
919  }
920 
926  {
927  return const_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
928  }
929 
935  {
936  return const_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
937  }
938 
944  {
945  return const_sample_iterator( *i.m_image, i.m_iterator - delta, i.m_end );
946  }
947 
953  {
954  return i.m_iterator - j.m_iterator;
955  }
956 
961  friend distance_type operator -( const const_sample_iterator& i, const sample* j )
962  {
963  return i.m_iterator - j;
964  }
965 
970  friend distance_type operator -( const sample* i, const const_sample_iterator& j )
971  {
972  return i - j.m_iterator;
973  }
974 
979  friend bool operator ==( const const_sample_iterator& i, const const_sample_iterator& j )
980  {
981  return i.m_iterator == j.m_iterator;
982  }
983 
988  friend bool operator ==( const const_sample_iterator& i, const sample* j )
989  {
990  return i.m_iterator == j;
991  }
992 
997  friend bool operator ==( const sample* i, const const_sample_iterator& j )
998  {
999  return i == j.m_iterator;
1000  }
1001 
1006  friend bool operator <( const const_sample_iterator& i, const const_sample_iterator& j )
1007  {
1008  return i.m_iterator < j.m_iterator;
1009  }
1010 
1014  friend bool operator <( const const_sample_iterator& i, const sample* j )
1015  {
1016  return i.m_iterator < j;
1017  }
1018 
1022  friend bool operator <( const sample* i, const const_sample_iterator& j )
1023  {
1024  return i < j.m_iterator;
1025  }
1026 
1027  protected:
1028 
1029  const image_type* m_image;
1030  const sample* m_iterator;
1031  const sample* m_end;
1032  };
1033 
1034  // -------------------------------------------------------------------------
1035 
1036  template <class image_type, class sample_pointer>
1037  class roi_sample_iterator_base
1038  {
1039  protected:
1040 
1041  image_type* m_image;
1042  sample_pointer m_iterator;
1043  sample_pointer m_rowBegin;
1044  sample_pointer m_rowEnd;
1045  sample_pointer m_end;
1046 
1047  roi_sample_iterator_base() :
1048  m_image( nullptr ), m_iterator( nullptr ), m_rowBegin( nullptr ), m_rowEnd( nullptr ), m_end( nullptr )
1049  {
1050  }
1051 
1052  roi_sample_iterator_base( image_type& image, const Rect& rect, int channel ) :
1053  m_image( &image ), m_iterator( nullptr ), m_rowBegin( nullptr ), m_rowEnd( nullptr ), m_end( nullptr )
1054  {
1055  Rect r = rect;
1056  if ( m_image->ParseRect( r ) )
1057  {
1058  if ( m_image->ParseChannel( channel ) )
1059  {
1060  m_iterator = m_rowBegin = m_image->PixelAddress( r.x0, r.y0, channel );
1061  m_rowEnd = m_rowBegin + r.Width();
1062  m_end = m_rowEnd + ((r.Height() - 1)*m_image->Width());
1063  }
1064  }
1065  }
1066 
1067  roi_sample_iterator_base( image_type& image, sample_pointer i, sample_pointer j ) :
1068  m_image( &image ), m_iterator( nullptr ), m_rowBegin( nullptr ), m_rowEnd( nullptr ), m_end( nullptr )
1069  {
1070  if ( j < i )
1071  pcl::Swap( i, j );
1072  m_iterator = m_rowBegin = i;
1073  m_rowEnd = m_rowBegin + (j - i)%m_image->Width();
1074  m_end = j;
1075  }
1076 
1077  roi_sample_iterator_base( const roi_sample_iterator_base& i ) = default;
1078 
1079  roi_sample_iterator_base& operator =( const roi_sample_iterator_base& ) = default;
1080 
1081  void Increment()
1082  {
1083  if ( ++m_iterator == m_rowEnd )
1084  {
1085  m_rowBegin += m_image->Width();
1086  m_rowEnd += m_image->Width();
1087  m_iterator = m_rowBegin;
1088  }
1089  }
1090 
1091  void Decrement()
1092  {
1093  if ( m_iterator == m_rowBegin )
1094  {
1095  m_rowBegin -= m_image->Width();
1096  m_rowEnd -= m_image->Width();
1097  m_iterator = m_rowEnd;
1098  }
1099  --m_iterator;
1100  }
1101 
1102  void MoveBy( int cols, int rows )
1103  {
1104  cols += m_iterator - m_rowBegin;
1105  if ( cols != 0 )
1106  {
1107  int w = m_rowEnd - m_rowBegin;
1108  if ( pcl::Abs( cols ) >= w )
1109  {
1110  rows += cols/w;
1111  cols %= w;
1112  }
1113  }
1114  int dy = rows * m_image->Width();
1115  m_rowBegin += dy;
1116  m_rowEnd += dy;
1117  m_iterator = m_rowBegin + cols;
1118  }
1119  };
1120 
1121  // -------------------------------------------------------------------------
1122 
1133  class roi_sample_iterator : private roi_sample_iterator_base<GenericImage<P>, sample*>
1134  {
1135  public:
1136 
1141 
1146 
1150  typedef typename image_type::sample sample;
1151 
1152  typedef roi_sample_iterator_base<GenericImage<P>, sample*>
1153  iterator_base;
1154 
1159  iterator_base()
1160  {
1161  }
1162 
1185  roi_sample_iterator( image_type& image, const Rect& rect = Rect( 0 ), int channel = -1 ) :
1186  iterator_base( image.EnsureUnique(), rect, channel )
1187  {
1188  }
1189 
1206  roi_sample_iterator( image_type& image, sample* i, sample* j ) :
1207  iterator_base( image, i, j )
1208  {
1209  }
1210 
1214  roi_sample_iterator( const roi_sample_iterator& ) = default;
1215 
1219  roi_sample_iterator& operator =( const roi_sample_iterator& ) = default;
1220 
1225  bool IsValid() const
1226  {
1227  return this->m_image != nullptr && this->m_iterator != nullptr;
1228  }
1229 
1233  image_type& Image() const
1234  {
1235  return *this->m_image;
1236  }
1237 
1241  sample* Position() const
1242  {
1243  return this->m_iterator;
1244  }
1245 
1252  operator bool() const
1253  {
1254  return this->m_iterator < this->m_end;
1255  }
1256 
1261  sample& operator *() const
1262  {
1263  return *this->m_iterator;
1264  }
1265 
1271  roi_sample_iterator& operator ++()
1272  {
1273  this->Increment();
1274  return *this;
1275  }
1276 
1282  roi_sample_iterator operator ++( int )
1283  {
1284  roi_sample_iterator i0( *this );
1285  this->Increment();
1286  return i0;
1287  }
1288 
1294  roi_sample_iterator& operator --()
1295  {
1296  this->Decrement();
1297  return *this;
1298  }
1299 
1305  roi_sample_iterator operator --( int )
1306  {
1307  roi_sample_iterator i0( *this );
1308  this->Decrement();
1309  return i0;
1310  }
1311 
1321  roi_sample_iterator& operator +=( distance_type delta )
1322  {
1323  int w = this->m_rowEnd - this->m_rowBegin;
1324  iterator_base::MoveBy( delta%w, delta/w );
1325  return *this;
1326  }
1327 
1337  roi_sample_iterator& operator -=( distance_type delta )
1338  {
1339  int w = this->m_rowEnd - this->m_rowBegin;
1340  iterator_base::MoveBy( -delta%w, -delta/w );
1341  return *this;
1342  }
1343 
1352  roi_sample_iterator& MoveBy( int dx, int dy )
1353  {
1354  iterator_base::MoveBy( dx, dy );
1355  return *this;
1356  }
1357 
1363  {
1364  roi_sample_iterator j( i );
1365  j += delta;
1366  return j;
1367  }
1368 
1374  {
1375  roi_sample_iterator j( i );
1376  j += delta;
1377  return j;
1378  }
1379 
1385  {
1386  roi_sample_iterator j( i );
1387  j -= delta;
1388  return j;
1389  }
1390 
1395  friend bool operator ==( const roi_sample_iterator& i, const roi_sample_iterator& j )
1396  {
1397  return i.m_iterator == j.m_iterator;
1398  }
1399 
1404  friend bool operator ==( const roi_sample_iterator& i, const sample* j )
1405  {
1406  return i.m_iterator == j;
1407  }
1408 
1413  friend bool operator ==( const sample* i, const roi_sample_iterator& j )
1414  {
1415  return i == j.m_iterator;
1416  }
1417 
1422  friend bool operator <( const roi_sample_iterator& i, const roi_sample_iterator& j )
1423  {
1424  return i.m_iterator < j.m_iterator;
1425  }
1426 
1430  friend bool operator <( const roi_sample_iterator& i, const sample* j )
1431  {
1432  return i.m_iterator < j;
1433  }
1434 
1438  friend bool operator <( const sample* i, const roi_sample_iterator& j )
1439  {
1440  return i < j.m_iterator;
1441  }
1442 
1443  friend class const_roi_pixel_iterator;
1444  };
1445 
1446  // -------------------------------------------------------------------------
1447 
1458  class const_roi_sample_iterator : private roi_sample_iterator_base<const GenericImage<P>, const sample*>
1459  {
1460  public:
1461 
1466 
1471 
1475  typedef typename image_type::sample sample;
1476 
1477  typedef roi_sample_iterator_base<const GenericImage<P>, const sample*>
1478  iterator_base;
1479 
1484  iterator_base()
1485  {
1486  }
1487 
1510  const_roi_sample_iterator( const image_type& image, const Rect& rect = Rect( 0 ), int channel = -1 ) :
1511  iterator_base( image, rect, channel )
1512  {
1513  }
1514 
1531  const_roi_sample_iterator( const image_type& image, const sample* i, const sample* j ) :
1532  iterator_base( image, i, j )
1533  {
1534  }
1535 
1545  iterator_base( i.m_image, i.m_rowBegin, i.m_end )
1546  {
1547  }
1548 
1553 
1559  {
1560  this->m_image = i.m_image;
1561  this->m_iterator = i.m_iterator;
1562  this->m_rowBegin = i.m_rowBegin;
1563  this->m_rowEnd = i.m_rowEnd;
1564  this->m_end = i.m_end;
1565  return *this;
1566  }
1567 
1571  const_roi_sample_iterator& operator =( const const_roi_sample_iterator& ) = default;
1572 
1577  bool IsValid() const
1578  {
1579  return this->m_image != nullptr && this->m_iterator != nullptr;
1580  }
1581 
1586  const image_type& Image() const
1587  {
1588  return *this->m_image;
1589  }
1590 
1595  const sample* Position() const
1596  {
1597  return this->m_iterator;
1598  }
1599 
1606  operator bool() const
1607  {
1608  return this->m_iterator < this->m_end;
1609  }
1610 
1615  const sample& operator *() const
1616  {
1617  return *this->m_iterator;
1618  }
1619 
1626  {
1627  this->Increment();
1628  return *this;
1629  }
1630 
1636  const_roi_sample_iterator operator ++( int )
1637  {
1638  const_roi_sample_iterator i0( *this );
1639  this->Increment();
1640  return i0;
1641  }
1642 
1649  {
1650  this->Decrement();
1651  return *this;
1652  }
1653 
1659  const_roi_sample_iterator operator --( int )
1660  {
1661  const_roi_sample_iterator i0( *this );
1662  this->Decrement();
1663  return i0;
1664  }
1665 
1676  {
1677  int w = this->m_rowEnd - this->m_rowBegin;
1678  iterator_base::MoveBy( delta%w, delta/w );
1679  return *this;
1680  }
1681 
1692  {
1693  int w = this->m_rowEnd - this->m_rowBegin;
1694  iterator_base::MoveBy( -delta%w, -delta/w );
1695  return *this;
1696  }
1697 
1707  {
1708  iterator_base::MoveBy( dx, dy );
1709  return *this;
1710  }
1711 
1717  {
1719  j += delta;
1720  return j;
1721  }
1722 
1728  {
1730  j += delta;
1731  return j;
1732  }
1733 
1739  {
1741  j -= delta;
1742  return j;
1743  }
1744 
1750  {
1751  return i.m_iterator == j.m_iterator;
1752  }
1753 
1758  friend bool operator ==( const const_roi_sample_iterator& i, const sample* j )
1759  {
1760  return i.m_iterator == j;
1761  }
1762 
1767  friend bool operator ==( const sample* i, const const_roi_sample_iterator& j )
1768  {
1769  return i == j.m_iterator;
1770  }
1771 
1777  {
1778  return i.m_iterator < j.m_iterator;
1779  }
1780 
1784  friend bool operator <( const const_roi_sample_iterator& i, const sample* j )
1785  {
1786  return i.m_iterator < j;
1787  }
1788 
1792  friend bool operator <( const sample* i, const const_roi_sample_iterator& j )
1793  {
1794  return i < j.m_iterator;
1795  }
1796  };
1797 
1798  // -------------------------------------------------------------------------
1799 
1800  template <class image_type, class iterator_base, class sample_pointer, class filter_type>
1801  class filter_sample_iterator_base : public iterator_base
1802  {
1803  protected:
1804 
1805  filter_type m_filter;
1806  sample_pointer m_begin;
1807 
1808  filter_sample_iterator_base() :
1809  iterator_base(), m_filter(), m_begin( nullptr )
1810  {
1811  }
1812 
1813  filter_sample_iterator_base( image_type& image, const filter_type& filter, int channel ) :
1814  iterator_base( image, channel ), m_filter( filter ), m_begin( iterator_base::m_iterator )
1815  {
1816  JumpToNextValidSample();
1817  }
1818 
1819  filter_sample_iterator_base( image_type& image, const filter_type& filter, sample_pointer i, sample_pointer j ) :
1820  iterator_base( image, i, j ), m_filter( filter ), m_begin( iterator_base::m_iterator )
1821  {
1822  JumpToNextValidSample();
1823  }
1824 
1825  filter_sample_iterator_base( const iterator_base& i, const filter_type& filter ) :
1826  iterator_base( i ), m_filter( filter ), m_begin( iterator_base::m_iterator )
1827  {
1828  JumpToNextValidSample();
1829  }
1830 
1831  filter_sample_iterator_base( const filter_sample_iterator_base& ) = default;
1832 
1833  filter_sample_iterator_base& operator =( const filter_sample_iterator_base& ) = default;
1834 
1835  filter_sample_iterator_base& operator =( const iterator_base& i )
1836  {
1837  (void)iterator_base::operator =( i );
1838  JumpToNextValidSample();
1839  return *this;
1840  }
1841 
1842  void JumpToNextValidSample()
1843  {
1844  while ( this->m_iterator < this->m_end && !this->m_filter( *this->m_iterator ) )
1845  ++this->m_iterator;
1846  }
1847 
1848  void JumpToPrevValidSample()
1849  {
1850  while ( this->m_iterator > this->m_begin && !this->m_filter( *this->m_iterator ) )
1851  --this->m_iterator;
1852  }
1853  };
1854 
1855  // -------------------------------------------------------------------------
1856 
1890  template <class F>
1892  public filter_sample_iterator_base<GenericImage<P>, sample_iterator, sample*, F>
1893  {
1894  public:
1895 
1900 
1905 
1909  typedef typename image_type::sample sample;
1910 
1915  typedef F filter_type;
1916 
1917  typedef filter_sample_iterator_base<GenericImage<P>, sample_iterator, sample*, F>
1918  iterator_base;
1919 
1924  iterator_base()
1925  {
1926  }
1927 
1944  filter_sample_iterator( image_type& image, const F& filter, int channel = -1 ) :
1945  iterator_base( image.EnsureUnique(), filter, channel )
1946  {
1947  }
1948 
1967  filter_sample_iterator( image_type& image, const F& filter, sample* i, sample* j ) :
1968  iterator_base( image, filter, i, j )
1969  {
1970  }
1971 
1976  filter_sample_iterator( const sample_iterator& i, const F& filter ) :
1977  iterator_base( i, filter )
1978  {
1979  }
1980 
1984  filter_sample_iterator( const filter_sample_iterator& i ) = default;
1985 
1989  filter_sample_iterator& operator =( const filter_sample_iterator& ) = default;
1990 
1995  filter_sample_iterator& operator =( const sample_iterator& i )
1996  {
1997  (void)iterator_base::operator =( i );
1998  return *this;
1999  }
2000 
2005  bool IsValid() const
2006  {
2007  return this->m_image != nullptr && this->m_iterator != nullptr;
2008  }
2009 
2013  image_type& Image() const
2014  {
2015  return *this->m_image;
2016  }
2017 
2022  const filter_type& Filter() const
2023  {
2024  return this->m_filter;
2025  }
2026 
2031  filter_type& Filter()
2032  {
2033  return this->m_filter;
2034  }
2035 
2039  sample* Position() const
2040  {
2041  return this->m_iterator;
2042  }
2043 
2051  operator bool() const
2052  {
2053  return this->m_iterator < this->m_end;
2054  }
2055 
2060  sample& operator *() const
2061  {
2062  return *this->m_iterator;
2063  }
2064 
2070  filter_sample_iterator& operator ++()
2071  {
2072  ++this->m_iterator;
2073  this->JumpToNextValidSample();
2074  return *this;
2075  }
2076 
2082  filter_sample_iterator operator ++( int )
2083  {
2084  sample* i0 = this->m_iterator++;
2085  this->JumpToNextValidSample();
2086  return filter_sample_iterator( *this->m_image, this->m_filter, i0, this->m_end );
2087  }
2088 
2094  filter_sample_iterator& operator --()
2095  {
2096  --this->m_iterator;
2097  this->JumpToPrevValidSample();
2098  return *this;
2099  }
2100 
2106  filter_sample_iterator operator --( int )
2107  {
2108  sample* i0 = this->m_iterator--;
2109  this->JumpToPrevValidSample();
2110  return filter_sample_iterator( *this->m_image, this->m_filter, i0, this->m_end );
2111  }
2112 
2121  {
2122  this->m_iterator += delta;
2123  this->JumpToNextValidSample();
2124  return *this;
2125  }
2126 
2135  {
2136  this->m_iterator -= delta;
2137  this->JumpToPrevValidSample();
2138  return *this;
2139  }
2140 
2148  filter_sample_iterator& MoveBy( int dx, int dy )
2149  {
2150  distance_type d = distance_type( dy )*this->m_image->Width() + distance_type( dx );
2151  this->m_iterator += d;
2152  if ( d >= 0 )
2153  this->JumpToNextValidSample();
2154  else
2155  this->JumpToPrevValidSample();
2156  return *this;
2157  }
2158 
2164  {
2165  return filter_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
2166  }
2167 
2173  {
2174  return filter_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
2175  }
2176 
2182  {
2183  return filter_sample_iterator( *i.m_image, i.m_iterator - delta, i.m_end );
2184  }
2185 
2191  {
2192  return i.m_iterator - j.m_iterator;
2193  }
2194 
2200  {
2201  return i.m_iterator == j.m_iterator;
2202  }
2203 
2208  friend bool operator ==( const filter_sample_iterator& i, const sample* j )
2209  {
2210  return i.m_iterator == j;
2211  }
2212 
2217  friend bool operator ==( const sample* i, const filter_sample_iterator& j )
2218  {
2219  return i == j.m_iterator;
2220  }
2221 
2227  {
2228  return i.m_iterator < j.m_iterator;
2229  }
2230 
2234  friend bool operator <( const filter_sample_iterator& i, const sample* j )
2235  {
2236  return i.m_iterator < j;
2237  }
2238 
2242  friend bool operator <( const sample* i, const filter_sample_iterator& j )
2243  {
2244  return i < j.m_iterator;
2245  }
2246  };
2247 
2248  // -------------------------------------------------------------------------
2249 
2283  template <class F>
2285  public filter_sample_iterator_base<const GenericImage<P>, const_sample_iterator, const sample*, F>
2286  {
2287  public:
2288 
2293 
2298 
2302  typedef typename image_type::sample sample;
2303 
2308  typedef F filter_type;
2309 
2310  typedef filter_sample_iterator_base<const GenericImage<P>, const_sample_iterator, const sample*, F>
2311  iterator_base;
2312 
2317  iterator_base()
2318  {
2319  }
2320 
2337  const_filter_sample_iterator( const image_type& image, const F& filter, int channel = -1 ) :
2338  iterator_base( image, filter, channel )
2339  {
2340  }
2341 
2360  const_filter_sample_iterator( const image_type& image, const F& filter, const sample* i, const sample* j ) :
2361  iterator_base( image, filter, i, j )
2362  {
2363  }
2364 
2369  const_filter_sample_iterator( const sample_iterator& i, const F& filter ) :
2370  iterator_base( i.m_image, filter, i.m_iterator, i.m_end )
2371  {
2372  }
2373 
2378  const_filter_sample_iterator( const const_sample_iterator& i, const F& filter ) :
2379  iterator_base( i, filter )
2380  {
2381  }
2382 
2388  iterator_base( i )
2389  {
2390  }
2391 
2396 
2400  const_filter_sample_iterator& operator =( const const_filter_sample_iterator& ) = default;
2401 
2407  {
2408  (void)const_sample_iterator::operator =( i );
2409  this->JumpToNextValidSample();
2410  return *this;
2411  }
2412 
2417  const_filter_sample_iterator& operator =( const const_sample_iterator& i )
2418  {
2419  (void)iterator_base::operator =( i );
2420  return *this;
2421  }
2422 
2427  bool IsValid() const
2428  {
2429  return this->m_image != nullptr && this->m_iterator != nullptr;
2430  }
2431 
2436  const image_type& Image() const
2437  {
2438  return *this->m_image;
2439  }
2440 
2445  const filter_type& Filter() const
2446  {
2447  return this->m_filter;
2448  }
2449 
2454  filter_type& Filter()
2455  {
2456  return this->m_filter;
2457  }
2458 
2463  const sample* Position() const
2464  {
2465  return this->m_iterator;
2466  }
2467 
2475  operator bool() const
2476  {
2477  return this->m_iterator < this->m_end;
2478  }
2479 
2484  const sample& operator *() const
2485  {
2486  return *this->m_iterator;
2487  }
2488 
2495  {
2496  ++this->m_iterator;
2497  this->JumpToNextValidSample();
2498  return *this;
2499  }
2500 
2506  const_filter_sample_iterator operator ++( int )
2507  {
2508  sample* i0 = this->m_iterator++;
2509  this->JumpToNextValidSample();
2510  return const_filter_sample_iterator( *this->m_image, this->m_filter, i0, this->m_end );
2511  }
2512 
2519  {
2520  --this->m_iterator;
2521  this->JumpToPrevValidSample();
2522  return *this;
2523  }
2524 
2530  const_filter_sample_iterator operator --( int )
2531  {
2532  sample* i0 = this->m_iterator--;
2533  this->JumpToPrevValidSample();
2534  return const_filter_sample_iterator( *this->m_image, this->m_filter, i0, this->m_end );
2535  }
2536 
2545  {
2546  this->m_iterator += delta;
2547  this->JumpToNextValidSample();
2548  return *this;
2549  }
2550 
2559  {
2560  this->m_iterator -= delta;
2561  this->JumpToPrevValidSample();
2562  return *this;
2563  }
2564 
2573  {
2574  distance_type d = distance_type( dy )*this->m_image->Width() + distance_type( dx );
2575  this->m_iterator += d;
2576  if ( d >= 0 )
2577  this->JumpToNextValidSample();
2578  else
2579  this->JumpToPrevValidSample();
2580  return *this;
2581  }
2582 
2588  {
2589  return const_filter_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
2590  }
2591 
2597  {
2598  return const_filter_sample_iterator( *i.m_image, i.m_iterator + delta, i.m_end );
2599  }
2600 
2606  {
2607  return const_filter_sample_iterator( *i.m_image, i.m_iterator - delta, i.m_end );
2608  }
2609 
2615  {
2616  return i.m_iterator - j.m_iterator;
2617  }
2618 
2624  {
2625  return i.m_iterator == j.m_iterator;
2626  }
2627 
2632  friend bool operator ==( const const_filter_sample_iterator& i, const sample* j )
2633  {
2634  return i.m_iterator == j;
2635  }
2636 
2641  friend bool operator ==( const sample* i, const const_filter_sample_iterator& j )
2642  {
2643  return i == j.m_iterator;
2644  }
2645 
2651  {
2652  return i.m_iterator < j.m_iterator;
2653  }
2654 
2658  friend bool operator <( const const_filter_sample_iterator& i, const sample* j )
2659  {
2660  return i.m_iterator < j;
2661  }
2662 
2666  friend bool operator <( const sample* i, const const_filter_sample_iterator& j )
2667  {
2668  return i < j.m_iterator;
2669  }
2670  };
2671 
2672  // -------------------------------------------------------------------------
2673 
2674  template <class image_type, class sample_pointer, class filter_type>
2675  class roi_filter_sample_iterator_base : public roi_sample_iterator_base<image_type, sample_pointer>
2676  {
2677  protected:
2678 
2679  typedef roi_sample_iterator_base<image_type, sample_pointer>
2680  roi_iterator_base;
2681 
2682  filter_type m_filter;
2683  sample_pointer m_begin;
2684 
2685  roi_filter_sample_iterator_base() :
2686  roi_iterator_base(), m_filter(), m_begin( nullptr )
2687  {
2688  }
2689 
2690  roi_filter_sample_iterator_base( image_type& image, const filter_type& filter, const Rect& rect, int channel ) :
2691  roi_iterator_base( image, rect, channel ), m_filter( filter ), m_begin( roi_iterator_base::m_iterator )
2692  {
2693  JumpToNextValidSample();
2694  }
2695 
2696  roi_filter_sample_iterator_base( image_type& image, const filter_type& filter, sample_pointer i, sample_pointer j ) :
2697  roi_iterator_base( image, i, j ), m_filter( filter ), m_begin( roi_iterator_base::m_iterator )
2698  {
2699  JumpToNextValidSample();
2700  }
2701 
2702  roi_filter_sample_iterator_base( const roi_iterator_base& i, const filter_type& filter ) :
2703  roi_iterator_base( i ), m_filter( filter ), m_begin( roi_iterator_base::m_iterator )
2704  {
2705  JumpToNextValidSample();
2706  }
2707 
2708  roi_filter_sample_iterator_base( const roi_filter_sample_iterator_base& ) = default;
2709 
2710  roi_filter_sample_iterator_base& operator =( const roi_filter_sample_iterator_base& i ) = default;
2711 
2712  roi_filter_sample_iterator_base& operator =( const roi_iterator_base& i )
2713  {
2714  (void)roi_iterator_base::operator =( i );
2715  JumpToNextValidSample();
2716  return *this;
2717  }
2718 
2719  void JumpToNextValidSample()
2720  {
2721  while ( this->m_iterator < this->m_end && !this->m_filter( *this->m_iterator ) )
2722  roi_iterator_base::Increment();
2723  }
2724 
2725  void JumpToPrevValidSample()
2726  {
2727  while ( this->m_iterator > this->m_begin && !this->m_filter( *this->m_iterator ) )
2728  roi_iterator_base::Decrement();
2729  }
2730  };
2731 
2732  // -------------------------------------------------------------------------
2733 
2744  template <class F>
2745  class roi_filter_sample_iterator : public roi_filter_sample_iterator_base<GenericImage<P>, sample*, F>
2746  {
2747  public:
2748 
2753 
2758 
2762  typedef typename image_type::sample sample;
2763 
2768  typedef F filter_type;
2769 
2770  typedef roi_filter_sample_iterator_base<GenericImage<P>, sample*, F>
2771  iterator_base;
2772 
2777  iterator_base()
2778  {
2779  }
2780 
2806  roi_filter_sample_iterator( image_type& image, const F& filter, const Rect& rect = Rect( 0 ), int channel = -1 ) :
2807  iterator_base( image.EnsureUnique(), filter, rect, channel )
2808  {
2809  }
2810 
2829  roi_filter_sample_iterator( image_type& image, const F& filter, sample* i, sample* j ) :
2830  iterator_base( image, filter, i, j )
2831  {
2832  }
2833 
2838  roi_filter_sample_iterator( const roi_sample_iterator& i, const F& filter ) :
2839  iterator_base( i, filter )
2840  {
2841  }
2842 
2847 
2851  roi_filter_sample_iterator& operator =( const roi_filter_sample_iterator& ) = default;
2852 
2858  {
2859  (void)iterator_base::operator =( i );
2860  return *this;
2861  }
2862 
2867  bool IsValid() const
2868  {
2869  return this->m_image != nullptr && this->m_iterator != nullptr;
2870  }
2871 
2875  image_type& Image() const
2876  {
2877  return *this->m_image;
2878  }
2879 
2884  const filter_type& Filter() const
2885  {
2886  return this->m_filter;
2887  }
2888 
2893  filter_type& Filter()
2894  {
2895  return this->m_filter;
2896  }
2897 
2901  sample* Position() const
2902  {
2903  return this->m_iterator;
2904  }
2905 
2912  operator bool() const
2913  {
2914  return this->m_iterator < this->m_end;
2915  }
2916 
2921  sample& operator *() const
2922  {
2923  return *this->m_iterator;
2924  }
2925 
2932  {
2933  this->Increment();
2934  this->JumpToNextValidSample();
2935  return *this;
2936  }
2937 
2943  roi_filter_sample_iterator operator ++( int )
2944  {
2945  roi_filter_sample_iterator i0( *this );
2946  this->Increment();
2947  this->JumpToNextValidSample();
2948  return i0;
2949  }
2950 
2957  {
2958  this->Decrement();
2959  this->JumpToPrevValidSample();
2960  return *this;
2961  }
2962 
2968  roi_filter_sample_iterator operator --( int )
2969  {
2970  roi_filter_sample_iterator i0( *this );
2971  this->Decrement();
2972  this->JumpToPrevValidSample();
2973  return i0;
2974  }
2975 
2986  {
2987  int w = this->m_rowEnd - this->m_rowBegin;
2988  return MoveBy( delta%w, delta/w );
2989  }
2990 
3001  {
3002  int w = this->m_rowEnd - this->m_rowBegin;
3003  return MoveBy( -delta%w, -delta/w );
3004  }
3005 
3015  {
3016  sample* i0 = this->m_iterator;
3017  iterator_base::MoveBy( dx, dy );
3018  if ( this->m_iterator >= i0 )
3019  this->JumpToNextValidSample();
3020  else
3021  this->JumpToPrevValidSample();
3022  return *this;
3023  }
3024 
3030  {
3032  j += delta;
3033  return j;
3034  }
3035 
3041  {
3043  j += delta;
3044  return j;
3045  }
3046 
3052  {
3054  j -= delta;
3055  return j;
3056  }
3057 
3063  {
3064  return i.m_iterator == j.m_iterator;
3065  }
3066 
3071  friend bool operator ==( const roi_filter_sample_iterator& i, const sample* j )
3072  {
3073  return i.m_iterator == j;
3074  }
3075 
3080  friend bool operator ==( const sample* i, const roi_filter_sample_iterator& j )
3081  {
3082  return i == j.m_iterator;
3083  }
3084 
3090  {
3091  return i.m_iterator < j.m_iterator;
3092  }
3093 
3097  friend bool operator <( const roi_filter_sample_iterator& i, const sample* j )
3098  {
3099  return i.m_iterator < j;
3100  }
3101 
3105  friend bool operator <( const sample* i, const roi_filter_sample_iterator& j )
3106  {
3107  return i < j.m_iterator;
3108  }
3109  };
3110 
3111  // -------------------------------------------------------------------------
3112 
3123  template <class F>
3124  class const_roi_filter_sample_iterator : public roi_filter_sample_iterator_base<const GenericImage<P>, const sample*, F>
3125  {
3126  public:
3127 
3132 
3137 
3141  typedef typename image_type::sample sample;
3142 
3147  typedef F filter_type;
3148 
3149  typedef roi_filter_sample_iterator_base<const GenericImage<P>, const sample*, F>
3150  iterator_base;
3151 
3156  iterator_base()
3157  {
3158  }
3159 
3185  const_roi_filter_sample_iterator( const image_type& image, const F& filter, const Rect& rect = Rect( 0 ), int channel = -1 ) :
3186  iterator_base( image, filter, rect, channel )
3187  {
3188  }
3189 
3208  const_roi_filter_sample_iterator( const image_type& image, const F& filter, const sample* i, const sample* j ) :
3209  iterator_base( image, filter, i, j )
3210  {
3211  }
3212 
3218  iterator_base( i, filter )
3219  {
3220  }
3221 
3226 
3231 
3237  {
3238  (void)iterator_base::operator =( i );
3239  return *this;
3240  }
3241 
3246  bool IsValid() const
3247  {
3248  return this->m_image != nullptr && this->m_iterator != nullptr;
3249  }
3250 
3255  const image_type& Image() const
3256  {
3257  return *this->m_image;
3258  }
3259 
3264  const filter_type& Filter() const
3265  {
3266  return this->m_filter;
3267  }
3268 
3273  filter_type& Filter()
3274  {
3275  return this->m_filter;
3276  }
3277 
3282  const sample* Position() const
3283  {
3284  return this->m_iterator;
3285  }
3286 
3293  operator bool() const
3294  {
3295  return this->m_iterator < this->m_end;
3296  }
3297 
3302  const sample& operator *() const
3303  {
3304  return *this->m_iterator;
3305  }
3306 
3313  {
3314  this->Increment();
3315  this->JumpToNextValidSample();
3316  return *this;
3317  }
3318 
3325  {
3327  this->Increment();
3328  this->JumpToNextValidSample();
3329  return i0;
3330  }
3331 
3338  {
3339  this->Decrement();
3340  this->JumpToPrevValidSample();
3341  return *this;
3342  }
3343 
3350  {
3352  this->Decrement();
3353  this->JumpToPrevValidSample();
3354  return i0;
3355  }
3356 
3367  {
3368  int w = this->m_rowEnd - this->m_rowBegin;
3369  return MoveBy( delta%w, delta/w );
3370  }
3371 
3382  {
3383  int w = this->m_rowEnd - this->m_rowBegin;
3384  return MoveBy( -delta%w, -delta/w );
3385  }
3386 
3396  {
3397  const sample* i0 = this->m_iterator;
3398  iterator_base::MoveBy( dx, dy );
3399  if ( this->m_iterator >= i0 )
3400  this->JumpToNextValidSample();
3401  else
3402  this->JumpToPrevValidSample();
3403  return *this;
3404  }
3405 
3411  {
3413  j += delta;
3414  return j;
3415  }
3416 
3422  {
3424  j += delta;
3425  return j;
3426  }
3427 
3433  {
3435  j -= delta;
3436  return j;
3437  }
3438 
3444  {
3445  return i.m_iterator == j.m_iterator;
3446  }
3447 
3452  friend bool operator ==( const const_roi_filter_sample_iterator& i, const sample* j )
3453  {
3454  return i.m_iterator == j;
3455  }
3456 
3461  friend bool operator ==( const sample* i, const const_roi_filter_sample_iterator& j )
3462  {
3463  return i == j.m_iterator;
3464  }
3465 
3471  {
3472  return i.m_iterator < j.m_iterator;
3473  }
3474 
3478  friend bool operator <( const const_roi_filter_sample_iterator& i, const sample* j )
3479  {
3480  return i.m_iterator < j;
3481  }
3482 
3486  friend bool operator <( const sample* i, const const_roi_filter_sample_iterator& j )
3487  {
3488  return i < j.m_iterator;
3489  }
3490  };
3491 
3492  // -------------------------------------------------------------------------
3493 
3504  {
3505  public:
3506 
3511 
3516 
3520  typedef typename image_type::sample sample;
3521 
3523 
3528  m_image( nullptr ), m_iterator(), m_end( nullptr )
3529  {
3530  }
3531 
3535  pixel_iterator( image_type& image ) :
3536  m_image( &image ), m_iterator(), m_end( nullptr )
3537  {
3538  m_image->EnsureUnique();
3539  if ( !m_image->IsEmpty() )
3540  {
3541  m_iterator = iterator_type( m_image->NumberOfChannels() );
3542  for ( int i = 0; i < m_iterator.Length(); ++i )
3543  m_iterator[i] = (*m_image)[i];
3544  m_end = m_iterator[0] + m_image->NumberOfPixels();
3545  }
3546  }
3547 
3551  pixel_iterator( const pixel_iterator& ) = default;
3552 
3556  pixel_iterator& operator =( const pixel_iterator& ) = default;
3557 
3562  bool IsValid() const
3563  {
3564  return m_image != nullptr && !m_iterator.IsEmpty();
3565  }
3566 
3570  image_type& Image() const
3571  {
3572  return *m_image;
3573  }
3574 
3579  sample* Position( int channel ) const
3580  {
3581  return m_iterator[channel];
3582  }
3583 
3589  operator bool() const
3590  {
3591  return m_iterator[0] < m_end;
3592  }
3593 
3598  sample& operator []( int channel ) const
3599  {
3600  return *m_iterator[channel];
3601  }
3602 
3607  pixel_iterator& operator ++()
3608  {
3609  for ( int i = 0; i < m_iterator.Length(); ++i )
3610  ++m_iterator[i];
3611  return *this;
3612  }
3613 
3619  pixel_iterator operator ++( int )
3620  {
3621  pixel_iterator i0( *this );
3622  for ( int i = 0; i < m_iterator.Length(); ++i )
3623  ++m_iterator[i];
3624  return i0;
3625  }
3626 
3631  pixel_iterator& operator --()
3632  {
3633  for ( int i = 0; i < m_iterator.Length(); ++i )
3634  --m_iterator[i];
3635  return *this;
3636  }
3637 
3643  pixel_iterator operator --( int )
3644  {
3645  pixel_iterator i0( *this );
3646  for ( int i = 0; i < m_iterator.Length(); ++i )
3647  --m_iterator[i];
3648  return i0;
3649  }
3650 
3658  pixel_iterator& operator +=( distance_type delta )
3659  {
3660  for ( int i = 0; i < m_iterator.Length(); ++i )
3661  m_iterator[i] += delta;
3662  return *this;
3663  }
3664 
3672  pixel_iterator& operator -=( distance_type delta )
3673  {
3674  for ( int i = 0; i < m_iterator.Length(); ++i )
3675  m_iterator[i] -= delta;
3676  return *this;
3677  }
3678 
3686  pixel_iterator& MoveBy( int dx, int dy )
3687  {
3688  return operator +=( distance_type( dy )*m_image->Width() + distance_type( dx ) );
3689  }
3690 
3696  {
3697  pixel_iterator j( i );
3698  j += delta;
3699  return j;
3700  }
3701 
3707  {
3708  pixel_iterator j( i );
3709  j += delta;
3710  return j;
3711  }
3712 
3718  {
3719  pixel_iterator j( i );
3720  j -= delta;
3721  return j;
3722  }
3723 
3729  {
3730  return i.m_iterator[0] - j.m_iterator[0];
3731  }
3732 
3737  friend bool operator ==( const pixel_iterator& i, const pixel_iterator& j )
3738  {
3739  return i.m_iterator[0] == j.m_iterator[0];
3740  }
3741 
3746  friend bool operator <( const pixel_iterator& i, const pixel_iterator& j )
3747  {
3748  return i.m_iterator[0] < j.m_iterator[0];
3749  }
3750 
3751  protected:
3752 
3753  image_type* m_image;
3754  iterator_type m_iterator;
3755  const sample* m_end;
3756  };
3757 
3758  // -------------------------------------------------------------------------
3759 
3770  {
3771  public:
3772 
3777 
3782 
3786  typedef typename image_type::sample sample;
3787 
3789 
3794  m_image( nullptr ), m_iterator(), m_end( nullptr )
3795  {
3796  }
3797 
3801  const_pixel_iterator( const image_type& image ) :
3802  m_image( &image ), m_iterator(), m_end( nullptr )
3803  {
3804  if ( !m_image->IsEmpty() )
3805  {
3806  m_iterator = iterator_type( m_image->NumberOfChannels() );
3807  for ( int i = 0; i < m_iterator.Length(); ++i )
3808  m_iterator[i] = (*m_image)[i];
3809  m_end = m_iterator[0] + m_image->NumberOfPixels();
3810  }
3811  }
3812 
3816  const_pixel_iterator( const const_pixel_iterator& ) = default;
3817 
3821  const_pixel_iterator& operator =( const const_pixel_iterator& ) = default;
3822 
3827  bool IsValid() const
3828  {
3829  return m_image != nullptr && !m_iterator.IsEmpty();
3830  }
3831 
3836  const image_type& Image() const
3837  {
3838  return *m_image;
3839  }
3840 
3845  const sample* Position( int channel ) const
3846  {
3847  return m_iterator[channel];
3848  }
3849 
3855  operator bool() const
3856  {
3857  return m_iterator[0] < m_end;
3858  }
3859 
3864  const sample& operator []( int channel ) const
3865  {
3866  return *m_iterator[channel];
3867  }
3868 
3873  const_pixel_iterator& operator ++()
3874  {
3875  for ( int i = 0; i < m_iterator.Length(); ++i )
3876  ++m_iterator[i];
3877  return *this;
3878  }
3879 
3885  const_pixel_iterator operator ++( int )
3886  {
3887  const_pixel_iterator i0( *this );
3888  for ( int i = 0; i < m_iterator.Length(); ++i )
3889  ++m_iterator[i];
3890  return i0;
3891  }
3892 
3897  const_pixel_iterator& operator --()
3898  {
3899  for ( int i = 0; i < m_iterator.Length(); ++i )
3900  --m_iterator[i];
3901  return *this;
3902  }
3903 
3909  const_pixel_iterator operator --( int )
3910  {
3911  const_pixel_iterator i0( *this );
3912  for ( int i = 0; i < m_iterator.Length(); ++i )
3913  --m_iterator[i];
3914  return i0;
3915  }
3916 
3924  const_pixel_iterator& operator +=( distance_type delta )
3925  {
3926  for ( int i = 0; i < m_iterator.Length(); ++i )
3927  m_iterator[i] += delta;
3928  return *this;
3929  }
3930 
3938  const_pixel_iterator& operator -=( distance_type delta )
3939  {
3940  for ( int i = 0; i < m_iterator.Length(); ++i )
3941  m_iterator[i] -= delta;
3942  return *this;
3943  }
3944 
3952  const_pixel_iterator& MoveBy( int dx, int dy )
3953  {
3954  return operator +=( distance_type( dy )*m_image->Width() + distance_type( dx ) );
3955  }
3956 
3962  {
3963  const_pixel_iterator j( i );
3964  j += delta;
3965  return j;
3966  }
3967 
3973  {
3974  const_pixel_iterator j( i );
3975  j += delta;
3976  return j;
3977  }
3978 
3984  {
3985  const_pixel_iterator j( i );
3986  j -= delta;
3987  return j;
3988  }
3989 
3995  {
3996  return i.m_iterator[0] - j.m_iterator[0];
3997  }
3998 
4003  friend bool operator ==( const const_pixel_iterator& i, const const_pixel_iterator& j )
4004  {
4005  return i.m_iterator[0] == j.m_iterator[0];
4006  }
4007 
4012  friend bool operator <( const const_pixel_iterator& i, const const_pixel_iterator& j )
4013  {
4014  return i.m_iterator[0] < j.m_iterator[0];
4015  }
4016 
4017  protected:
4018 
4019  const image_type* m_image;
4020  iterator_type m_iterator;
4021  const sample* m_end;
4022  };
4023 
4024  // -------------------------------------------------------------------------
4025 
4026  template <class image_type, class sample_pointer>
4027  class roi_pixel_iterator_base
4028  {
4029  protected:
4030 
4032 
4033  image_type* m_image;
4034  iterator_type m_iterator;
4035  sample_pointer m_rowBegin;
4036  sample_pointer m_rowEnd;
4037  sample_pointer m_end;
4038 
4039  roi_pixel_iterator_base() :
4040  m_image( nullptr ), m_iterator(), m_rowBegin( nullptr ), m_rowEnd( nullptr ), m_end( nullptr )
4041  {
4042  }
4043 
4044  roi_pixel_iterator_base( image_type& image, const Rect& rect ) :
4045  m_image( &image ), m_iterator(), m_rowBegin( nullptr ), m_rowEnd( nullptr ), m_end( nullptr )
4046  {
4047  Rect r = rect;
4048  if ( m_image->ParseRect( r ) )
4049  {
4050  m_iterator = iterator_type( m_image->NumberOfChannels() );
4051  for ( int i = 0; i < m_iterator.Length(); ++i )
4052  m_iterator[i] = m_image->PixelAddress( r.x0, r.y0, i );
4053  m_rowBegin = m_iterator[0];
4054  m_rowEnd = m_rowBegin + r.Width();
4055  m_end = m_rowEnd + ((r.Height() - 1)*m_image->Width());
4056  }
4057  }
4058 
4059  roi_pixel_iterator_base( const roi_pixel_iterator_base& ) = default;
4060 
4061  roi_pixel_iterator_base& operator =( const roi_pixel_iterator_base& ) = default;
4062 
4063  void Increment()
4064  {
4065  for ( int i = 0; i < m_iterator.Length(); ++i )
4066  ++m_iterator[i];
4067  if ( m_iterator[0] == m_rowEnd )
4068  {
4069  int w = m_rowEnd - m_rowBegin;
4070  for ( int i = 0; i < m_iterator.Length(); ++i )
4071  m_iterator[i] += m_image->Width() - w;
4072  m_rowBegin += m_image->Width();
4073  m_rowEnd += m_image->Width();
4074  }
4075  }
4076 
4077  void Decrement()
4078  {
4079  if ( m_iterator[0] == m_rowBegin )
4080  {
4081  int w = m_rowEnd - m_rowBegin;
4082  for ( int i = 0; i < m_iterator.Length(); ++i )
4083  m_iterator[i] -= m_image->Width() - w;
4084  m_rowBegin -= m_image->Width();
4085  m_rowEnd -= m_image->Width();
4086  }
4087  for ( int i = 0; i < m_iterator.Length(); ++i )
4088  --m_iterator[i];
4089  }
4090 
4091  void MoveBy( int cols, int rows )
4092  {
4093  int dx = m_iterator[0] - m_rowBegin;
4094  for ( int i = 0; i < m_iterator.Length(); ++i )
4095  m_iterator[i] -= dx;
4096  cols += dx;
4097  if ( cols != 0 )
4098  {
4099  int w = m_rowEnd - m_rowBegin;
4100  if ( pcl::Abs( cols ) >= w )
4101  {
4102  rows += cols/w;
4103  cols %= w;
4104  }
4105  }
4106  int dy = rows * m_image->Width();
4107  for ( int i = 0; i < m_iterator.Length(); ++i )
4108  m_iterator[i] += dy + cols;
4109  m_rowBegin += dy;
4110  m_rowEnd += dy;
4111  }
4112  };
4113 
4114  // -------------------------------------------------------------------------
4115 
4125  class roi_pixel_iterator : private roi_pixel_iterator_base<GenericImage<P>, sample*>
4126  {
4127  public:
4128 
4133 
4138 
4142  typedef typename image_type::sample sample;
4143 
4144  typedef roi_pixel_iterator_base<GenericImage<P>, sample*>
4145  iterator_base;
4146 
4151  iterator_base()
4152  {
4153  }
4154 
4169  roi_pixel_iterator( image_type& image, const Rect& rect = Rect( 0 ) ) :
4170  iterator_base( image.EnsureUnique(), rect )
4171  {
4172  }
4173 
4177  roi_pixel_iterator( const roi_pixel_iterator& ) = default;
4178 
4182  roi_pixel_iterator& operator =( const roi_pixel_iterator& ) = default;
4183 
4188  bool IsValid() const
4189  {
4190  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
4191  }
4192 
4196  image_type& Image() const
4197  {
4198  return *this->m_image;
4199  }
4200 
4205  sample* Position( int channel ) const
4206  {
4207  return this->m_iterator[channel];
4208  }
4209 
4216  operator bool() const
4217  {
4218  return this->m_iterator[0] < this->m_end;
4219  }
4220 
4225  sample& operator []( int channel ) const
4226  {
4227  return *this->m_iterator[channel];
4228  }
4229 
4235  roi_pixel_iterator& operator ++()
4236  {
4237  this->Increment();
4238  return *this;
4239  }
4240 
4246  roi_pixel_iterator operator ++( int )
4247  {
4248  roi_pixel_iterator i0( *this );
4249  this->Increment();
4250  return i0;
4251  }
4252 
4258  roi_pixel_iterator& operator --()
4259  {
4260  this->Decrement();
4261  return *this;
4262  }
4263 
4269  roi_pixel_iterator operator --( int )
4270  {
4271  roi_pixel_iterator i0( *this );
4272  this->Decrement();
4273  return i0;
4274  }
4275 
4285  roi_pixel_iterator& operator +=( distance_type delta )
4286  {
4287  int w = this->m_rowEnd - this->m_rowBegin;
4288  iterator_base::MoveBy( delta%w, delta/w );
4289  return *this;
4290  }
4291 
4301  roi_pixel_iterator& operator -=( distance_type delta )
4302  {
4303  int w = this->m_rowEnd - this->m_rowBegin;
4304  iterator_base::MoveBy( -delta%w, -delta/w );
4305  return *this;
4306  }
4307 
4316  roi_pixel_iterator& MoveBy( int dx, int dy )
4317  {
4318  iterator_base::MoveBy( dx, dy );
4319  return *this;
4320  }
4321 
4327  {
4328  roi_pixel_iterator j( i );
4329  j += delta;
4330  return j;
4331  }
4332 
4338  {
4339  roi_pixel_iterator j( i );
4340  j += delta;
4341  return j;
4342  }
4343 
4349  {
4350  roi_pixel_iterator j( i );
4351  j -= delta;
4352  return j;
4353  }
4354 
4359  friend bool operator ==( const roi_pixel_iterator& i, const roi_pixel_iterator& j )
4360  {
4361  return i.m_iterator[0] == j.m_iterator[0];
4362  }
4363 
4368  friend bool operator <( const roi_pixel_iterator& i, const roi_pixel_iterator& j )
4369  {
4370  return i.m_iterator[0] < j.m_iterator[0];
4371  }
4372  };
4373 
4374  // -------------------------------------------------------------------------
4375 
4385  class const_roi_pixel_iterator : private roi_pixel_iterator_base<const GenericImage<P>, const sample*>
4386  {
4387  public:
4388 
4393 
4398 
4402  typedef typename image_type::sample sample;
4403 
4404  typedef roi_pixel_iterator_base<const GenericImage<P>, const sample*>
4405  iterator_base;
4406 
4411  iterator_base()
4412  {
4413  }
4414 
4429  const_roi_pixel_iterator( const image_type& image, const Rect& rect = Rect( 0 ) ) :
4430  iterator_base( image, rect )
4431  {
4432  }
4433 
4438 
4442  const_roi_pixel_iterator& operator =( const const_roi_pixel_iterator& ) = default;
4443 
4448  bool IsValid() const
4449  {
4450  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
4451  }
4452 
4457  const image_type& Image() const
4458  {
4459  return *this->m_image;
4460  }
4461 
4466  const sample* Position( int channel ) const
4467  {
4468  return this->m_iterator[channel];
4469  }
4470 
4477  operator bool() const
4478  {
4479  return this->m_iterator[0] < this->m_end;
4480  }
4481 
4486  const sample& operator []( int channel ) const
4487  {
4488  return *this->m_iterator[channel];
4489  }
4490 
4497  {
4498  this->Increment();
4499  return *this;
4500  }
4501 
4507  const_roi_pixel_iterator operator ++( int )
4508  {
4509  const_roi_pixel_iterator i0( *this );
4510  this->Increment();
4511  return i0;
4512  }
4513 
4520  {
4521  this->Decrement();
4522  return *this;
4523  }
4524 
4530  const_roi_pixel_iterator operator --( int )
4531  {
4532  const_roi_pixel_iterator i0( *this );
4533  this->Decrement();
4534  return i0;
4535  }
4536 
4547  {
4548  int w = this->m_rowEnd - this->m_rowBegin;
4549  iterator_base::MoveBy( delta%w, delta/w );
4550  return *this;
4551  }
4552 
4563  {
4564  int w = this->m_rowEnd - this->m_rowBegin;
4565  iterator_base::MoveBy( -delta%w, -delta/w );
4566  return *this;
4567  }
4568 
4578  {
4579  iterator_base::MoveBy( dx, dy );
4580  return *this;
4581  }
4582 
4588  {
4589  const_roi_pixel_iterator j( i );
4590  j += delta;
4591  return j;
4592  }
4593 
4599  {
4600  const_roi_pixel_iterator j( i );
4601  j += delta;
4602  return j;
4603  }
4604 
4610  {
4611  const_roi_pixel_iterator j( i );
4612  j -= delta;
4613  return j;
4614  }
4615 
4621  {
4622  return i.m_iterator[0] == j.m_iterator[0];
4623  }
4624 
4630  {
4631  return i.m_iterator[0] < j.m_iterator[0];
4632  }
4633  };
4634 
4635  // -------------------------------------------------------------------------
4636 
4637  template <class image_type, class iterator_base, class sample_pointer, class filter_type>
4638  class filter_pixel_iterator_base : public iterator_base
4639  {
4640  protected:
4641 
4642  filter_type m_filter;
4643  sample_pointer m_begin;
4644 
4645  filter_pixel_iterator_base() :
4646  iterator_base(), m_filter(), m_begin( nullptr )
4647  {
4648  }
4649 
4650  filter_pixel_iterator_base( image_type& image, const filter_type& filter ) :
4651  iterator_base( image ), m_filter( filter ), m_begin( iterator_base::m_iterator )
4652  {
4653  JumpToNextValidSample();
4654  }
4655 
4656  filter_pixel_iterator_base( const iterator_base& i, const filter_type& filter ) :
4657  iterator_base( i ), m_filter( filter ), m_begin( iterator_base::m_iterator )
4658  {
4659  JumpToNextValidSample();
4660  }
4661 
4662  filter_pixel_iterator_base( const filter_pixel_iterator_base& ) = default;
4663 
4664  filter_pixel_iterator_base& operator =( const filter_pixel_iterator_base& ) = default;
4665 
4666  filter_pixel_iterator_base& operator =( const iterator_base& i )
4667  {
4668  (void)iterator_base::operator =( i );
4669  JumpToNextValidSample();
4670  }
4671 
4672  void JumpToNextValidSample()
4673  {
4674  while ( this->m_iterator[0] < this->m_end && !this->m_filter( this->m_iterator ) )
4675  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4676  ++this->m_iterator[i];
4677  }
4678 
4679  void JumpToPrevValidSample()
4680  {
4681  while ( this->m_iterator[0] > this->m_begin && !this->m_filter( this->m_iterator ) )
4682  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4683  --this->m_iterator[i];
4684  }
4685  };
4686 
4687  // -------------------------------------------------------------------------
4688 
4724  template <class F>
4726  public filter_pixel_iterator_base<GenericImage<P>, pixel_iterator, sample*, F>
4727  {
4728  public:
4729 
4734 
4739 
4743  typedef typename image_type::sample sample;
4744 
4749  typedef F filter_type;
4750 
4751  typedef filter_pixel_iterator_base<GenericImage<P>, pixel_iterator, sample*, F>
4752  iterator_base;
4753 
4758  iterator_base()
4759  {
4760  }
4761 
4770  filter_pixel_iterator( image_type& image, const F& filter ) :
4771  iterator_base( image.EnsureUnique(), filter )
4772  {
4773  }
4774 
4779  filter_pixel_iterator( const pixel_iterator& i, const F& filter ) :
4780  iterator_base( i, filter )
4781  {
4782  }
4783 
4787  filter_pixel_iterator( const filter_pixel_iterator& ) = default;
4788 
4792  filter_pixel_iterator& operator =( const filter_pixel_iterator& ) = default;
4793 
4798  filter_pixel_iterator& operator =( const pixel_iterator& i )
4799  {
4800  (void)iterator_base::operator =( i );
4801  return *this;
4802  }
4803 
4808  bool IsValid() const
4809  {
4810  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
4811  }
4812 
4816  image_type& Image() const
4817  {
4818  return *this->m_image;
4819  }
4820 
4825  const filter_type& Filter() const
4826  {
4827  return this->m_filter;
4828  }
4829 
4834  filter_type& Filter()
4835  {
4836  return this->m_filter;
4837  }
4838 
4843  sample* Position( int channel ) const
4844  {
4845  return this->m_iterator[channel];
4846  }
4847 
4853  operator bool() const
4854  {
4855  return this->m_iterator[0] < this->m_end;
4856  }
4857 
4862  sample& operator []( int channel ) const
4863  {
4864  return *this->m_iterator[channel];
4865  }
4866 
4872  filter_pixel_iterator& operator ++()
4873  {
4874  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4875  ++this->m_iterator[i];
4876  this->JumpToNextValidSample();
4877  return *this;
4878  }
4879 
4885  filter_pixel_iterator operator ++( int )
4886  {
4887  filter_pixel_iterator i0( *this );
4888  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4889  ++this->m_iterator[i];
4890  this->JumpToNextValidSample();
4891  return i0;
4892  }
4893 
4899  filter_pixel_iterator& operator --()
4900  {
4901  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4902  --this->m_iterator[i];
4903  this->JumpToPrevValidSample();
4904  return *this;
4905  }
4906 
4912  filter_pixel_iterator operator --( int )
4913  {
4914  filter_pixel_iterator i0( *this );
4915  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4916  --this->m_iterator[i];
4917  this->JumpToPrevValidSample();
4918  return i0;
4919  }
4920 
4928  filter_pixel_iterator& operator +=( distance_type delta )
4929  {
4930  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4931  this->m_iterator[i] += delta;
4932  this->JumpToNextValidSample();
4933  return *this;
4934  }
4935 
4943  filter_pixel_iterator& operator -=( distance_type delta )
4944  {
4945  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4946  this->m_iterator[i] -= delta;
4947  this->JumpToPrevValidSample();
4948  return *this;
4949  }
4950 
4958  filter_pixel_iterator& MoveBy( int dx, int dy )
4959  {
4960  distance_type d = distance_type( dy )*this->m_image->Width() + distance_type( dx );
4961  for ( int i = 0; i < this->m_iterator.Length(); ++i )
4962  this->m_iterator[i] += d;
4963  if ( d >= 0 )
4964  this->JumpToNextValidSample();
4965  else
4966  this->JumpToPrevValidSample();
4967  return *this;
4968  }
4969 
4975  {
4976  filter_pixel_iterator j( i );
4977  j += delta;
4978  return j;
4979  }
4980 
4986  {
4987  filter_pixel_iterator j( i );
4988  j += delta;
4989  return j;
4990  }
4991 
4997  {
4998  filter_pixel_iterator j( i );
4999  j -= delta;
5000  return j;
5001  }
5002 
5007  friend bool operator ==( const filter_pixel_iterator& i, const filter_pixel_iterator& j )
5008  {
5009  return i.m_iterator[0] == j.m_iterator[0];
5010  }
5011 
5016  friend bool operator <( const filter_pixel_iterator& i, const filter_pixel_iterator& j )
5017  {
5018  return i.m_iterator[0] < j.m_iterator[0];
5019  }
5020  };
5021 
5022  // -------------------------------------------------------------------------
5023 
5059  template <class F>
5061  public filter_pixel_iterator_base<const GenericImage<P>, const_pixel_iterator, const sample*, F>
5062  {
5063  public:
5064 
5069 
5074 
5078  typedef typename image_type::sample sample;
5079 
5084  typedef F filter_type;
5085 
5086  typedef filter_pixel_iterator_base<const GenericImage<P>, const_pixel_iterator, const sample*, F>
5087  iterator_base;
5088 
5093  iterator_base()
5094  {
5095  }
5096 
5105  const_filter_pixel_iterator( const image_type& image, const F& filter ) :
5106  iterator_base( image, filter )
5107  {
5108  }
5109 
5114  const_filter_pixel_iterator( const const_pixel_iterator& i, const F& filter ) :
5115  iterator_base( i, filter )
5116  {
5117  }
5118 
5123 
5127  const_filter_pixel_iterator& operator =( const const_filter_pixel_iterator& ) = default;
5128 
5133  const_filter_pixel_iterator& operator =( const const_pixel_iterator& i )
5134  {
5135  (void)iterator_base::operator =( i );
5136  return *this;
5137  }
5138 
5143  bool IsValid() const
5144  {
5145  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
5146  }
5147 
5152  const image_type& Image() const
5153  {
5154  return *this->m_image;
5155  }
5156 
5161  const filter_type& Filter() const
5162  {
5163  return this->m_filter;
5164  }
5165 
5170  filter_type& Filter()
5171  {
5172  return this->m_filter;
5173  }
5174 
5179  const sample* Position( int channel ) const
5180  {
5181  return this->m_iterator[channel];
5182  }
5183 
5189  operator bool() const
5190  {
5191  return this->m_iterator[0] < this->m_end;
5192  }
5193 
5198  const sample& operator []( int channel ) const
5199  {
5200  return *this->m_iterator[channel];
5201  }
5202 
5209  {
5210  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5211  ++this->m_iterator[i];
5212  this->JumpToNextValidSample();
5213  return *this;
5214  }
5215 
5221  const_filter_pixel_iterator operator ++( int )
5222  {
5223  const_filter_pixel_iterator i0( *this );
5224  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5225  ++this->m_iterator[i];
5226  this->JumpToNextValidSample();
5227  return i0;
5228  }
5229 
5236  {
5237  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5238  --this->m_iterator[i];
5239  this->JumpToPrevValidSample();
5240  return *this;
5241  }
5242 
5248  const_filter_pixel_iterator operator --( int )
5249  {
5250  const_filter_pixel_iterator i0( *this );
5251  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5252  --this->m_iterator[i];
5253  this->JumpToPrevValidSample();
5254  return i0;
5255  }
5256 
5265  {
5266  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5267  this->m_iterator[i] += delta;
5268  this->JumpToNextValidSample();
5269  return *this;
5270  }
5271 
5280  {
5281  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5282  this->m_iterator[i] -= delta;
5283  this->JumpToPrevValidSample();
5284  return *this;
5285  }
5286 
5295  {
5296  distance_type d = distance_type( dy )*this->m_image->Width() + distance_type( dx );
5297  for ( int i = 0; i < this->m_iterator.Length(); ++i )
5298  this->m_iterator[i] += d;
5299  if ( d >= 0 )
5300  this->JumpToNextValidSample();
5301  else
5302  this->JumpToPrevValidSample();
5303  return *this;
5304  }
5305 
5311  {
5313  j += delta;
5314  return j;
5315  }
5316 
5322  {
5324  j += delta;
5325  return j;
5326  }
5327 
5333  {
5335  j -= delta;
5336  return j;
5337  }
5338 
5344  {
5345  return i.m_iterator[0] == j.m_iterator[0];
5346  }
5347 
5353  {
5354  return i.m_iterator[0] < j.m_iterator[0];
5355  }
5356  };
5357 
5358  // -------------------------------------------------------------------------
5359 
5360  template <class image_type, class sample_pointer, class filter_type>
5361  class roi_filter_pixel_iterator_base : public roi_pixel_iterator_base<image_type, sample_pointer>
5362  {
5363  protected:
5364 
5365  typedef roi_pixel_iterator_base<image_type, sample_pointer>
5366  roi_iterator_base;
5367 
5368  filter_type m_filter;
5369  sample_pointer m_begin;
5370 
5371  roi_filter_pixel_iterator_base() :
5372  roi_iterator_base(), m_filter(), m_begin( nullptr )
5373  {
5374  }
5375 
5376  roi_filter_pixel_iterator_base( image_type& image, const filter_type& filter, const Rect& rect ) :
5377  roi_iterator_base( image, rect ), m_filter( filter ), m_begin( roi_iterator_base::m_iterator )
5378  {
5379  JumpToNextValidSample();
5380  }
5381 
5382  roi_filter_pixel_iterator_base( const roi_iterator_base& i, const filter_type& filter ) :
5383  roi_iterator_base( i ), m_filter( filter ), m_begin( roi_iterator_base::m_iterator )
5384  {
5385  JumpToNextValidSample();
5386  }
5387 
5388  roi_filter_pixel_iterator_base( const roi_filter_pixel_iterator_base& ) = default;
5389 
5390  roi_filter_pixel_iterator_base& operator =( const roi_filter_pixel_iterator_base& ) = default;
5391 
5392  roi_filter_pixel_iterator_base& operator =( const roi_iterator_base& i )
5393  {
5394  (void)roi_iterator_base::operator =( i );
5395  JumpToNextValidSample();
5396  return *this;
5397  }
5398 
5399  void JumpToNextValidSample()
5400  {
5401  while ( this->m_iterator[0] < this->m_end && !this->m_filter( this->m_iterator ) )
5402  roi_iterator_base::Increment();
5403  }
5404 
5405  void JumpToPrevValidSample()
5406  {
5407  while ( this->m_iterator[0] > this->m_begin && !this->m_filter( this->m_iterator ) )
5408  roi_iterator_base::Decrement();
5409  }
5410  };
5411 
5412  // -------------------------------------------------------------------------
5413 
5424  template <class F>
5425  class roi_filter_pixel_iterator : public roi_filter_pixel_iterator_base<GenericImage<P>, sample*, F>
5426  {
5427  public:
5428 
5433 
5438 
5442  typedef typename image_type::sample sample;
5443 
5448  typedef F filter_type;
5449 
5450  typedef roi_filter_pixel_iterator_base<GenericImage<P>, sample*, F>
5451  iterator_base;
5452 
5457  iterator_base()
5458  {
5459  }
5460 
5478  roi_filter_pixel_iterator( image_type& image, const F& filter, const Rect& rect = Rect( 0 ) ) :
5479  iterator_base( image.EnsureUnique(), filter, rect )
5480  {
5481  }
5482 
5487  roi_filter_pixel_iterator( const roi_pixel_iterator& i, const F& filter ) :
5488  iterator_base( i, filter )
5489  {
5490  }
5491 
5496 
5500  roi_filter_pixel_iterator& operator =( const roi_filter_pixel_iterator& ) = default;
5501 
5506  {
5507  (void)iterator_base::operator =( i );
5508  return *this;
5509  }
5510 
5515  bool IsValid() const
5516  {
5517  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
5518  }
5519 
5523  image_type& Image() const
5524  {
5525  return *this->m_image;
5526  }
5527 
5532  const filter_type& Filter() const
5533  {
5534  return this->m_filter;
5535  }
5536 
5541  filter_type& Filter()
5542  {
5543  return this->m_filter;
5544  }
5545 
5550  sample* Position( int channel ) const
5551  {
5552  return this->m_iterator[channel];
5553  }
5554 
5561  operator bool() const
5562  {
5563  return this->m_iterator[0] < this->m_end;
5564  }
5565 
5570  sample& operator []( int channel ) const
5571  {
5572  return *this->m_iterator[channel];
5573  }
5574 
5581  {
5582  this->Increment();
5583  this->JumpToNextValidSample();
5584  return *this;
5585  }
5586 
5592  roi_filter_pixel_iterator operator ++( int )
5593  {
5594  roi_filter_pixel_iterator i0( *this );
5595  this->Increment();
5596  this->JumpToNextValidSample();
5597  return i0;
5598  }
5599 
5606  {
5607  this->Decrement();
5608  this->JumpToPrevValidSample();
5609  return *this;
5610  }
5611 
5617  roi_filter_pixel_iterator operator --( int )
5618  {
5619  roi_filter_pixel_iterator i0( *this );
5620  this->Decrement();
5621  this->JumpToPrevValidSample();
5622  return i0;
5623  }
5624 
5635  {
5636  int w = this->m_rowEnd - this->m_rowBegin;
5637  return MoveBy( delta%w, delta/w );
5638  }
5639 
5650  {
5651  int w = this->m_rowEnd - this->m_rowBegin;
5652  return MoveBy( -delta%w, -delta/w );
5653  }
5654 
5664  {
5665  sample* i0 = this->m_iterator[0];
5666  iterator_base::MoveBy( dx, dy );
5667  if ( this->m_iterator[0] >= i0 )
5668  this->JumpToNextValidSample();
5669  else
5670  this->JumpToPrevValidSample();
5671  return *this;
5672  }
5673 
5679  {
5681  j += delta;
5682  return j;
5683  }
5684 
5690  {
5692  j += delta;
5693  return j;
5694  }
5695 
5701  {
5703  j -= delta;
5704  return j;
5705  }
5706 
5712  {
5713  return i.m_iterator[0] == j.m_iterator[0];
5714  }
5715 
5721  {
5722  return i.m_iterator[0] < j.m_iterator[0];
5723  }
5724  };
5725 
5726  // -------------------------------------------------------------------------
5727 
5738  template <class F>
5739  class const_roi_filter_pixel_iterator : public roi_filter_pixel_iterator_base<const GenericImage<P>, const sample*, F>
5740  {
5741  public:
5742 
5747 
5752 
5756  typedef typename image_type::sample sample;
5757 
5762  typedef F filter_type;
5763 
5764  typedef roi_filter_pixel_iterator_base<const GenericImage<P>, const sample*, F>
5765  iterator_base;
5766 
5771  iterator_base()
5772  {
5773  }
5774 
5793  const_roi_filter_pixel_iterator( const image_type& image, const F& filter, const Rect& rect = Rect( 0 ) ) :
5794  iterator_base( image, filter, rect )
5795  {
5796  }
5797 
5803  iterator_base( i, filter )
5804  {
5805  }
5806 
5811 
5812 
5816  const_roi_filter_pixel_iterator& operator =( const const_roi_filter_pixel_iterator& ) = default;
5817 
5822  {
5823  (void)iterator_base::operator =( i );
5824  return *this;
5825  }
5826 
5831  bool IsValid() const
5832  {
5833  return this->m_image != nullptr && !this->m_iterator.IsEmpty();
5834  }
5835 
5840  const image_type& Image() const
5841  {
5842  return *this->m_image;
5843  }
5844 
5849  const filter_type& Filter() const
5850  {
5851  return this->m_filter;
5852  }
5853 
5858  filter_type& Filter()
5859  {
5860  return this->m_filter;
5861  }
5862 
5867  const sample* Position( int channel ) const
5868  {
5869  return this->m_iterator[channel];
5870  }
5871 
5878  operator bool() const
5879  {
5880  return this->m_iterator[0] < this->m_end;
5881  }
5882 
5887  const sample& operator []( int channel ) const
5888  {
5889  return *this->m_iterator[channel];
5890  }
5891 
5898  {
5899  this->Increment();
5900  this->JumpToNextValidSample();
5901  return *this;
5902  }
5903 
5910  {
5911  const_roi_filter_pixel_iterator i0( *this );
5912  this->Increment();
5913  this->JumpToNextValidSample();
5914  return i0;
5915  }
5916 
5923  {
5924  this->Decrement();
5925  this->JumpToPrevValidSample();
5926  return *this;
5927  }
5928 
5935  {
5936  const_roi_filter_pixel_iterator i0( *this );
5937  this->Decrement();
5938  this->JumpToPrevValidSample();
5939  return i0;
5940  }
5941 
5952  {
5953  int w = this->m_rowEnd - this->m_rowBegin;
5954  return MoveBy( delta%w, delta/w );
5955  }
5956 
5967  {
5968  int w = this->m_rowEnd - this->m_rowBegin;
5969  return MoveBy( -delta%w, -delta/w );
5970  }
5971 
5981  {
5982  const sample* i0 = this->m_iterator[0];
5983  iterator_base::MoveBy( dx, dy );
5984  if ( this->m_iterator[0] >= i0 )
5985  this->JumpToNextValidSample();
5986  else
5987  this->JumpToPrevValidSample();
5988  return *this;
5989  }
5990 
5996  {
5998  j += delta;
5999  return j;
6000  }
6001 
6007  {
6009  j += delta;
6010  return j;
6011  }
6012 
6018  {
6020  j -= delta;
6021  return j;
6022  }
6023 
6029  {
6030  return i.m_iterator[0] == j.m_iterator[0];
6031  }
6032 
6038  {
6039  return i.m_iterator[0] < j.m_iterator[0];
6040  }
6041  };
6042 
6043  // -------------------------------------------------------------------------
6044 
6049  static bool IsFloatSample()
6050  {
6051  return pixel_traits::IsFloatSample();
6052  }
6053 
6058  static bool IsComplexSample()
6059  {
6060  return pixel_traits::IsComplexSample();
6061  }
6062 
6067  static int BytesPerSample()
6068  {
6069  return P::BytesPerSample();
6070  }
6071 
6076  static int BitsPerSample()
6077  {
6078  return P::BitsPerSample();
6079  }
6080 
6088  template <class P1>
6089  bool SameSampleType( const GenericImage<P1>& image ) const
6090  {
6091  return image.BitsPerSample() == BitsPerSample() &&
6092  image.IsFloatSample() == IsFloatSample() &&
6093  image.IsComplexSample() == IsComplexSample();
6094  }
6095 
6101  bool SameSampleType( const GenericImage& image ) const
6102  {
6103  return true;
6104  }
6105 
6106  // -------------------------------------------------------------------------
6107 
6113  {
6114  m_data = new Data( this );
6115  }
6116 
6146  GenericImage( const GenericImage& image )
6147  {
6148  if ( !image.IsShared() )
6149  if ( image.IsCompletelySelected() )
6150  {
6151  image.m_data->Attach( this );
6152  m_data = image.m_data;
6153  m_status = image.m_status;
6154  ResetSelections();
6155  return;
6156  }
6157 
6158  m_data = new Data( this );
6159  (void)Assign( image );
6160  }
6161 
6166  AbstractImage( image ), m_data( image.m_data )
6167  {
6168  image.m_data = nullptr;
6169  }
6170 
6183  template <class P1>
6185  {
6186  m_data = new Data( this );
6187  (void)Assign( image );
6188  }
6189 
6230  template <class P1>
6231  GenericImage( const GenericImage<P1>& image, const Rect& rect, int firstChannel = -1, int lastChannel = -1 )
6232  {
6233  m_data = new Data( this );
6234  (void)Assign( image, rect, firstChannel, lastChannel );
6235  }
6236 
6255  GenericImage( int width, int height, color_space colorSpace = ColorSpace::Gray )
6256  {
6257  m_data = new Data( this );
6258  m_data->Allocate( width, height, ColorSpace::NumberOfNominalChannels( colorSpace ), colorSpace );
6259  ResetSelections();
6260  }
6261 
6276  explicit GenericImage( File& stream )
6277  {
6278  m_data = new Data( this );
6279  Read( stream );
6280  }
6281 
6301  explicit GenericImage( void* handle )
6302  {
6303  m_data = new Data( this, handle );
6304  ResetSelections();
6305  }
6306 
6334  GenericImage( void*, int width, int height, color_space colorSpace = ColorSpace::Gray )
6335  {
6336  m_data = new Data( this, width, height, ColorSpace::NumberOfNominalChannels( colorSpace ), colorSpace );
6337  ResetSelections();
6338  }
6339 
6357  virtual ~GenericImage()
6358  {
6359  if ( m_data != nullptr )
6360  {
6361  DetachFromData();
6362  m_data = nullptr;
6363  }
6364  }
6365 
6366  // -------------------------------------------------------------------------
6367 
6384  bool IsShared() const
6385  {
6386  return m_data->IsShared();
6387  }
6388 
6399  bool IsUnique() const
6400  {
6401  return m_data->IsUnique();
6402  }
6403 
6417  {
6418  if ( m_data->IsShared() )
6419  {
6420  GenericImage local_;
6421  GenericImage* local = &local_; // ### Workaround to GCC 7's 'dereferencing type-punned pointer' bugs
6422  local->m_data->Allocate( m_width, m_height, m_numberOfChannels, m_colorSpace );
6423  local->m_RGBWS = m_RGBWS;
6424  local->m_selected = m_selected;
6425  local->m_savedSelections = m_savedSelections;
6426  local->m_status = m_status;
6427  for ( int c = 0; c < m_numberOfChannels; ++c )
6428  P::Copy( local->m_pixelData[c], m_pixelData[c], NumberOfPixels() );
6429 
6430  local->m_data->Attach( this );
6431  DetachFromData();
6432  m_data = local->m_data;
6433  }
6434  return *this;
6435  }
6436 
6453  {
6454  if ( !m_data->IsUnique() )
6455  {
6456  Data* newData = m_data->Clone( this );
6457  DetachFromData();
6458  m_data = newData;
6459  }
6460  return *this;
6461  }
6462 
6485  pixel_allocator& Allocator() const
6486  {
6487  return m_allocator;
6488  }
6489 
6495  void Synchronize()
6496  {
6497  m_data->SynchronizeWithSharedImage();
6498  ResetSelections();
6499  }
6500 
6535  GenericImage& AllocateData( int width, int height,
6536  int numberOfChannels = 1,
6537  color_space colorSpace = ColorSpace::Gray )
6538  {
6539  if ( !m_data->IsUnique() )
6540  {
6541  Data* newData = new Data( this );
6542  DetachFromData();
6543  m_data = newData;
6544  }
6545  m_data->Allocate( width, height, numberOfChannels, colorSpace );
6546  ResetSelections();
6547  return *this;
6548  }
6549 
6561  int numberOfChannels = 1,
6562  color_space colorSpace = ColorSpace::Gray )
6563  {
6564  return AllocateData( rect.Width(), rect.Height(), numberOfChannels, colorSpace );
6565  }
6566 
6579  {
6580  if ( !m_data->IsEmpty() )
6581  if ( m_data->IsUnique() )
6582  m_data->Deallocate();
6583  else
6584  {
6585  Data* newData = new Data( this );
6586  DetachFromData();
6587  m_data = newData;
6588  }
6589  ResetSelections();
6590  return *this;
6591  }
6592 
6648  GenericImage& ImportData( sample** data, int width, int height,
6649  int numberOfChannels = 1, color_space colorSpace = ColorSpace::Gray )
6650  {
6651  if ( !m_data->IsUnique() )
6652  {
6653  if ( m_data->IsShared() )
6654  throw Error( "GenericImage::ImportData(): Invalid operation for an aliased shared image" );
6655  Data* newData = new Data( this );
6656  DetachFromData();
6657  m_data = newData;
6658  }
6659  m_data->Import( data, width, height, numberOfChannels, colorSpace );
6660  ResetSelections();
6661  return *this;
6662  }
6663 
6698  sample** ReleaseData()
6699  {
6700  if ( !m_data->IsUnique() )
6701  throw Error( "GenericImage::ReleaseData(): Invalid operation for an aliased image" );
6702  sample** data = m_data->Release();
6703  ResetSelections();
6704  return data;
6705  }
6706 
6707  // -------------------------------------------------------------------------
6708 
6714  {
6715  return BytesPerSample() * size_type( m_width );
6716  }
6717 
6723  {
6724  return BytesPerSample() * NumberOfPixels();
6725  }
6726 
6734  {
6735  return ChannelSize() * size_type( m_numberOfChannels );
6736  }
6737 
6744  {
6745  return ChannelSize() * NumberOfNominalChannels();
6746  }
6747 
6754  {
6755  return ChannelSize() * NumberOfAlphaChannels();
6756  }
6757 
6772  sample* PixelData( int channel = 0 )
6773  {
6774  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6775  EnsureUnique();
6776  return m_pixelData[channel];
6777  }
6778 
6785  const sample* PixelData( int channel = 0 ) const
6786  {
6787  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6788  return m_pixelData[channel];
6789  }
6790 
6794  operator bool() const
6795  {
6796  return m_data != nullptr && !m_data->IsEmpty();
6797  }
6798 
6809  sample* operator []( int channel )
6810  {
6811  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6812  return PixelData( channel );
6813  }
6814 
6821  const sample* operator []( int channel ) const
6822  {
6823  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6824  return PixelData( channel );
6825  }
6826 
6834  sample* operator *()
6835  {
6836  PCL_PRECONDITION( 0 < m_numberOfChannels )
6837  return PixelData( 0 );
6838  }
6839 
6846  const sample* operator *() const
6847  {
6848  PCL_PRECONDITION( 0 < m_numberOfChannels )
6849  return PixelData( 0 );
6850  }
6851 
6871  sample* ScanLine( int y, int channel = 0 )
6872  {
6873  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6874  PCL_PRECONDITION( 0 <= y && y < m_height )
6875  EnsureUnique();
6876  return m_pixelData[channel] + RowOffset( y );
6877  }
6878 
6885  const sample* ScanLine( int y, int channel = 0 ) const
6886  {
6887  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6888  PCL_PRECONDITION( 0 <= y && y < m_height )
6889  return m_pixelData[channel] + RowOffset( y );
6890  }
6891 
6915  sample* PixelAddress( int x, int y, int channel = 0 )
6916  {
6917  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6918  PCL_PRECONDITION( 0 <= x && x < m_width )
6919  PCL_PRECONDITION( 0 <= y && y < m_height )
6920  EnsureUnique();
6921  return m_pixelData[channel] + PixelOffset( x, y );
6922  }
6923 
6930  const sample* PixelAddress( int x, int y, int channel = 0 ) const
6931  {
6932  PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6933  PCL_PRECONDITION( 0 <= x && x < m_width )
6934  PCL_PRECONDITION( 0 <= y && y < m_height )
6935  return m_pixelData[channel] + PixelOffset( x, y );
6936  }
6937 
6958  sample* PixelAddress( const Point& p, int channel = 0 )
6959  {
6960  return PixelAddress( p.x, p.y, channel );
6961  }
6962 
6970  const sample* PixelAddress( const Point& p, int channel = 0 ) const
6971  {
6972  return PixelAddress( p.x, p.y, channel );
6973  }
6974 
6995  sample& operator ()( int x, int y, int channel = 0 )
6996  {
6997  return *PixelAddress( x, y, channel );
6998  }
6999 
7016  sample operator ()( int x, int y, int channel = 0 ) const
7017  {
7018  return *PixelAddress( x, y, channel );
7019  }
7020 
7038  sample& operator ()( const Point& p, int channel = 0 )
7039  {
7040  return *PixelAddress( p, channel );
7041  }
7042 
7056  sample operator ()( const Point& p, int channel = 0 ) const
7057  {
7058  return *PixelAddress( p, channel );
7059  }
7060 
7068  sample& Pixel( int x, int y, int channel = 0 )
7069  {
7070  return operator()( x, y, channel );
7071  }
7072 
7080  sample Pixel( int x, int y, int channel = 0 ) const
7081  {
7082  return operator()( x, y, channel );
7083  }
7084 
7092  sample& Pixel( const Point& p, int channel = 0 )
7093  {
7094  return operator()( p, channel );
7095  }
7096 
7105  sample Pixel( const Point& p, int channel = 0 ) const
7106  {
7107  return operator()( p, channel );
7108  }
7109 
7110  // -------------------------------------------------------------------------
7111 
7119  void SetRGBWorkingSpace( const RGBColorSystem& RGBWS ) override
7120  {
7121  if ( !IsShared() )
7122  {
7123  EnsureUnique();
7124  m_RGBWS = RGBWS;
7125  }
7126  }
7127 
7128  // -------------------------------------------------------------------------
7129 
7200  template <class P1>
7202  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
7203  {
7204  m_status = image.Status();
7205 
7206  Rect r = rect;
7207  if ( !image.ParseSelection( r, firstChannel, lastChannel ) )
7208  {
7209  FreeData();
7210  return *this;
7211  }
7212 
7213  int n = 1 + lastChannel - firstChannel;
7214  AllocateData( r, n, (firstChannel == 0 && n >= ColorSpace::NumberOfNominalChannels( image.ColorSpace() )) ?
7215  image.ColorSpace() : ColorSpace::Gray );
7216 
7217  if ( !IsShared() ) // ### cannot modify a shared image's RGBWS
7218  m_RGBWS = image.RGBWorkingSpace();
7219 
7220  ResetSelections();
7221 
7222  if ( r == image.Bounds() )
7223  for ( int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7224  P::Copy( m_pixelData[c], image[firstChannel], NumberOfPixels() );
7225  else
7226  for ( int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7227  {
7228  sample* f = m_pixelData[c];
7229  const typename P1::sample* g = image.PixelAddress( r.LeftTop(), firstChannel );
7230  for ( int y = 0; y < m_height; ++y, f += m_width, g += image.Width() )
7231  P::Copy( f, g, m_width );
7232  }
7233 
7234  return *this;
7235  }
7236 
7237  GenericImage& Assign( const GenericImage& image,
7238  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
7239  {
7240  m_status = image.Status();
7241 
7242  Rect r = rect;
7243  if ( !image.ParseSelection( r, firstChannel, lastChannel ) )
7244  {
7245  FreeData();
7246  return *this;
7247  }
7248 
7249 #define completeSelection (firstChannel == 0 && lastChannel == image.m_numberOfChannels-1 && r == image.Bounds())
7250 
7251  if ( m_data == image.m_data )
7252  {
7253  // Self-assignment
7254  if ( !completeSelection )
7255  {
7256  GenericImage result( image, r, firstChannel, lastChannel ); // ### implicit recursion
7257  result.m_data->Attach( this );
7258  DetachFromData();
7259  m_data = result.m_data;
7260  }
7261  ResetSelections();
7262  return *this;
7263  }
7264 
7265  if ( !IsShared() )
7266  if ( !image.IsShared() )
7267  if ( completeSelection )
7268  {
7269  image.m_data->Attach( this );
7270  DetachFromData();
7271  m_data = image.m_data;
7272  ResetSelections();
7273  return *this;
7274  }
7275 
7276 #undef completeSelection
7277 
7278  int n = 1 + lastChannel - firstChannel;
7279  AllocateData( r, n, (firstChannel == 0 && n >= ColorSpace::NumberOfNominalChannels( image.ColorSpace() )) ?
7280  image.ColorSpace() : ColorSpace::Gray );
7281 
7282  if ( !IsShared() ) // ### cannot modify a shared image's RGBWS
7283  m_RGBWS = image.m_RGBWS;
7284 
7285  ResetSelections();
7286 
7287  if ( r == image.Bounds() )
7288  for ( int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7289  P::Copy( m_pixelData[c], image.m_pixelData[firstChannel], NumberOfPixels() );
7290  else
7291  for ( int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7292  {
7293  sample* f = m_pixelData[c];
7294  const sample* g = image.PixelAddress( r.LeftTop(), firstChannel );
7295  for ( int y = 0; y < m_height; ++y, f += m_width, g += image.m_width )
7296  P::Copy( f, g, m_width );
7297  }
7298 
7299  return *this;
7300  }
7301 
7308  template <class P1>
7309  GenericImage& operator =( const GenericImage<P1>& image )
7310  {
7311  return Assign( image );
7312  }
7313 
7324  GenericImage& operator =( const GenericImage& image )
7325  {
7326  return Assign( image );
7327  }
7328 
7329 #define TRANSFER_BODY() \
7330  if ( m_data != image.m_data ) \
7331  { \
7332  DetachFromData(); \
7333  m_data = image.m_data; \
7334  (void)AbstractImage::operator =( image ); \
7335  image.m_data = nullptr; \
7336  } \
7337  return *this
7338 
7351  {
7352  TRANSFER_BODY();
7353  }
7354 
7367  {
7368  TRANSFER_BODY();
7369  }
7370 
7371 #undef TRANSFER_BODY
7372 
7378  GenericImage& operator =( GenericImage&& image )
7379  {
7380  return Transfer( image );
7381  }
7382 
7389  GenericImage& operator =( sample scalar )
7390  {
7391  return Fill( scalar );
7392  }
7393 
7397  friend void Swap( GenericImage& x1, GenericImage& x2 )
7398  {
7399  x1.AbstractImage::Swap( x2 );
7400  pcl::Swap( x1.m_data, x2.m_data );
7401  }
7402 
7403  // -------------------------------------------------------------------------
7404 
7405 #ifndef __PCL_NO_VECTOR_IMAGE_CONVERSION
7406 
7425  sample_vector RowVector( int y, int channel = -1 ) const
7426  {
7427  if ( channel < 0 )
7428  channel = m_channel;
7429  if ( y < 0 || y >= m_height || channel < 0 || channel >= m_numberOfChannels )
7430  return sample_vector();
7431  sample_vector row( m_width );
7432  P::Get( row.Begin(), ScanLine( y, channel ), m_width );
7433  return row;
7434  }
7435 
7454  sample_vector ColumnVector( int x, int channel = -1 ) const
7455  {
7456  if ( channel < 0 )
7457  channel = m_channel;
7458  if ( x < 0 || x >= m_width || channel < 0 || channel >= m_numberOfChannels )
7459  return sample_vector();
7460  sample_vector col( m_height );
7461  const sample* v = PixelAddress( x, 0, channel );
7462  for ( int y = 0; y < m_height; ++y, v += m_width )
7463  col[y] = *v;
7464  return col;
7465  }
7466 
7470  sample_vector ColVector( int x, int channel = 0 ) const
7471  {
7472  return ColumnVector( x, channel );
7473  }
7474 
7475 #endif // !__PCL_NO_VECTOR_IMAGE_CONVERSION
7476 
7498  template <typename T>
7499  void GetRow( T* buffer, int y, int channel = -1 ) const
7500  {
7501  PCL_PRECONDITION( buffer != 0 )
7502  if ( channel < 0 )
7503  channel = m_channel;
7504  if ( y >= 0 && y < m_height && channel >= 0 && channel < m_numberOfChannels )
7505  P::Get( buffer, ScanLine( y, channel ), m_width );
7506  }
7507 
7529  template <typename T>
7530  void GetColumn( T* buffer, int x, int channel = -1 ) const
7531  {
7532  PCL_PRECONDITION( buffer != 0 )
7533  if ( channel < 0 )
7534  channel = m_channel;
7535  if ( x >= 0 && x < m_width && channel >= 0 && channel < m_numberOfChannels )
7536  {
7537  const sample* v = PixelAddress( x, 0, channel );
7538  for ( int y = 0; y < m_height; ++y, ++buffer, v += m_width )
7539  P::FromSample( *buffer, *v );
7540  }
7541  }
7542 
7564  template <typename T>
7565  GenericImage& SetRow( const T* buffer, int y, int channel = -1 )
7566  {
7567  PCL_PRECONDITION( buffer != 0 )
7568  if ( channel < 0 )
7569  channel = m_channel;
7570  if ( y >= 0 && y < m_height && channel >= 0 && channel < m_numberOfChannels )
7571  P::Copy( ScanLine( y, channel ), buffer, m_width );
7572  return *this;
7573  }
7574 
7596  template <typename T>
7597  GenericImage& SetColumn( const T* buffer, int x, int channel = -1 )
7598  {
7599  PCL_PRECONDITION( buffer != 0 )
7600  if ( channel < 0 )
7601  channel = m_channel;
7602  if ( x >= 0 && x < m_width && channel >= 0 && channel < m_numberOfChannels )
7603  {
7604  sample* v = PixelAddress( x, 0, channel );
7605  for ( int y = 0; y < m_height; ++y, ++buffer, v += m_width )
7606  *v = P::ToSample( *buffer );
7607  }
7608  return *this;
7609  }
7610 
7611  // -------------------------------------------------------------------------
7612 
7623  {
7624  if ( n > 0 && m_numberOfChannels > 0 )
7625  {
7626  EnsureUnique();
7627  sample** oldData = m_pixelData;
7628  sample** newData = nullptr;
7629  try
7630  {
7631  newData = m_allocator.AllocateChannelSlots( m_numberOfChannels+n );
7632  for ( int i = 0; i < m_numberOfChannels; ++i )
7633  newData[i] = oldData[i];
7634  for ( int i = 0; i < n; ++i )
7635  newData[m_numberOfChannels+i] = m_allocator.AllocatePixels( m_width, m_height );
7636  }
7637  catch ( ... )
7638  {
7639  if ( newData != nullptr )
7640  {
7641  for ( int i = 0; i < n; ++i )
7642  if ( newData[m_numberOfChannels+i] != nullptr )
7643  m_allocator.Deallocate( newData[m_numberOfChannels+i] );
7644  m_allocator.Deallocate( newData );
7645  }
7646  throw;
7647  }
7648 
7649  m_allocator.SetSharedData( m_pixelData = newData );
7650  m_allocator.SetSharedGeometry( m_width, m_height, m_numberOfChannels += n );
7651  m_allocator.Deallocate( oldData );
7652  }
7653 
7654  return *this;
7655  }
7656 
7671  GenericImage& AddAlphaChannel( sample* data = nullptr )
7672  {
7673  // $$$ WARNING $$$
7674  // * If this is a shared image, data must either be null or point to a
7675  // shared memory block.
7676  // * If this is a local image, data must either be null or point to a
7677  // block allocated in the local heap.
7678 
7679  if ( data == nullptr )
7680  CreateAlphaChannels( 1 );
7681  else if ( m_numberOfChannels > 0 )
7682  {
7683  EnsureUnique();
7684  sample** oldData = m_pixelData;
7685  sample** newData = nullptr;
7686  try
7687  {
7688  newData = m_allocator.AllocateChannelSlots( m_numberOfChannels+1 );
7689  for ( int i = 0; i < m_numberOfChannels; ++i )
7690  newData[i] = oldData[i];
7691  newData[m_numberOfChannels] = data;
7692  }
7693  catch ( ... )
7694  {
7695  if ( newData != nullptr )
7696  m_allocator.Deallocate( newData );
7697  throw;
7698  }
7699 
7700  m_allocator.SetSharedData( m_pixelData = newData );
7701  m_allocator.SetSharedGeometry( m_width, m_height, ++m_numberOfChannels );
7702  m_allocator.Deallocate( oldData );
7703  }
7704 
7705  return *this;
7706  }
7707 
7731  {
7732  if ( IsShared() != image.IsShared() )
7733  throw Error( "GenericImage::ReleaseAlphaChannel(): Cannot release pixel data between local and shared images" );
7734 
7735  if ( channel < 0 || channel >= NumberOfAlphaChannels() )
7736  {
7737  image.FreeData();
7738  return *this;
7739  }
7740 
7741  int c = NumberOfNominalChannels() + channel;
7742 
7743  sample** newData = nullptr;
7744  try
7745  {
7746  newData = image.m_allocator.AllocateChannelSlots( 1 );
7747  *newData = m_pixelData[c];
7748  }
7749  catch ( ... )
7750  {
7751  if ( newData != nullptr )
7752  image.m_allocator.Deallocate( newData );
7753  throw;
7754  }
7755 
7756  image.FreeData();
7757 
7758  image.m_pixelData = newData;
7759  image.m_width = m_width;
7760  image.m_height = m_height;
7761  image.m_numberOfChannels = 1;
7762  image.m_colorSpace = ColorSpace::Gray;
7763  image.m_data->UpdateSharedImage();
7764  image.ResetSelections();
7765 
7766  m_pixelData[c] = nullptr;
7767  ForgetAlphaChannel( channel );
7768 
7769  return *this;
7770  }
7771 
7784  {
7785  if ( channel >= 0 && channel < NumberOfAlphaChannels() )
7786  {
7787  EnsureUnique();
7788  int c = NumberOfNominalChannels() + channel;
7789  m_allocator.Deallocate( m_pixelData[c] );
7790  m_pixelData[c] = nullptr;
7791  ForgetAlphaChannel( channel );
7792  }
7793 
7794  return *this;
7795  }
7796 
7814  {
7815  if ( channel >= 0 && channel < NumberOfAlphaChannels() )
7816  {
7817  EnsureUnique();
7818  sample** oldData = m_pixelData;
7819  sample** newData = m_allocator.AllocateChannelSlots( m_numberOfChannels-1 );
7820 
7821  int n0 = NumberOfNominalChannels();
7822  int c = n0 + channel;
7823 
7824  for ( int i = 0; i < c; ++i )
7825  newData[i] = oldData[i];
7826  for ( int i = c, j = c; ++j < m_numberOfChannels; ++i )
7827  newData[i] = oldData[j];
7828 
7829  m_allocator.SetSharedData( m_pixelData = newData );
7830  m_allocator.SetSharedGeometry( m_width, m_height, --m_numberOfChannels );
7831 
7832  if ( m_channel >= n0 || m_lastChannel >= n0 )
7833  ResetChannelRange();
7834 
7835  m_allocator.Deallocate( oldData );
7836  }
7837 
7838  return *this;
7839  }
7840 
7846  {
7847  int n0 = NumberOfNominalChannels();
7848  int n = m_numberOfChannels;
7849  if ( n > n0 )
7850  {
7851  EnsureUnique();
7852  do
7853  m_allocator.Deallocate( m_pixelData[--n] ), m_pixelData[n] = nullptr;
7854  while ( n > n0 );
7855  ForgetAlphaChannels();
7856  }
7857 
7858  return *this;
7859  }
7860 
7870  {
7871  int n0 = NumberOfNominalChannels();
7872  if ( m_numberOfChannels > n0 )
7873  {
7874  EnsureUnique();
7875  sample** oldData = m_pixelData;
7876  sample** newData = m_allocator.AllocateChannelSlots( n0 );
7877 
7878  for ( int i = 0; i < n0; ++i )
7879  newData[i] = oldData[i];
7880 
7881  m_allocator.SetSharedData( m_pixelData = newData );
7882  m_allocator.SetSharedGeometry( m_width, m_height, m_numberOfChannels = n0 );
7883 
7884  if ( m_channel >= n0 || m_lastChannel >= n0 )
7885  ResetChannelRange();
7886 
7887  m_allocator.Deallocate( oldData );
7888  }
7889 
7890  return *this;
7891  }
7892 
7893  // -------------------------------------------------------------------------
7894 
7931  template <typename T>
7932  GenericImage& Fill( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
7933  {
7934  Rect r = rect;
7935  if ( !ParseSelection( r, firstChannel, lastChannel ) )
7936  return *this;
7937 
7938  EnsureUnique();
7939 
7940  size_type N = size_type( r.Width() )*size_type( r.Height() );
7941  if ( m_status.IsInitializationEnabled() )
7942  m_status.Initialize( "Filling image", N*(1 + lastChannel - firstChannel) );
7943 
7944  sample v = P::ToSample( scalar );
7945 
7946  if ( r == Bounds() )
7947  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
7948  P::Fill( m_pixelData[i], v, N );
7949  else
7950  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
7951  {
7952  sample* f = PixelAddress( r.LeftTop(), i );
7953  for ( int j = 0; j < h; ++j, f += m_width )
7954  P::Fill( f, v, w );
7955  }
7956 
7957  return *this;
7958  }
7959 
7977  template <typename T>
7979  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
7980  {
7981  Rect r = rect;
7982  if ( !ParseSelection( r, firstChannel, lastChannel ) )
7983  return *this;
7984 
7985  EnsureUnique();
7986 
7987  size_type N = size_type( r.Width() )*size_type( r.Height() );
7988  if ( m_status.IsInitializationEnabled() )
7989  m_status.Initialize( "Filling image", N*(1 + lastChannel - firstChannel) );
7990 
7991  if ( r == Bounds() )
7992  for ( int i = firstChannel, c = 0; i <= lastChannel; ++i, ++c, m_status += N )
7993  {
7994  sample v = (c < values.Length()) ? P::ToSample( values[c] ) : P::MinSampleValue();
7995  P::Fill( m_pixelData[i], v, N );
7996  }
7997  else
7998  for ( int i = firstChannel, c = 0, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, ++c, m_status += N )
7999  {
8000  sample* f = PixelAddress( r.LeftTop(), i );
8001  sample v = (c < values.Length()) ? P::ToSample( values[c] ) : P::MinSampleValue();
8002  for ( int j = 0; j < h; ++j, f += m_width )
8003  P::Fill( f, v, w );
8004  }
8005 
8006  return *this;
8007  }
8008 
8019  template <typename T>
8020  GenericImage Filled( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8021  {
8022  GenericImage result( *this, rect, firstChannel, lastChannel );
8023  (void)result.Fill( scalar );
8024  return result;
8025  }
8026 
8038  template <typename T>
8040  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8041  {
8042  GenericImage result( *this, rect, firstChannel, lastChannel );
8043  (void)result.Fill( values );
8044  return result;
8045  }
8046 
8061  GenericImage& Zero( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8062  {
8063  return Fill( P::ToSample( 0.0 ), rect, firstChannel, lastChannel );
8064  }
8065 
8080  GenericImage& One( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8081  {
8082  return Fill( P::ToSample( 1.0 ), rect, firstChannel, lastChannel );
8083  }
8084 
8098  GenericImage& Black( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8099  {
8100  return Fill( P::MinSampleValue(), rect, firstChannel, lastChannel );
8101  }
8102 
8116  GenericImage& White( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8117  {
8118  return Fill( P::MaxSampleValue(), rect, firstChannel, lastChannel );
8119  }
8120 
8121  // -------------------------------------------------------------------------
8122 
8137  template <typename T>
8138  GenericImage& Invert( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8139  {
8140  Rect r = rect;
8141  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8142  return *this;
8143 
8144  EnsureUnique();
8145 
8146  size_type N = size_type( r.Width() )*size_type( r.Height() );
8147  if ( m_status.IsInitializationEnabled() )
8148  m_status.Initialize( "Inverting samples", N*(1 + lastChannel - firstChannel) );
8149 
8150  sample v = P::ToSample( scalar );
8151 
8152  if ( r == Bounds() )
8153  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8154  for ( sample* f = m_pixelData[i], * f1 = f+N; f < f1; ++f )
8155  *f = v - *f;
8156  else
8157  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8158  {
8159  sample* f = PixelAddress( r.LeftTop(), i );
8160  for ( int j = 0; j < h; ++j, f += m_width-w )
8161  for ( sample* f1 = f+w; f < f1; ++f )
8162  *f = v - *f;
8163  }
8164 
8165  return *this;
8166  }
8167 
8178  template <typename T>
8179  GenericImage Inverted( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8180  {
8181  GenericImage result( *this, rect, firstChannel, lastChannel );
8182  (void)result.Invert( scalar );
8183  return result;
8184  }
8185 
8203  GenericImage& Invert( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8204  {
8205  return Invert( P::MaxSampleValue(), rect, firstChannel, lastChannel );
8206  }
8207 
8219  GenericImage Inverted( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8220  {
8221  GenericImage result( *this, rect, firstChannel, lastChannel );
8222  (void)result.Invert();
8223  return result;
8224  }
8225 
8234  GenericImage operator ~() const
8235  {
8236  GenericImage result( *this );
8237  (void)result.Invert();
8238  return result;
8239  }
8240 
8251  GenericImage& Not( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8252  {
8253  Rect r = rect;
8254  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8255  return *this;
8256 
8257  EnsureUnique();
8258 
8259  size_type N = size_type( r.Width() )*size_type( r.Height() );
8260  if ( m_status.IsInitializationEnabled() )
8261  m_status.Initialize( "Bitwise Not", N*(1 + lastChannel - firstChannel) );
8262 
8263  if ( r == Bounds() )
8264  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8265  for ( sample* f = m_pixelData[i], * f1 = f+N; f < f1; ++f )
8266  P::Not( *f );
8267  else
8268  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8269  {
8270  sample* f = PixelAddress( r.LeftTop(), i );
8271  for ( int j = 0; j < h; ++j, f += m_width-w )
8272  for ( sample* f1 = f+w; f < f1; ++f )
8273  P::Not( *f );
8274  }
8275 
8276  return *this;
8277  }
8278 
8295  template <typename T>
8296  GenericImage& Truncate( T lowerBound, T upperBound,
8297  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8298  {
8299  Rect r = rect;
8300  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8301  return *this;
8302 
8303  EnsureUnique();
8304 
8305  size_type N = size_type( r.Width() )*size_type( r.Height() );
8306  if ( m_status.IsInitializationEnabled() )
8307  m_status.Initialize( "Truncating samples", N*(1 + lastChannel - firstChannel) );
8308 
8309  sample b0 = P::ToSample( lowerBound );
8310  sample b1 = P::ToSample( upperBound );
8311  if ( b1 < b0 )
8312  pcl::Swap( b0, b1 );
8313 
8314  if ( r == Bounds() )
8315  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8316  {
8317  for ( sample* f = m_pixelData[i], * f1 = f+N; f < f1; ++f )
8318  if ( *f < b0 )
8319  *f = b0;
8320  else if ( b1 < *f )
8321  *f = b1;
8322  }
8323  else
8324  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8325  {
8326  sample* f = PixelAddress( r.LeftTop(), i );
8327  for ( int j = 0; j < h; ++j, f += m_width-w )
8328  for ( sample* f1 = f+w; f < f1; ++f )
8329  if ( *f < b0 )
8330  *f = b0;
8331  else if ( b1 < *f )
8332  *f = b1;
8333  }
8334 
8335  return *this;
8336  }
8337 
8351  template <typename T>
8352  GenericImage Truncated( T lowerBound, T upperBound,
8353  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8354  {
8355  GenericImage result( *this, rect, firstChannel, lastChannel );
8356  (void)result.Truncate( lowerBound, upperBound );
8357  return result;
8358  }
8359 
8381  GenericImage& Truncate( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8382  {
8383  return Truncate( P::MinSampleValue(), P::MaxSampleValue(), rect, firstChannel, lastChannel );
8384  }
8385 
8396  GenericImage Truncated( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8397  {
8398  GenericImage result( *this, rect, firstChannel, lastChannel );
8399  (void)result.Truncate();
8400  return result;
8401  }
8402 
8431  template <typename T>
8432  GenericImage& Rescale( T lowerBound, T upperBound,
8433  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8434  {
8435  Rect r = rect;
8436  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8437  return *this;
8438 
8439  size_type N = size_type( r.Width() )*size_type( r.Height() );
8440  size_type Ns = N*(1 + lastChannel - firstChannel);
8441  if ( m_status.IsInitializationEnabled() )
8442  m_status.Initialize( "Rescaling samples", Ns );
8443 
8444  sample b0 = P::ToSample( lowerBound );
8445  sample b1 = P::ToSample( upperBound );
8446  if ( b1 < b0 )
8447  pcl::Swap( b0, b1 );
8448 
8449  sample v0, v1;
8450  GetExtremePixelValues( v0, v1, r, firstChannel, lastChannel );
8451 
8452  if ( v0 == b0 && v1 == b1 )
8453  {
8454  m_status += Ns;
8455  return *this;
8456  }
8457 
8458  EnsureUnique();
8459 
8460  double d = 0;
8461  if ( b0 != b1 )
8462  if ( v0 != v1 )
8463  d = (double( b1 ) - double( b0 ))/(double( v1 ) - double( v0 ));
8464 
8465  if ( r == Bounds() )
8466  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8467  {
8468  if ( v0 != v1 )
8469  {
8470  if ( b0 != b1 )
8471  {
8472  if ( b0 == sample( 0 ) )
8473  for ( sample* f = m_pixelData[i], * f1 = f+N; f < f1; ++f )
8474  *f = P::FloatToSample( d*(*f - v0) );
8475  else
8476  for ( sample* f = m_pixelData[i], * f1 = f+N; f < f1; ++f )
8477  *f = P::FloatToSample( d*(*f - v0) + b0 );
8478  }
8479  else
8480  P::Fill( m_pixelData[i], b0, N );
8481  }
8482  else
8483  P::Fill( m_pixelData[i], pcl::Range( v0, b0, b1 ), N );
8484  }
8485  else
8486  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8487  {
8488  sample* f = PixelAddress( r.LeftTop(), i );
8489 
8490  if ( v0 != v1 )
8491  {
8492  if ( b0 != b1 )
8493  {
8494  if ( b0 == sample( 0 ) )
8495  for ( int j = 0; j < h; ++j, f += m_width-w )
8496  for ( sample* f1 = f+w; f < f1; ++f )
8497  *f = P::FloatToSample( d*(*f - v0) );
8498  else
8499  for ( int j = 0; j < h; ++j, f += m_width-w )
8500  for ( sample* f1 = f+w; f < f1; ++f )
8501  *f = P::FloatToSample( d*(*f - v0) + b0 );
8502  }
8503  else
8504  for ( int j = 0; j < h; ++j, f += m_width )
8505  P::Fill( f, b0, w );
8506  }
8507  else
8508  {
8509  sample v = pcl::Range( v0, b0, b1 );
8510  for ( int j = 0; j < h; ++j, f += m_width )
8511  P::Fill( f, v, w );
8512  }
8513  }
8514 
8515  return *this;
8516  }
8517 
8531  template <typename T>
8532  GenericImage Rescaled( T lowerBound, T upperBound,
8533  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8534  {
8535  GenericImage result( *this, rect, firstChannel, lastChannel );
8536  (void)result.Rescale( lowerBound, upperBound );
8537  return result;
8538  }
8539 
8556  GenericImage& Rescale( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8557  {
8558  return Rescale( P::MinSampleValue(), P::MaxSampleValue(), rect, firstChannel, lastChannel );
8559  }
8560 
8571  GenericImage Rescaled( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8572  {
8573  GenericImage result( *this, rect, firstChannel, lastChannel );
8574  (void)result.Rescale();
8575  return result;
8576  }
8577 
8612  template <typename T>
8613  GenericImage& Normalize( T lowerBound, T upperBound,
8614  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8615  {
8616  Rect r = rect;
8617  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8618  return *this;
8619 
8620  size_type N = size_type( r.Width() )*size_type( r.Height() );
8621  size_type Ns = N*(1 + lastChannel - firstChannel);
8622  if ( m_status.IsInitializationEnabled() )
8623  m_status.Initialize( "Normalizing samples", Ns );
8624 
8625  sample b0 = P::ToSample( lowerBound );
8626  sample b1 = P::ToSample( upperBound );
8627  if ( b1 < b0 )
8628  pcl::Swap( b0, b1 );
8629 
8630  sample v0, v1;
8631  GetExtremePixelValues( v0, v1, r, firstChannel, lastChannel );
8632 
8633  if ( v0 >= b0 && v1 <= b1 )
8634  {
8635  m_status += Ns;
8636  return *this;
8637  }
8638 
8639  EnsureUnique();
8640 
8641  double d = 0;
8642  if ( b0 != b1 )
8643  if ( v0 != v1 )
8644  d = (double( b1 ) - double( b0 ))/(double( v1 ) - double( v0 ));
8645 
8646  if ( r == Bounds() )
8647  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8648  {
8649  if ( v0 != v1 )
8650  {
8651  if ( b0 != b1 )
8652  {
8653  if ( b0 == sample( 0 ) )
8654  for ( sample* f = m_pixelData[i], * f1 = f+N; f < f1; ++f )
8655  *f = P::FloatToSample( d*(*f - v0) );
8656  else
8657  for ( sample* f = m_pixelData[i], * f1 = f+N; f < f1; ++f )
8658  *f = P::FloatToSample( d*(*f - v0) + b0 );
8659  }
8660  else
8661  P::Fill( m_pixelData[i], b0, N );
8662  }
8663  else
8664  P::Fill( m_pixelData[i], pcl::Range( v0, b0, b1 ), N );
8665  }
8666  else
8667  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8668  {
8669  sample* f = PixelAddress( r.LeftTop(), i );
8670 
8671  if ( v0 != v1 )
8672  {
8673  if ( b0 != b1 )
8674  {
8675  if ( b0 == sample( 0 ) )
8676  for ( int j = 0; j < h; ++j, f += m_width-w )
8677  for ( sample* f1 = f+w; f < f1; ++f )
8678  *f = P::FloatToSample( d*(*f - v0) );
8679  else
8680  for ( int j = 0; j < h; ++j, f += m_width-w )
8681  for ( sample* f1 = f+w; f < f1; ++f )
8682  *f = P::FloatToSample( d*(*f - v0) + b0 );
8683  }
8684  else
8685  for ( int j = 0; j < h; ++j, f += m_width )
8686  P::Fill( f, b0, w );
8687  }
8688  else
8689  {
8690  sample v = pcl::Range( v0, b0, b1 );
8691  for ( int j = 0; j < h; ++j, f += m_width )
8692  P::Fill( f, v, w );
8693  }
8694  }
8695 
8696  return *this;
8697  }
8698 
8712  template <typename T>
8713  GenericImage Normalized( T lowerBound, T upperBound,
8714  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8715  {
8716  GenericImage result( *this, rect, firstChannel, lastChannel );
8717  (void)result.Normalize( lowerBound, upperBound );
8718  return result;
8719  }
8720 
8737  GenericImage& Normalize( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8738  {
8739  return Normalize( P::MinSampleValue(), P::MaxSampleValue(), rect, firstChannel, lastChannel );
8740  }
8741 
8752  GenericImage Normalized( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8753  {
8754  GenericImage result( *this, rect, firstChannel, lastChannel );
8755  (void)result.Normalize();
8756  return result;
8757  }
8758 
8788  template <typename T>
8789  GenericImage& Binarize( T threshold,
8790  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8791  {
8792  Rect r = rect;
8793  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8794  return *this;
8795 
8796  EnsureUnique();
8797 
8798  size_type N = size_type( r.Width() )*size_type( r.Height() );
8799  if ( m_status.IsInitializationEnabled() )
8800  m_status.Initialize( "Binarizing samples", N*(1 + lastChannel - firstChannel) );
8801 
8802  sample t = P::ToSample( threshold );
8803 
8804  if ( r == Bounds() )
8805  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8806  for ( sample* f = m_pixelData[i], * f1 = f+N; f < f1; ++f )
8807  *f = (*f < t) ? P::MinSampleValue() : P::MaxSampleValue();
8808  else
8809  for ( int c = firstChannel, w = r.Width(), h = r.Height(); c <= lastChannel; ++c, m_status += N )
8810  {
8811  sample* f = PixelAddress( r.LeftTop(), c );
8812  for ( int j = 0; j < h; ++j, f += m_width-w )
8813  for ( sample* f1 = f+w; f < f1; ++f )
8814  *f = (*f < t) ? P::MinSampleValue() : P::MaxSampleValue();
8815  }
8816 
8817  return *this;
8818  }
8819 
8830  template <typename T>
8831  GenericImage Binarized( T threshold,
8832  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8833  {
8834  GenericImage result( *this, rect, firstChannel, lastChannel );
8835  (void)result.Binarize( threshold );
8836  return result;
8837  }
8838 
8855  GenericImage& Binarize( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8856  {
8857  return Binarize( (P::MinSampleValue() + P::MaxSampleValue())/2, rect, firstChannel, lastChannel );
8858  }
8859 
8871  GenericImage Binarized( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8872  {
8873  GenericImage result( *this, rect, firstChannel, lastChannel );
8874  (void)result.Binarize();
8875  return result;
8876  }
8877 
8891  GenericImage& SetAbsoluteValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8892  {
8893  Rect r = rect;
8894  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8895  return *this;
8896 
8897  EnsureUnique();
8898 
8899  size_type N = size_type( r.Width() )*size_type( r.Height() );
8900  if ( m_status.IsInitializationEnabled() )
8901  m_status.Initialize( "Computing absolute value", N*(1 + lastChannel - firstChannel) );
8902 
8903  if ( r == Bounds() )
8904  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8905  for ( sample* f = m_pixelData[i], * f1 = f+N; f < f1; ++f )
8906  *f = pcl::Abs( *f );
8907  else
8908  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
8909  {
8910  sample* f = PixelAddress( r.LeftTop(), i );
8911  for ( int j = 0; j < h; ++j, f += m_width-w )
8912  for ( sample* f1 = f+w; f < f1; ++f )
8913  *f = pcl::Abs( *f );
8914  }
8915 
8916  return *this;
8917  }
8918 
8922  GenericImage& Abs( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8923  {
8924  return SetAbsoluteValue( rect, firstChannel, lastChannel );
8925  }
8926 
8937  GenericImage AbsoluteValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
8938  {
8939  GenericImage result( *this, rect, firstChannel, lastChannel );
8940  (void)result.SetAbsoluteValue();
8941  return result;
8942  }
8943 
8944  // -------------------------------------------------------------------------
8945 
8946  /*
8947  * Implementation of Apply( scalar ) member functions. We have to have a
8948  * separate implementation function to prevent infinite recursion in several
8949  * template specializations of the Apply() member function.
8950  */
8951  template <typename T>
8952  GenericImage& ApplyScalar( T scalar, image_op op = ImageOp::Mov,
8953  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
8954  {
8955  if ( op == ImageOp::Div )
8956  if ( 1 + scalar == 1 )
8957  throw Error( "Division by zero or insignificant scalar" );
8958 
8959  Rect r = rect;
8960  if ( !ParseSelection( r, firstChannel, lastChannel ) )
8961  return *this;
8962 
8963  EnsureUnique();
8964 
8965  size_type N = size_type( r.Width() )*size_type( r.Height() );
8966  if ( m_status.IsInitializationEnabled() )
8967  m_status.Initialize( "Applying scalar: "
8968  + ImageOp::Id( op )
8969  + ' ' + String( scalar ), N*(1 + lastChannel - firstChannel) );
8970 
8971  if ( r == Bounds() )
8972  for ( int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8973  {
8974  sample* f = m_pixelData[i];
8975 #define ITERATE( Op ) \
8976  for ( sample* f1 = f+N; f < f1; ++f ) \
8977  P::Op( *f, scalar )
8978  switch ( op )
8979  {
8980  case ImageOp::Mov: ITERATE( Mov ); break;
8981  case ImageOp::Add: ITERATE( Add ); break;
8982  case ImageOp::Sub: ITERATE( Sub ); break;
8983  case ImageOp::Mul: ITERATE( Mul ); break;
8984  case ImageOp::Div: ITERATE( Div ); break;
8985  case ImageOp::Pow: ITERATE( Pow ); break;
8986  case ImageOp::Dif: ITERATE( Dif ); break;
8987  case ImageOp::Min: ITERATE( Min ); break;
8988  case ImageOp::Max: ITERATE( Max ); break;
8989  case ImageOp::Not: ITERATE( Not ); break;
8990  case ImageOp::Or: ITERATE( Or ); break;
8991  case ImageOp::Nor: ITERATE( Nor ); break;
8992  case ImageOp::And: ITERATE( And ); break;
8993  case ImageOp::Nand: ITERATE( Nand ); break;
8994  case ImageOp::Xor: ITERATE( Xor ); break;
8995  case ImageOp::Xnor: ITERATE( Xnor ); break;
8996  case ImageOp::ColorBurn: ITERATE( ColorBurn ); break;
8997  case ImageOp::LinearBurn: ITERATE( LinearBurn ); break;
8998  case ImageOp::Screen: ITERATE( Screen ); break;
8999  case ImageOp::ColorDodge: ITERATE( ColorDodge ); break;
9000  case ImageOp::Overlay: ITERATE( Overlay ); break;
9001  case ImageOp::SoftLight: ITERATE( SoftLight ); break;
9002  case ImageOp::HardLight: ITERATE( HardLight ); break;
9003  case ImageOp::VividLight: ITERATE( VividLight ); break;
9004  case ImageOp::LinearLight: ITERATE( LinearLight ); break;
9005  case ImageOp::PinLight: ITERATE( PinLight ); break;
9006  case ImageOp::Exclusion: ITERATE( Exclusion ); break;
9007  default: break;
9008  }
9009 #undef ITERATE
9010  }
9011  else
9012  for ( int i = firstChannel, w = r.Width(), h = r.Height(); i <= lastChannel; ++i, m_status += N )
9013  {
9014  sample* f = PixelAddress( r.LeftTop(), i );
9015 #define ITERATE( Op ) \
9016  for ( int j = 0; j < h; ++j, f += m_width-w ) \
9017  for ( sample* f1 = f+w; f < f1; ++f ) \
9018  P::Op( *f, scalar )
9019  switch ( op )
9020  {
9021  case ImageOp::Mov: ITERATE( Mov ); break;
9022  case ImageOp::Add: ITERATE( Add ); break;
9023  case ImageOp::Sub: ITERATE( Sub ); break;
9024  case ImageOp::Mul: ITERATE( Mul ); break;
9025  case ImageOp::Div: ITERATE( Div ); break;
9026  case ImageOp::Pow: ITERATE( Pow ); break;
9027  case ImageOp::Dif: ITERATE( Dif ); break;
9028  case ImageOp::Min: ITERATE( Min ); break;
9029  case ImageOp::Max: ITERATE( Max ); break;
9030  case ImageOp::Not: ITERATE( Not ); break;
9031  case ImageOp::Or: ITERATE( Or ); break;
9032  case ImageOp::Nor: ITERATE( Nor ); break;
9033  case ImageOp::And: ITERATE( And ); break;
9034  case ImageOp::Nand: ITERATE( Nand ); break;
9035  case ImageOp::Xor: ITERATE( Xor ); break;
9036  case ImageOp::Xnor: ITERATE( Xnor ); break;
9037  case ImageOp::ColorBurn: ITERATE( ColorBurn ); break;
9038  case ImageOp::LinearBurn: ITERATE( LinearBurn ); break;
9039  case ImageOp::Screen: ITERATE( Screen ); break;
9040  case ImageOp::ColorDodge: ITERATE( ColorDodge ); break;
9041  case ImageOp::Overlay: ITERATE( Overlay ); break;
9042  case ImageOp::SoftLight: ITERATE( SoftLight ); break;
9043  case ImageOp::HardLight: ITERATE( HardLight ); break;
9044  case ImageOp::VividLight: ITERATE( VividLight ); break;
9045  case ImageOp::LinearLight: ITERATE( LinearLight ); break;
9046  case ImageOp::PinLight: ITERATE( PinLight ); break;
9047  case ImageOp::Exclusion: ITERATE( Exclusion ); break;
9048  default: break;
9049  }
9050 #undef ITERATE
9051  }
9052 
9053  return *this;
9054  }
9055 
9078  template <typename T>
9079  GenericImage& Apply( T scalar, image_op op = ImageOp::Mov,
9080  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9081  {
9082  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9083  }
9084 
9085  GenericImage& Apply( float scalar, image_op op = ImageOp::Mov,
9086  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9087  {
9089  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9090  return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9091  }
9092 
9093  GenericImage& Apply( double scalar, image_op op = ImageOp::Mov,
9094  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9095  {
9097  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9098  return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9099  }
9100 
9101  GenericImage& Apply( pcl::Complex<float> scalar, image_op op = ImageOp::Mov,
9102  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9103  {
9105  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9106  return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9107  }
9108 
9109  GenericImage& Apply( pcl::Complex<double> scalar, image_op op = ImageOp::Mov,
9110  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9111  {
9113  return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9114  return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9115  }
9116 
9135  template <typename T>
9136  GenericImage Applied( T scalar, image_op op = ImageOp::Mov,
9137  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9138  {
9139  GenericImage result( *this, rect, firstChannel, lastChannel );
9140  (void)result.Apply( scalar, op );
9141  return result;
9142  }
9143 
9144  // -------------------------------------------------------------------------
9145 
9190  template <class P1>
9191  GenericImage& Apply( const GenericImage<P1>& image, image_op op = ImageOp::Mov,
9192  const Point& point = Point( int_max ), int channel = -1,
9193  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9194  {
9195  Rect r = rect;
9196  if ( !image.ParseSelection( r, firstChannel, lastChannel ) )
9197  return *this;
9198 
9199  if ( !ParseChannel( channel ) )
9200  return *this;
9201 
9202  Point p = point;
9203  if ( p.x == int_max || p.y == int_max )
9204  p = m_point;
9205 
9206  if ( p.x < 0 )
9207  {
9208  if ( (r.x0 -= p.x) >= r.x1 )
9209  return *this;
9210  p.x = 0;
9211  }
9212  else if ( p.x >= m_width )
9213  return *this;
9214 
9215  if ( p.y < 0 )
9216  {
9217  if ( (r.y0 -= p.y) >= r.y1 )
9218  return *this;
9219  p.y = 0;
9220  }
9221  else if ( p.y >= m_height )
9222  return *this;
9223 
9224  r.ResizeTo( pcl::Min( m_width - p.x, r.Width() ),
9225  pcl::Min( m_height - p.y, r.Height() ) );
9226 
9227  lastChannel = pcl::Min( lastChannel, firstChannel + m_numberOfChannels - channel - 1 );
9228 
9229  EnsureUnique();
9230 
9231  size_type N = size_type( r.Width() )*size_type( r.Height() );
9232  if ( m_status.IsInitializationEnabled() )
9233  m_status.Initialize( "Applying image, op=" + ImageOp::Id( op ), N*(1 + lastChannel - firstChannel) );
9234 
9235  if ( r == Bounds() && r == image.Bounds() )
9236  for ( int i = channel, j = firstChannel; j <= lastChannel; ++i, ++j, m_status += N )
9237  {
9238  sample* f = m_pixelData[i];
9239  const typename P1::sample* g = image[j];
9240 
9241 #define ITERATE( Op ) \
9242  for ( sample* f1 = f+N; f < f1; ++f, ++g ) \
9243  P::Op( *f, *g )
9244  switch ( op )
9245  {
9246  case ImageOp::Mov:
9247  P::Copy( f, g, N );
9248  break;
9249  case ImageOp::Min:
9250  P::CopyMin( f, g, N );
9251  break;
9252  case ImageOp::Max:
9253  P::CopyMax( f, g, N );
9254  break;
9255  default:
9256  switch ( op )
9257  {
9258  case ImageOp::Add: ITERATE( Add ); break;
9259  case ImageOp::Sub: ITERATE( Sub ); break;
9260  case ImageOp::Mul: ITERATE( Mul ); break;
9261  case ImageOp::Div:
9262  for ( sample* f1 = f+N; f < f1; ++f, ++g )
9263  if ( *g != 0 )
9264  P::Div( *f, *g );
9265  else
9266  *f = P::MaxSampleValue();
9267  break;
9268  case ImageOp::Pow: ITERATE( Pow ); break;
9269  case ImageOp::Dif: ITERATE( Dif ); break;
9270  case ImageOp::Not: ITERATE( Not ); break;
9271  case ImageOp::Or: ITERATE( Or ); break;
9272  case ImageOp::Nor: ITERATE( Nor ); break;
9273  case ImageOp::And: ITERATE( And ); break;
9274  case ImageOp::Nand: ITERATE( Nand ); break;
9275  case ImageOp::Xor: ITERATE( Xor ); break;
9276  case ImageOp::Xnor: ITERATE( Xnor ); break;
9277  case ImageOp::ColorBurn: ITERATE( ColorBurn ); break;
9278  case ImageOp::LinearBurn: ITERATE( LinearBurn ); break;
9279  case ImageOp::Screen: ITERATE( Screen ); break;
9280  case ImageOp::ColorDodge: ITERATE( ColorDodge ); break;
9281  case ImageOp::Overlay: ITERATE( Overlay ); break;
9282  case ImageOp::SoftLight: ITERATE( SoftLight ); break;
9283  case ImageOp::HardLight: ITERATE( HardLight ); break;
9284  case ImageOp::VividLight: ITERATE( VividLight ); break;
9285  case ImageOp::LinearLight: ITERATE( LinearLight ); break;
9286  case ImageOp::PinLight: ITERATE( PinLight ); break;
9287  case ImageOp::Exclusion: ITERATE( Exclusion ); break;
9288  default: break;
9289  }
9290 #undef ITERATE
9291  break;
9292  }
9293  }
9294  else
9295  for ( int i = channel, j = firstChannel, w = r.Width(), h = r.Height(); j <= lastChannel; ++i, ++j, m_status += N )
9296  {
9297  sample* f = PixelAddress( p, i );
9298  const typename P1::sample* g = image.PixelAddress( r.LeftTop(), j );
9299 
9300 #define ITERATE( Op ) \
9301  for ( int k = 0; k < h; ++k, f += m_width-w, g += image.Width()-w ) \
9302  for ( sample* f1 = f+w; f < f1; ++f, ++g ) \
9303  P::Op( *f, *g )
9304  switch ( op )
9305  {
9306  case ImageOp::Mov:
9307  for ( int k = 0; k < h; ++k, f += m_width, g += image.Width() )
9308  P::Copy( f, g, w );
9309  break;
9310  case ImageOp::Min:
9311  for ( int k = 0; k < h; ++k, f += m_width, g += image.Width() )
9312  P::CopyMin( f, g, w );
9313  break;
9314  case ImageOp::Max:
9315  for ( int k = 0; k < h; ++k, f += m_width, g += image.Width() )
9316  P::CopyMax( f, g, w );
9317  break;
9318  case ImageOp::Add: ITERATE( Add ); break;
9319  case ImageOp::Sub: ITERATE( Sub ); break;
9320  case ImageOp::Mul: ITERATE( Mul ); break;
9321  case ImageOp::Div:
9322  for ( int k = 0; k < h; ++k, f += m_width-w, g += image.Width()-w )
9323  for ( sample* f1 = f+w; f < f1; ++f, ++g )
9324  if ( *g != 0 )
9325  P::Div( *f, *g );
9326  else
9327  *f = P::MaxSampleValue();
9328  break;
9329  case ImageOp::Pow: ITERATE( Pow ); break;
9330  case ImageOp::Dif: ITERATE( Dif ); break;
9331  case ImageOp::Not: ITERATE( Not ); break;
9332  case ImageOp::Or: ITERATE( Or ); break;
9333  case ImageOp::Nor: ITERATE( Nor ); break;
9334  case ImageOp::And: ITERATE( And ); break;
9335  case ImageOp::Nand: ITERATE( Nand ); break;
9336  case ImageOp::Xor: ITERATE( Xor ); break;
9337  case ImageOp::Xnor: ITERATE( Xnor ); break;
9338  case ImageOp::ColorBurn: ITERATE( ColorBurn ); break;
9339  case ImageOp::LinearBurn: ITERATE( LinearBurn ); break;
9340  case ImageOp::Screen: ITERATE( Screen ); break;
9341  case ImageOp::ColorDodge: ITERATE( ColorDodge ); break;
9342  case ImageOp::Overlay: ITERATE( Overlay ); break;
9343  case ImageOp::SoftLight: ITERATE( SoftLight ); break;
9344  case ImageOp::HardLight: ITERATE( HardLight ); break;
9345  case ImageOp::VividLight: ITERATE( VividLight ); break;
9346  case ImageOp::LinearLight: ITERATE( LinearLight ); break;
9347  case ImageOp::PinLight: ITERATE( PinLight ); break;
9348  case ImageOp::Exclusion: ITERATE( Exclusion ); break;
9349  break;
9350  default:
9351  break;
9352  }
9353 #undef ITERATE
9354  }
9355 
9356  return *this;
9357  }
9358 
9370  template <class P1>
9371  GenericImage Applied( const GenericImage<P1>& image, image_op op = ImageOp::Mov,
9372  const Point& point = Point( int_max ), int channel = -1,
9373  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9374  {
9375  int c0 = (channel < 0) ? m_channel : channel;
9376  int c1 = c0 + ((firstChannel < 0) ? image.FirstSelectedChannel() : firstChannel);
9377  int c2 = c0 + ((lastChannel < 0) ? image.LastSelectedChannel() : lastChannel);
9378  GenericImage result( *this, rect.MovedTo( point ), c1, c2 );
9379  (void)result.Apply( image, op, Point( 0 ), 0, rect, firstChannel, lastChannel );
9380  return result;
9381  }
9382 
9383  // -------------------------------------------------------------------------
9384 
9418  GenericImage& Apply( const ImageTransformation& transformation,
9419  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 );
9420  // ### Implemented in pcl/ImageTransformation.h (because of mutual dependencies)
9421 
9440  GenericImage Applied( const ImageTransformation& transformation,
9441  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9442  {
9443  GenericImage result( *this, rect, firstChannel, lastChannel );
9444  (void)result.Apply( transformation );
9445  return result;
9446  }
9447 
9469  void Transform( BidirectionalImageTransformation& transform,
9470  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const;
9471  // ### Implemented in pcl/ImageTransformation.h (because of mutual dependencies)
9472 
9473  // -------------------------------------------------------------------------
9474 
9475 #ifndef __PCL_IMAGE_NO_BITMAP
9476 
9518  GenericImage& Blend( const Bitmap& bitmap,
9519  const Point& point = Point( int_max ), const Rect& rect = Rect( 0 ) )
9520  {
9521  Rect r = rect;
9522  if ( r.IsRect() )
9523  r = bitmap.Bounds().Intersection( r );
9524  else
9525  r = bitmap.Bounds();
9526  if ( !r.IsRect() )
9527  return *this;
9528 
9529  Point p = point;
9530  if ( p.x == int_max || p.y == int_max )
9531  p = m_point;
9532 
9533  if ( p.x < 0 )
9534  {
9535  if ( (r.x0 -= p.x) >= r.x1 )
9536  return *this;
9537  p.x = 0;
9538  }
9539  else if ( p.x >= m_width )
9540  return *this;
9541 
9542  if ( p.y < 0 )
9543  {
9544  if ( (r.y0 -= p.y) >= r.y1 )
9545  return *this;
9546  p.y = 0;
9547  }
9548  else if ( p.y >= m_height )
9549  return *this;
9550 
9551  r.ResizeTo( pcl::Min( m_width - p.x, r.Width() ),
9552  pcl::Min( m_height - p.y, r.Height() ) );
9553 
9554  bool hasAlpha = HasAlphaChannels();
9555  int w = r.Width();
9556  int h = r.Height();
9557 
9558  EnsureUnique();
9559 
9560  if ( IsColor() )
9561  {
9562  if ( m_status.IsInitializationEnabled() )
9563  m_status.Initialize( "Blending bitmap", size_type( w )*size_type( h ) );
9564 
9565  sample* fR = 0, * fG = 0, * fB = 0, * fA = 0;
9566 
9567  for ( int i = 0; i < h; ++i, ++p.y, m_status += w )
9568  {
9569  fR = PixelAddress( p, 0 );
9570  fG = PixelAddress( p, 1 );
9571  fB = PixelAddress( p, 2 );
9572  if ( hasAlpha )
9573  fA = PixelAddress( p, 3 );
9574 
9575  const RGBA* g = bitmap.ScanLine( r.y0 + i ) + r.x0;
9576 
9577  for ( int j = 0; j < w; ++j, ++fR, ++fG, ++fB, ++fA, ++g )
9578  {
9579  RGBA rgba = *g;
9580 
9581  uint8 A = Alpha( rgba );
9582 
9583  if ( hasAlpha )
9584  {
9585  P::Mov( *fR, Red( rgba ) );
9586  P::Mov( *fG, Green( rgba ) );
9587  P::Mov( *fB, Blue( rgba ) );
9588  P::Mov( *fA, A );
9589  }
9590  else if ( A != 0 )
9591  {
9592  if ( A == 0xFF )
9593  {
9594  P::Mov( *fR, Red( rgba ) );
9595  P::Mov( *fG, Green( rgba ) );
9596  P::Mov( *fB, Blue( rgba ) );
9597  }
9598  else
9599  {
9600  double k = PTLUT->pDLUTA[A];
9601  double k1 = PTLUT->p1DLUT8[A];
9602  double v;
9603  P::FromSample( v, *fR ), P::Mov( *fR, k*Red( rgba ) + k1*v );
9604  P::FromSample( v, *fG ), P::Mov( *fG, k*Green( rgba ) + k1*v );
9605  P::FromSample( v, *fB ), P::Mov( *fB, k*Blue( rgba ) + k1*v );
9606  }
9607  }
9608  }
9609  }
9610  }
9611  else
9612  {
9613  if ( m_status.IsInitializationEnabled() )
9614  m_status.Initialize( "Blending grayscale bitmap", size_type( w )*size_type( h ) );
9615 
9616  sample* fK = 0, * fA = 0;
9617 
9618  for ( int i = 0; i < h; ++i, ++p.y, m_status += w )
9619  {
9620  fK = PixelAddress( p, 0 );
9621  if ( hasAlpha )
9622  fA = PixelAddress( p, 1 );
9623 
9624  const RGBA* g = bitmap.ScanLine( r.y0 + i ) + r.x0;
9625 
9626  for ( int j = 0; j < w; ++j, ++fK, ++fA, ++g )
9627  {
9628  RGBA rgba = *g;
9629  uint8 R = Red( rgba );
9630  uint8 G = Green( rgba );
9631  uint8 B = Blue( rgba );
9632  uint8 A = Alpha( rgba );
9633 
9634  double K = 0.5*(pcl::Min( pcl::Min( R, G ), B )
9635  + pcl::Max( pcl::Max( R, G ), B ));
9636 
9637  if ( hasAlpha )
9638  {
9639  P::Mov( *fK, K/255 );
9640  P::Mov( *fA, A );
9641  }
9642  else if ( A != 0 )
9643  {
9644  if ( A == 0xFF )
9645  P::Mov( *fK, K/255 );
9646  else
9647  {
9648  double v;
9649  P::FromSample( v, *fK );
9650  P::Mov( *fK, PTLUT->pDLUTA[A]*K + PTLUT->p1DLUT8[A]*v );
9651  }
9652  }
9653  }
9654  }
9655  }
9656 
9657  return *this;
9658  }
9659 
9671  GenericImage Blended( const Bitmap& bitmap,
9672  const Point& point = Point( int_max ), const Rect& rect = Rect( 0 ) ) const
9673  {
9674  GenericImage result( *this, Bounds(), 0, m_numberOfChannels-1 );
9675  (void)result.Blend( bitmap, point, rect );
9676  return result;
9677  }
9678 
9679 #endif // !__PCL_IMAGE_NO_BITMAP
9680 
9681  // -------------------------------------------------------------------------
9682 
9693  template <typename T>
9694  GenericImage& Move( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9695  {
9696  return Apply( scalar, ImageOp::Mov, rect, firstChannel, lastChannel );
9697  }
9698 
9702  template <typename T>
9703  GenericImage& Mov( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9704  {
9705  return Move( scalar, rect, firstChannel, lastChannel );
9706  }
9707 
9718  template <typename T>
9719  GenericImage& Add( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9720  {
9721  return Apply( scalar, ImageOp::Add, rect, firstChannel, lastChannel );
9722  }
9723 
9727  template <typename T>
9728  GenericImage& operator +=( T scalar )
9729  {
9730  return Add( scalar );
9731  }
9732 
9743  template <typename T>
9744  GenericImage Added( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9745  {
9746  GenericImage result( *this, rect, firstChannel, lastChannel );
9747  (void)result.Add( scalar );
9748  return result;
9749  }
9750 
9761  template <typename T>
9762  GenericImage& Subtract( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9763  {
9764  return Apply( scalar, ImageOp::Sub, rect, firstChannel, lastChannel );
9765  }
9766 
9770  template <typename T>
9771  GenericImage& Sub( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9772  {
9773  return Subtract( scalar, rect, firstChannel, lastChannel );
9774  }
9775 
9779  template <typename T>
9780  GenericImage& operator -=( T scalar )
9781  {
9782  return Subtract( scalar );
9783  }
9784 
9795  template <typename T>
9796  GenericImage Subtracted( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9797  {
9798  GenericImage result( *this, rect, firstChannel, lastChannel );
9799  (void)result.Subtract( scalar );
9800  return result;
9801  }
9802 
9813  template <typename T>
9814  GenericImage& Multiply( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9815  {
9816  return Apply( scalar, ImageOp::Mul, rect, firstChannel, lastChannel );
9817  }
9818 
9822  template <typename T>
9823  GenericImage& Mul( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9824  {
9825  return Multiply( scalar, rect, firstChannel, lastChannel );
9826  }
9827 
9831  template <typename T>
9832  GenericImage& operator *=( T scalar )
9833  {
9834  return Multiply( scalar );
9835  }
9836 
9847  template <typename T>
9848  GenericImage Multiplied( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9849  {
9850  GenericImage result( *this, rect, firstChannel, lastChannel );
9851  (void)result.Multiply( scalar );
9852  return result;
9853  }
9854 
9868  template <typename T>
9869  GenericImage& Divide( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9870  {
9871  return Apply( scalar, ImageOp::Div, rect, firstChannel, lastChannel );
9872  }
9873 
9877  template <typename T>
9878  GenericImage& Div( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9879  {
9880  return Divide( scalar, rect, firstChannel, lastChannel );
9881  }
9882 
9886  template <typename T>
9887  GenericImage& operator /=( T scalar )
9888  {
9889  return Divide( scalar );
9890  }
9891 
9905  template <typename T>
9906  GenericImage Divided( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9907  {
9908  GenericImage result( *this, rect, firstChannel, lastChannel );
9909  (void)result.Divide( scalar );
9910  return result;
9911  }
9912 
9923  template <typename T>
9924  GenericImage& Raise( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9925  {
9926  return Apply( scalar, ImageOp::Pow, rect, firstChannel, lastChannel );
9927  }
9928 
9932  template <typename T>
9933  GenericImage& Pow( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9934  {
9935  return Raise( scalar, rect, firstChannel, lastChannel );
9936  }
9937 
9941  template <typename T>
9942  GenericImage& operator ^=( T scalar )
9943  {
9944  return Raise( scalar );
9945  }
9946 
9957  template <typename T>
9958  GenericImage Raised( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
9959  {
9960  GenericImage result( *this, rect, firstChannel, lastChannel );
9961  (void)result.Raise( scalar );
9962  return result;
9963  }
9964 
9976  template <typename T>
9977  GenericImage& SetAbsoluteDifference( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9978  {
9979  return Apply( scalar, ImageOp::Dif, rect, firstChannel, lastChannel );
9980  }
9981 
9985  template <typename T>
9986  GenericImage& Dif( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
9987  {
9988  return SetAbsoluteDifference( scalar, rect, firstChannel, lastChannel );
9989  }
9990 
10002  template <typename T>
10003  GenericImage AbsoluteDifference( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
10004  {
10005  GenericImage result( *this, rect, firstChannel, lastChannel );
10006  (void)result.SetAbsoluteDifference( scalar );
10007  return result;
10008  }
10009 
10020  template <typename T>
10021  GenericImage& SetMinimum( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10022  {
10023  return Apply( scalar, ImageOp::Min, rect, firstChannel, lastChannel );
10024  }
10025 
10029  template <typename T>
10030  GenericImage& Min( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10031  {
10032  return SetMinimum( scalar, rect, firstChannel, lastChannel );
10033  }
10034 
10046  template <typename T>
10047  GenericImage Minimum( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
10048  {
10049  GenericImage result( *this, rect, firstChannel, lastChannel );
10050  (void)result.SetMinimum( scalar );
10051  return result;
10052  }
10053 
10064  template <typename T>
10065  GenericImage& SetMaximum( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10066  {
10067  return Apply( scalar, ImageOp::Max, rect, firstChannel, lastChannel );
10068  }
10069 
10073  template <typename T>
10074  GenericImage& Max( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10075  {
10076  return SetMaximum( scalar, rect, firstChannel, lastChannel );
10077  }
10078 
10090  template <typename T>
10091  GenericImage Maximum( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 ) const
10092  {
10093  GenericImage result( *this, rect, firstChannel, lastChannel );
10094  (void)result.SetMaximum( scalar );
10095  return result;
10096  }
10097 
10109  template <typename T>
10110  GenericImage& Or( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10111  {
10112  return Apply( scalar, ImageOp::Or, rect, firstChannel, lastChannel );
10113  }
10114 
10126  template <typename T>
10127  GenericImage& And( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10128  {
10129  return Apply( scalar, ImageOp::And, rect, firstChannel, lastChannel );
10130  }
10131 
10143  template <typename T>
10144  GenericImage& Xor( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10145  {
10146  return Apply( scalar, ImageOp::Xor, rect, firstChannel, lastChannel );
10147  }
10148 
10160  template <typename T>
10161  GenericImage& Nor( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10162  {
10163  return Apply( scalar, ImageOp::Nor, rect, firstChannel, lastChannel );
10164  }
10165 
10177  template <typename T>
10178  GenericImage& Nand( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10179  {
10180  return Apply( scalar, ImageOp::Nand, rect, firstChannel, lastChannel );
10181  }
10182 
10194  template <typename T>
10195  GenericImage& Xnor( T scalar, const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10196  {
10197  return Apply( scalar, ImageOp::Xnor, rect, firstChannel, lastChannel );
10198  }
10199 
10200  // -------------------------------------------------------------------------
10201 
10212  template <class P1>
10214  const Point& point = Point( int_max ), int channel = -1,
10215  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10216  {
10217  return Apply( image, ImageOp::Mov, point, channel, rect, firstChannel, lastChannel );
10218  }
10219 
10223  template <class P1>
10225  const Point& point = Point( int_max ), int channel = -1,
10226  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10227  {
10228  return Move( image, point, channel, rect, firstChannel, lastChannel );
10229  }
10230 
10241  template <class P1>
10243  const Point& point = Point( int_max ), int channel = -1,
10244  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10245  {
10246  return Apply( image, ImageOp::Add, point, channel, rect, firstChannel, lastChannel );
10247  }
10248 
10252  template <class P1>
10253  GenericImage& operator +=( const GenericImage<P1>& image )
10254  {
10255  return Add( image );
10256  }
10257 
10268  template <class P1>
10270  const Point& point = Point( int_max ), int channel = -1,
10271  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10272  {
10273  return Apply( image, ImageOp::Sub, point, channel, rect, firstChannel, lastChannel );
10274  }
10275 
10279  template <class P1>
10281  const Point& point = Point( int_max ), int channel = -1,
10282  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10283  {
10284  return Subtract( image, point, channel, rect, firstChannel, lastChannel );
10285  }
10286 
10290  template <class P1>
10291  GenericImage& operator -=( const GenericImage<P1>& image )
10292  {
10293  return Subtract( image );
10294  }
10295 
10306  template <class P1>
10308  const Point& point = Point( int_max ), int channel = -1,
10309  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10310  {
10311  return Apply( image, ImageOp::Mul, point, channel, rect, firstChannel, lastChannel );
10312  }
10313 
10317  template <class P1>
10319  const Point& point = Point( int_max ), int channel = -1,
10320  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10321  {
10322  return Multiply( image, point, channel, rect, firstChannel, lastChannel );
10323  }
10324 
10328  template <class P1>
10329  GenericImage& operator *=( const GenericImage<P1>& image )
10330  {
10331  return Multiply( image );
10332  }
10333 
10348  template <class P1>
10350  const Point& point = Point( int_max ), int channel = -1,
10351  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10352  {
10353  return Apply( image, ImageOp::Div, point, channel, rect, firstChannel, lastChannel );
10354  }
10355 
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 Divide( image, point, channel, rect, firstChannel, lastChannel );
10365  }
10366 
10370  template <class P1>
10371  GenericImage& operator /=( const GenericImage<P1>& image )
10372  {
10373  return Divide( image );
10374  }
10375 
10387  template <class P1>
10389  const Point& point = Point( int_max ), int channel = -1,
10390  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10391  {
10392  return Apply( image, ImageOp::Pow, point, channel, rect, firstChannel, lastChannel );
10393  }
10394 
10398  template <class P1>
10400  const Point& point = Point( int_max ), int channel = -1,
10401  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10402  {
10403  return Raise( image, point, channel, rect, firstChannel, lastChannel );
10404  }
10405 
10409  template <class P1>
10410  GenericImage& operator ^=( const GenericImage<P1>& image )
10411  {
10412  return Raise( image );
10413  }
10414 
10426  template <class P1>
10428  const Point& point = Point( int_max ), int channel = -1,
10429  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10430  {
10431  return Apply( image, ImageOp::Dif, point, channel, rect, firstChannel, lastChannel );
10432  }
10433 
10437  template <class P1>
10439  const Point& point = Point( int_max ), int channel = -1,
10440  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10441  {
10442  return SetAbsoluteDifference( image, point, channel, rect, firstChannel, lastChannel );
10443  }
10444 
10456  template <class P1>
10458  const Point& point = Point( int_max ), int channel = -1,
10459  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10460  {
10461  return Apply( image, ImageOp::Min, point, channel, rect, firstChannel, lastChannel );
10462  }
10463 
10467  template <class P1>
10469  const Point& point = Point( int_max ), int channel = -1,
10470  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10471  {
10472  return SetMinimum( image, point, channel, rect, firstChannel, lastChannel );
10473  }
10474 
10486  template <class P1>
10488  const Point& point = Point( int_max ), int channel = -1,
10489  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10490  {
10491  return Apply( image, ImageOp::Max, point, channel, rect, firstChannel, lastChannel );
10492  }
10493 
10497  template <class P1>
10499  const Point& point = Point( int_max ), int channel = -1,
10500  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10501  {
10502  return SetMaximum( image, point, channel, rect, firstChannel, lastChannel );
10503  }
10504 
10516  template <class P1>
10518  const Point& point = Point( int_max ), int channel = -1,
10519  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10520  {
10521  return Apply( image, ImageOp::Or, point, channel, rect, firstChannel, lastChannel );
10522  }
10523 
10535  template <class P1>
10537  const Point& point = Point( int_max ), int channel = -1,
10538  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10539  {
10540  return Apply( image, ImageOp::And, point, channel, rect, firstChannel, lastChannel );
10541  }
10542 
10554  template <class P1>
10556  const Point& point = Point( int_max ), int channel = -1,
10557  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10558  {
10559  return Apply( image, ImageOp::Xor, point, channel, rect, firstChannel, lastChannel );
10560  }
10561 
10573  template <class P1>
10575  const Point& point = Point( int_max ), int channel = -1,
10576  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10577  {
10578  return Apply( image, ImageOp::Nor, point, channel, rect, firstChannel, lastChannel );
10579  }
10580 
10592  template <class P1>
10594  const Point& point = Point( int_max ), int channel = -1,
10595  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10596  {
10597  return Apply( image, ImageOp::Nand, point, channel, rect, firstChannel, lastChannel );
10598  }
10599 
10611  template <class P1>
10613  const Point& point = Point( int_max ), int channel = -1,
10614  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10615  {
10616  return Apply( image, ImageOp::Xnor, point, channel, rect, firstChannel, lastChannel );
10617  }
10618 
10619  // -------------------------------------------------------------------------
10620 
10658  template <class P1>
10660  const Point& point = Point( int_max ), int channel = -1,
10661  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10662  {
10663  Rect r = rect;
10664  if ( !image.ParseSelection( r, firstChannel, lastChannel ) )
10665  return *this;
10666 
10667  if ( !ParseChannel( channel ) )
10668  return *this;
10669 
10670  Point p = point;
10671  if ( p.x == int_max || p.y == int_max )
10672  p = m_point;
10673 
10674  if ( p.x < 0 )
10675  {
10676  if ( (r.x0 -= p.x) >= r.x1 )
10677  return *this;
10678  p.x = 0;
10679  }
10680  else if ( p.x >= m_width )
10681  return *this;
10682 
10683  if ( p.y < 0 )
10684  {
10685  if ( (r.y0 -= p.y) >= r.y1 )
10686  return *this;
10687  p.y = 0;
10688  }
10689  else if ( p.y >= m_height )
10690  return *this;
10691 
10692  r.ResizeTo( pcl::Min( m_width - p.x, r.Width() ),
10693  pcl::Min( m_height - p.y, r.Height() ) );
10694 
10695  lastChannel = pcl::Min( lastChannel, firstChannel + m_numberOfChannels - channel - 1 );
10696 
10697  EnsureUnique();
10698  image.EnsureUnique();
10699 
10700  size_type N = size_type( r.Width() )*size_type( r.Height() );
10701  if ( m_status.IsInitializationEnabled() )
10702  m_status.Initialize( "Exchanging pixel samples", N*(1 + lastChannel - firstChannel) );
10703 
10704  if ( r == Bounds() && r == image.Bounds() )
10705  for ( int i = channel, j = firstChannel; j <= lastChannel; ++i, ++j, m_status += N )
10706  {
10707  sample* f = m_pixelData[i];
10708  typename P1::sample* g = image[j];
10709  for ( sample* f1 = f+N; f < f1; ++f, ++g )
10710  {
10711  sample t = *f;
10712  P1::FromSample( *f, *g );
10713  P::FromSample( *g, t );
10714  }
10715  }
10716  else
10717  for ( int i = channel, j = firstChannel, w = r.Width(), h = r.Height(); j <= lastChannel; ++i, ++j, m_status += N )
10718  {
10719  sample* f = PixelAddress( p, i );
10720  typename P1::sample* g = image.PixelAddress( r.LeftTop(), j );
10721  for ( int k = 0; k < h; ++k, f += m_width-w, g += image.Width()-w )
10722  for ( sample* f1 = f+w; f < f1; ++f, ++g )
10723  {
10724  sample t = *f;
10725  P1::FromSample( *f, *g );
10726  P::FromSample( *g, t );
10727  }
10728  }
10729 
10730  return *this;
10731  }
10732 
10736  template <class P1>
10738  const Point& point = Point( int_max ), int channel = -1,
10739  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1 )
10740  {
10741  return Exchange( image, point, channel, rect, firstChannel, lastChannel );
10742  }
10743 
10744  // -------------------------------------------------------------------------
10745 
10765  sample MinimumSampleValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
10766  int maxProcessors = 0 ) const
10767  {
10768  Rect r = rect;
10769  if ( !ParseSelection( r, firstChannel, lastChannel ) )
10770  return 0;
10771 
10772  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
10773  if ( m_status.IsInitializationEnabled() )
10774  m_status.Initialize( "Computing minimum sample value", N );
10775 
10776  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
10777  bool useAffinity = m_parallel && Thread::IsRootThread();
10778  ReferenceArray<MinThread> threads;
10779  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
10780  threads.Add( new MinThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
10781  if ( threads.Length() > 1 )
10782  {
10783  int n = 0;
10784  for ( MinThread& thread : threads )
10785  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
10786  for ( MinThread& thread : threads )
10787  thread.Wait();
10788  }
10789  else
10790  threads[0].Run();
10791 
10792  sample min = P::MinSampleValue();
10793  bool initialized = false;
10794  for ( const MinThread& thread : threads )
10795  if ( thread.initialized )
10796  if ( initialized )
10797  {
10798  if ( thread.min < min )
10799  min = thread.min;
10800  }
10801  else
10802  {
10803  min = thread.min;
10804  initialized = true;
10805  }
10806 
10807  threads.Destroy();
10808  m_status += N;
10809  return min;
10810  }
10811 
10817  sample MinimumPixelValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
10818  int maxProcessors = 0 ) const
10819  {
10820  return MinimumSampleValue( rect, firstChannel, lastChannel, maxProcessors );
10821  }
10822 
10842  sample MaximumSampleValue( const Rect& rect = Rect( 0 ),
10843  int firstChannel = -1, int lastChannel = -1, int maxProcessors = 0 ) const
10844  {
10845  Rect r = rect;
10846  if ( !ParseSelection( r, firstChannel, lastChannel ) )
10847  return 0;
10848 
10849  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
10850  if ( m_status.IsInitializationEnabled() )
10851  m_status.Initialize( "Computing maximum sample value", N );
10852 
10853  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
10854  bool useAffinity = m_parallel && Thread::IsRootThread();
10855  ReferenceArray<MaxThread> threads;
10856  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
10857  threads.Add( new MaxThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
10858  if ( threads.Length() > 1 )
10859  {
10860  int n = 0;
10861  for ( MaxThread& thread : threads )
10862  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
10863  for ( MaxThread& thread : threads )
10864  thread.Wait();
10865  }
10866  else
10867  threads[0].Run();
10868 
10869  sample max = P::MinSampleValue();
10870  bool initialized = false;
10871  for ( const MaxThread& thread : threads )
10872  if ( thread.initialized )
10873  if ( initialized )
10874  {
10875  if ( max < thread.max )
10876  max = thread.max;
10877  }
10878  else
10879  {
10880  max = thread.max;
10881  initialized = true;
10882  }
10883 
10884  threads.Destroy();
10885  m_status += N;
10886  return max;
10887  }
10888 
10894  sample MaximumPixelValue( const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
10895  int maxProcessors = 0 ) const
10896  {
10897  return MaximumSampleValue( rect, firstChannel, lastChannel, maxProcessors );
10898  }
10899 
10926  template <typename T>
10927  void GetExtremeSampleValues( T& min, T& max,
10928  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
10929  int maxProcessors = 0 ) const
10930  {
10931  Rect r = rect;
10932  if ( !ParseSelection( r, firstChannel, lastChannel ) )
10933  {
10934  // ### Required for compatibility with PCL 1.x
10935  P::FromSample( min, P::MinSampleValue() );
10936  max = min;
10937  return;
10938  }
10939 
10940  size_type N = size_type( r.Width() )*size_type( r.Height() )*(1 + lastChannel - firstChannel);
10941  if ( m_status.IsInitializationEnabled() )
10942  m_status.Initialize( "Computing extreme sample values", N );
10943 
10944  Array<size_type> L = OptimalThreadRows( r.Height(), r.Width(), maxProcessors );
10945  bool useAffinity = m_parallel && Thread::IsRootThread();
10947  for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
10948  threads.Add( new MinMaxThread( *this, r, firstChannel, lastChannel, n, n + int( L[i] ) ) );
10949  if ( threads.Length() > 1 )
10950  {
10951  int n = 0;
10952  for ( MinMaxThread& thread : threads )
10953  thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
10954  for ( MinMaxThread& thread : threads )
10955  thread.Wait();
10956  }
10957  else
10958  threads[0].Run();
10959 
10960  sample vmin = P::MinSampleValue();
10961  sample vmax = P::MinSampleValue();
10962  bool initialized = false;
10963  for ( const MinMaxThread& thread : threads )
10964  if ( thread.initialized )
10965  if ( initialized )
10966  {
10967  if ( thread.min < vmin )
10968  vmin = thread.min;
10969  if ( vmax < thread.max )
10970  vmax = thread.max;
10971  }
10972  else
10973  {
10974  vmin = thread.min;
10975  vmax = thread.max;
10976  initialized = true;
10977  }
10978 
10979  threads.Destroy();
10980  m_status += N;
10981  P::FromSample( min, vmin );
10982  P::FromSample( max, vmax );
10983  }
10984 
10990  void GetExtremePixelValues( sample& min, sample& max,
10991  const Rect& rect = Rect( 0 ), int firstChannel = -1, int lastChannel = -1,
10992  int maxProcessors = 0 ) const
10993  {
10994  GetExtremeSampleValues( min, max, rect, firstChannel, lastChannel, maxProcessors );
10995  }
10996 
11023  sample LocateMi