58 #include <pcl/Diagnostics.h>
71 #ifndef __PCL_IMAGE_NO_BITMAP
72 # ifdef __PCL_BUILDING_PIXINSIGHT_APPLICATION
73 # ifndef __PI_Bitmap_h
74 # include <API/Bitmap.h>
78 # ifndef __PCL_Bitmap_h
82 # ifndef __PCL_Color_h
87 #ifdef __PCL_BUILDING_PIXINSIGHT_APPLICATION
176 return op >= Add && op <= Dif;
185 return op >= Or && op <= Xnor;
194 return op == Mov || op == Min || op == Max;
203 return op >= ColorBurn && op <= Exclusion;
214 #define m_pixelData m_data->data
215 #define m_channelData( c ) reinterpret_cast<sample*>( PCL_ASSUME_ALIGNED_32( m_pixelData[c] ) )
216 #define m_allocator m_data->allocator
218 #define m_width m_geometry->width
219 #define m_height m_geometry->height
220 #define m_numberOfChannels m_geometry->numberOfChannels
222 #define m_colorSpace m_color->colorSpace
223 #define m_RGBWS m_color->RGBWS
225 #define m_channel m_selected.channel
226 #define m_lastChannel m_selected.lastChannel
227 #define m_point m_selected.point
228 #define m_rectangle m_selected.rectangle
229 #define m_clipLow m_selected.clipLow
230 #define m_clipHigh m_selected.clipHigh
231 #define m_clippedLow m_selected.clippedLow
232 #define m_clippedHigh m_selected.clippedHigh
236 class PCL_CLASS ImageVariant;
237 class PCL_CLASS ImageTransformation;
238 class PCL_CLASS BidirectionalImageTransformation;
312 using color_space = AbstractImage::color_space;
325 using image_op = ImageOp::value_type;
394 m_image->EnsureUnique();
395 if ( m_image->ParseChannel( channel ) )
397 m_iterator = (*m_image)[channel];
398 m_end = m_iterator + m_image->NumberOfPixels();
441 return m_image !=
nullptr && m_iterator !=
nullptr;
467 operator bool() const noexcept
469 return m_iterator < m_end;
595 return i.m_iterator - j.m_iterator;
604 return i.m_iterator - j;
613 return i - j.m_iterator;
622 return i.m_iterator == j.m_iterator;
631 return i.m_iterator == j;
640 return i == j.m_iterator;
649 return i.m_iterator < j.m_iterator;
657 return i.m_iterator < j;
665 return i < j.m_iterator;
670 image_type* m_image =
nullptr;
671 sample* __restrict__ m_iterator =
nullptr;
672 const sample* __restrict__ m_end =
nullptr;
728 if ( m_image->ParseChannel( channel ) )
730 m_iterator = (*m_image)[channel];
731 m_end = m_iterator + m_image->NumberOfPixels();
766 : m_image( i.m_image )
767 , m_iterator( i.m_iterator )
784 m_iterator = i.m_iterator;
800 return m_image !=
nullptr && m_iterator !=
nullptr;
828 operator bool() const noexcept
830 return m_iterator < m_end;
956 return i.m_iterator - j.m_iterator;
965 return i.m_iterator - j;
974 return i - j.m_iterator;
983 return i.m_iterator == j.m_iterator;
992 return i.m_iterator == j;
1001 return i == j.m_iterator;
1010 return i.m_iterator < j.m_iterator;
1018 return i.m_iterator < j;
1026 return i < j.m_iterator;
1031 const image_type* m_image =
nullptr;
1032 const sample* __restrict__ m_iterator =
nullptr;
1033 const sample* __restrict__ m_end =
nullptr;
1038 template <
class image_type,
class sample_po
inter>
1039 class roi_sample_iterator_base
1043 image_type* m_image =
nullptr;
1044 sample_pointer m_iterator =
nullptr;
1045 sample_pointer m_rowBegin =
nullptr;
1046 sample_pointer m_rowEnd =
nullptr;
1047 sample_pointer m_end =
nullptr;
1049 roi_sample_iterator_base() =
default;
1051 roi_sample_iterator_base( image_type& image,
const Rect& rect,
int channel )
1055 if ( m_image->ParseRect( r ) )
1057 if ( m_image->ParseChannel( channel ) )
1059 m_iterator = m_rowBegin = m_image->PixelAddress( r.
x0, r.
y0, channel );
1060 m_rowEnd = m_rowBegin + r.
Width();
1061 m_end = m_rowEnd + ((r.
Height() - 1)*m_image->Width());
1066 roi_sample_iterator_base( image_type& image, sample_pointer i, sample_pointer j )
1071 m_iterator = m_rowBegin = i;
1072 m_rowEnd = m_rowBegin + (j - i)%m_image->Width();
1076 roi_sample_iterator_base(
const roi_sample_iterator_base& i ) =
default;
1078 roi_sample_iterator_base& operator =(
const roi_sample_iterator_base& ) =
default;
1080 void Increment() noexcept
1082 if ( ++m_iterator == m_rowEnd )
1084 m_rowBegin += m_image->Width();
1085 m_rowEnd += m_image->Width();
1086 m_iterator = m_rowBegin;
1090 void Decrement() noexcept
1092 if ( m_iterator == m_rowBegin )
1094 m_rowBegin -= m_image->Width();
1095 m_rowEnd -= m_image->Width();
1096 m_iterator = m_rowEnd;
1101 void MoveBy(
int cols,
int rows ) noexcept
1103 cols += m_iterator - m_rowBegin;
1106 int w = m_rowEnd - m_rowBegin;
1113 int dy = rows * m_image->Width();
1116 m_iterator = m_rowBegin + cols;
1151 using iterator_base = roi_sample_iterator_base<GenericImage<P>,
sample*>;
1181 : iterator_base( image.EnsureUnique(), rect, channel )
1202 : iterator_base( image, i, j )
1222 return this->m_image !=
nullptr && this->m_iterator !=
nullptr;
1230 return *this->m_image;
1238 return this->m_iterator;
1247 operator bool() const noexcept
1249 return this->m_iterator < this->m_end;
1258 return *this->m_iterator;
1318 int w = this->m_rowEnd - this->m_rowBegin;
1319 iterator_base::MoveBy( delta%w, delta/w );
1334 int w = this->m_rowEnd - this->m_rowBegin;
1335 iterator_base::MoveBy( -delta%w, -delta/w );
1349 iterator_base::MoveBy( dx, dy );
1392 return i.m_iterator == j.m_iterator;
1401 return i.m_iterator == j;
1410 return i == j.m_iterator;
1419 return i.m_iterator < j.m_iterator;
1427 return i.m_iterator < j;
1435 return i < j.m_iterator;
1472 using iterator_base = roi_sample_iterator_base<const GenericImage<P>,
const sample*>;
1502 : iterator_base( image, rect, channel )
1523 : iterator_base( image, i, j )
1536 : iterator_base( i.m_image, i.m_rowBegin, i.m_end )
1551 this->m_image = i.m_image;
1552 this->m_iterator = i.m_iterator;
1553 this->m_rowBegin = i.m_rowBegin;
1554 this->m_rowEnd = i.m_rowEnd;
1555 this->m_end = i.m_end;
1570 return this->m_image !=
nullptr && this->m_iterator !=
nullptr;
1579 return *this->m_image;
1588 return this->m_iterator;
1597 operator bool() const noexcept
1599 return this->m_iterator < this->m_end;
1608 return *this->m_iterator;
1668 int w = this->m_rowEnd - this->m_rowBegin;
1669 iterator_base::MoveBy( delta%w, delta/w );
1684 int w = this->m_rowEnd - this->m_rowBegin;
1685 iterator_base::MoveBy( -delta%w, -delta/w );
1699 iterator_base::MoveBy( dx, dy );
1742 return i.m_iterator == j.m_iterator;
1751 return i.m_iterator == j;
1760 return i == j.m_iterator;
1769 return i.m_iterator < j.m_iterator;
1777 return i.m_iterator < j;
1785 return i < j.m_iterator;
1791 template <
class image_type,
class iterator_base,
class sample_po
inter,
class filter_type>
1792 class filter_sample_iterator_base :
public iterator_base
1796 filter_type m_filter;
1797 sample_pointer m_begin =
nullptr;
1799 filter_sample_iterator_base() =
default;
1801 filter_sample_iterator_base( image_type& image,
const filter_type& filter,
int channel )
1802 : iterator_base( image, channel )
1803 , m_filter( filter )
1804 , m_begin( iterator_base::m_iterator )
1806 JumpToNextValidSample();
1809 filter_sample_iterator_base( image_type& image,
const filter_type& filter, sample_pointer i, sample_pointer j )
1810 : iterator_base( image, i, j )
1811 , m_filter( filter )
1812 , m_begin( iterator_base::m_iterator )
1814 JumpToNextValidSample();
1817 filter_sample_iterator_base(
const iterator_base& i,
const filter_type& filter )
1818 : iterator_base( i )
1819 , m_filter( filter )
1820 , m_begin( iterator_base::m_iterator )
1822 JumpToNextValidSample();
1825 filter_sample_iterator_base(
const filter_sample_iterator_base& ) =
default;
1827 filter_sample_iterator_base& operator =(
const filter_sample_iterator_base& ) =
default;
1829 filter_sample_iterator_base& operator =(
const iterator_base& i ) noexcept
1831 (void)iterator_base::operator =( i );
1832 JumpToNextValidSample();
1836 void JumpToNextValidSample() noexcept
1838 while ( this->m_iterator < this->m_end && !this->m_filter( *this->m_iterator ) )
1842 void JumpToPrevValidSample() noexcept
1844 while ( this->m_iterator > this->m_begin && !this->m_filter( *this->m_iterator ) )
1886 public filter_sample_iterator_base<GenericImage<P>, sample_iterator, sample*, F>
1935 : iterator_base( image.EnsureUnique(), filter, channel )
1958 : iterator_base( image, filter, i, j )
1967 : iterator_base( i, filter )
1987 (void)iterator_base::operator =( i );
1997 return this->m_image !=
nullptr && this->m_iterator !=
nullptr;
2005 return *this->m_image;
2014 return this->m_filter;
2023 return this->m_filter;
2031 return this->m_iterator;
2041 operator bool() const noexcept
2043 return this->m_iterator < this->m_end;
2052 return *this->m_iterator;
2063 this->JumpToNextValidSample();
2074 sample* __restrict__ i0 = this->m_iterator++;
2075 this->JumpToNextValidSample();
2087 this->JumpToPrevValidSample();
2098 sample* __restrict__ i0 = this->m_iterator--;
2099 this->JumpToPrevValidSample();
2112 this->m_iterator += delta;
2113 this->JumpToNextValidSample();
2126 this->m_iterator -= delta;
2127 this->JumpToPrevValidSample();
2141 this->m_iterator += d;
2143 this->JumpToNextValidSample();
2145 this->JumpToPrevValidSample();
2182 return i.m_iterator - j.m_iterator;
2191 return i.m_iterator == j.m_iterator;
2200 return i.m_iterator == j;
2209 return i == j.m_iterator;
2218 return i.m_iterator < j.m_iterator;
2226 return i.m_iterator < j;
2234 return i < j.m_iterator;
2275 public filter_sample_iterator_base<const GenericImage<P>, const_sample_iterator, const sample*, F>
2324 : iterator_base( image, filter, channel )
2347 : iterator_base( image, filter, i, j )
2356 : iterator_base( i.m_image, filter, i.m_iterator, i.m_end )
2365 : iterator_base( i, filter )
2374 : iterator_base( i )
2394 (void)const_sample_iterator::operator =( i );
2395 this->JumpToNextValidSample();
2405 (void)iterator_base::operator =( i );
2415 return this->m_image !=
nullptr && this->m_iterator !=
nullptr;
2424 return *this->m_image;
2433 return this->m_filter;
2442 return this->m_filter;
2451 return this->m_iterator;
2461 operator bool() const noexcept
2463 return this->m_iterator < this->m_end;
2472 return *this->m_iterator;
2483 this->JumpToNextValidSample();
2494 sample* __restrict__ i0 = this->m_iterator++;
2495 this->JumpToNextValidSample();
2507 this->JumpToPrevValidSample();
2518 sample* __restrict__ i0 = this->m_iterator--;
2519 this->JumpToPrevValidSample();
2532 this->m_iterator += delta;
2533 this->JumpToNextValidSample();
2546 this->m_iterator -= delta;
2547 this->JumpToPrevValidSample();
2561 this->m_iterator += d;
2563 this->JumpToNextValidSample();
2565 this->JumpToPrevValidSample();
2602 return i.m_iterator - j.m_iterator;
2611 return i.m_iterator == j.m_iterator;
2620 return i.m_iterator == j;
2629 return i == j.m_iterator;
2638 return i.m_iterator < j.m_iterator;
2646 return i.m_iterator < j;
2654 return i < j.m_iterator;
2660 template <
class image_type,
class sample_po
inter,
class filter_type>
2661 class roi_filter_sample_iterator_base :
public roi_sample_iterator_base<image_type, sample_pointer>
2665 using roi_iterator_base = roi_sample_iterator_base<image_type, sample_pointer>;
2667 filter_type m_filter;
2668 sample_pointer m_begin =
nullptr;
2670 roi_filter_sample_iterator_base() =
default;
2672 roi_filter_sample_iterator_base( image_type& image,
const filter_type& filter,
const Rect& rect,
int channel )
2673 : roi_iterator_base( image, rect, channel )
2674 , m_filter( filter )
2675 , m_begin( roi_iterator_base::m_iterator )
2677 JumpToNextValidSample();
2680 roi_filter_sample_iterator_base( image_type& image,
const filter_type& filter, sample_pointer i, sample_pointer j )
2681 : roi_iterator_base( image, i, j )
2682 , m_filter( filter )
2683 , m_begin( roi_iterator_base::m_iterator )
2685 JumpToNextValidSample();
2688 roi_filter_sample_iterator_base(
const roi_iterator_base& i,
const filter_type& filter )
2689 : roi_iterator_base( i )
2690 , m_filter( filter )
2691 , m_begin( roi_iterator_base::m_iterator )
2693 JumpToNextValidSample();
2696 roi_filter_sample_iterator_base(
const roi_filter_sample_iterator_base& ) =
default;
2698 roi_filter_sample_iterator_base& operator =(
const roi_filter_sample_iterator_base& i ) =
default;
2700 roi_filter_sample_iterator_base& operator =(
const roi_iterator_base& i ) noexcept
2702 (void)roi_iterator_base::operator =( i );
2703 JumpToNextValidSample();
2707 void JumpToNextValidSample() noexcept
2709 while ( this->m_iterator < this->m_end && !this->m_filter( *this->m_iterator ) )
2710 roi_iterator_base::Increment();
2713 void JumpToPrevValidSample() noexcept
2715 while ( this->m_iterator > this->m_begin && !this->m_filter( *this->m_iterator ) )
2716 roi_iterator_base::Decrement();
2758 using iterator_base = roi_filter_sample_iterator_base<GenericImage<P>,
sample*, F>;
2791 : iterator_base( image.EnsureUnique(), filter, rect, channel )
2814 : iterator_base( image, filter, i, j )
2823 : iterator_base( i, filter )
2843 (void)iterator_base::operator =( i );
2853 return this->m_image !=
nullptr && this->m_iterator !=
nullptr;
2861 return *this->m_image;
2870 return this->m_filter;
2879 return this->m_filter;
2887 return this->m_iterator;
2896 operator bool() const noexcept
2898 return this->m_iterator < this->m_end;
2907 return *this->m_iterator;
2918 this->JumpToNextValidSample();
2931 this->JumpToNextValidSample();
2943 this->JumpToPrevValidSample();
2956 this->JumpToPrevValidSample();
2971 int w = this->m_rowEnd - this->m_rowBegin;
2972 return MoveBy( delta%w, delta/w );
2986 int w = this->m_rowEnd - this->m_rowBegin;
2987 return MoveBy( -delta%w, -delta/w );
3000 sample* __restrict__ i0 = this->m_iterator;
3001 iterator_base::MoveBy( dx, dy );
3002 if ( this->m_iterator >= i0 )
3003 this->JumpToNextValidSample();
3005 this->JumpToPrevValidSample();
3048 return i.m_iterator == j.m_iterator;
3057 return i.m_iterator == j;
3066 return i == j.m_iterator;
3075 return i.m_iterator < j.m_iterator;
3083 return i.m_iterator < j;
3091 return i < j.m_iterator;
3133 using iterator_base = roi_filter_sample_iterator_base<const GenericImage<P>,
const sample*, F>;
3166 : iterator_base( image, filter, rect, channel )
3189 : iterator_base( image, filter, i, j )
3198 : iterator_base( i, filter )
3218 (void)iterator_base::operator =( i );
3228 return this->m_image !=
nullptr && this->m_iterator !=
nullptr;
3237 return *this->m_image;
3246 return this->m_filter;
3255 return this->m_filter;
3264 return this->m_iterator;
3273 operator bool() const noexcept
3275 return this->m_iterator < this->m_end;
3284 return *this->m_iterator;
3295 this->JumpToNextValidSample();
3308 this->JumpToNextValidSample();
3320 this->JumpToPrevValidSample();
3333 this->JumpToPrevValidSample();
3348 int w = this->m_rowEnd - this->m_rowBegin;
3349 return MoveBy( delta%w, delta/w );
3363 int w = this->m_rowEnd - this->m_rowBegin;
3364 return MoveBy( -delta%w, -delta/w );
3377 const sample* __restrict__ i0 = this->m_iterator;
3378 iterator_base::MoveBy( dx, dy );
3379 if ( this->m_iterator >= i0 )
3380 this->JumpToNextValidSample();
3382 this->JumpToPrevValidSample();
3425 return i.m_iterator == j.m_iterator;
3434 return i.m_iterator == j;
3443 return i == j.m_iterator;
3452 return i.m_iterator < j.m_iterator;
3460 return i.m_iterator < j;
3468 return i < j.m_iterator;
3515 m_image->EnsureUnique();
3516 if ( !m_image->IsEmpty() )
3519 for (
int i = 0; i < m_iterator.Length(); ++i )
3520 m_iterator[i] = (*m_image)[i];
3521 m_end = m_iterator[0] + m_image->NumberOfPixels();
3541 return m_image !=
nullptr && !m_iterator.IsEmpty();
3558 return m_iterator[channel];
3566 operator bool() const noexcept
3568 return m_iterator[0] < m_end;
3575 sample& operator [](
int channel )
const noexcept
3577 return *m_iterator[channel];
3586 for (
int i = 0; i < m_iterator.Length(); ++i )
3599 for (
int i = 0; i < m_iterator.Length(); ++i )
3610 for (
int i = 0; i < m_iterator.Length(); ++i )
3623 for (
int i = 0; i < m_iterator.Length(); ++i )
3637 for (
int i = 0; i < m_iterator.Length(); ++i )
3638 m_iterator[i] += delta;
3651 for (
int i = 0; i < m_iterator.Length(); ++i )
3652 m_iterator[i] -= delta;
3707 return i.m_iterator[0] - j.m_iterator[0];
3716 return i.m_iterator[0] == j.m_iterator[0];
3725 return i.m_iterator[0] < j.m_iterator[0];
3730 image_type* m_image =
nullptr;
3731 iterator_type m_iterator;
3732 const sample* __restrict__ m_end =
nullptr;
3778 if ( !m_image->IsEmpty() )
3781 for (
int i = 0; i < m_iterator.Length(); ++i )
3782 m_iterator[i] = (*m_image)[i];
3783 m_end = m_iterator[0] + m_image->NumberOfPixels();
3803 return m_image !=
nullptr && !m_iterator.IsEmpty();
3821 return m_iterator[channel];
3829 operator bool() const noexcept
3831 return m_iterator[0] < m_end;
3838 const sample& operator [](
int channel )
const noexcept
3840 return *m_iterator[channel];
3849 for (
int i = 0; i < m_iterator.Length(); ++i )
3862 for (
int i = 0; i < m_iterator.Length(); ++i )
3873 for (
int i = 0; i < m_iterator.Length(); ++i )
3886 for (
int i = 0; i < m_iterator.Length(); ++i )
3900 for (
int i = 0; i < m_iterator.Length(); ++i )
3901 m_iterator[i] += delta;
3914 for (
int i = 0; i < m_iterator.Length(); ++i )
3915 m_iterator[i] -= delta;
3970 return i.m_iterator[0] - j.m_iterator[0];
3979 return i.m_iterator[0] == j.m_iterator[0];
3988 return i.m_iterator[0] < j.m_iterator[0];
3993 const image_type* m_image =
nullptr;
3994 iterator_type m_iterator;
3995 const sample* __restrict__ m_end =
nullptr;
4000 template <
class image_type,
class sample_po
inter>
4001 class roi_pixel_iterator_base
4007 image_type* m_image =
nullptr;
4008 iterator_type m_iterator;
4009 sample_pointer m_rowBegin =
nullptr;
4010 sample_pointer m_rowEnd =
nullptr;
4011 sample_pointer m_end =
nullptr;
4013 roi_pixel_iterator_base() =
default;
4015 roi_pixel_iterator_base( image_type& image,
const Rect& rect )
4019 if ( m_image->ParseRect( r ) )
4021 m_iterator = iterator_type( m_image->NumberOfChannels() );
4022 for (
int i = 0; i < m_iterator.Length(); ++i )
4023 m_iterator[i] = m_image->PixelAddress( r.
x0, r.
y0, i );
4024 m_rowBegin = m_iterator[0];
4025 m_rowEnd = m_rowBegin + r.
Width();
4026 m_end = m_rowEnd + ((r.
Height() - 1)*m_image->Width());
4030 roi_pixel_iterator_base(
const roi_pixel_iterator_base& ) =
default;
4032 roi_pixel_iterator_base& operator =(
const roi_pixel_iterator_base& ) =
default;
4034 void Increment() noexcept
4036 for (
int i = 0; i < m_iterator.Length(); ++i )
4038 if ( m_iterator[0] == m_rowEnd )
4040 int w = m_rowEnd - m_rowBegin;
4041 for (
int i = 0; i < m_iterator.Length(); ++i )
4042 m_iterator[i] += m_image->Width() - w;
4043 m_rowBegin += m_image->Width();
4044 m_rowEnd += m_image->Width();
4048 void Decrement() noexcept
4050 if ( m_iterator[0] == m_rowBegin )
4052 int w = m_rowEnd - m_rowBegin;
4053 for (
int i = 0; i < m_iterator.Length(); ++i )
4054 m_iterator[i] -= m_image->Width() - w;
4055 m_rowBegin -= m_image->Width();
4056 m_rowEnd -= m_image->Width();
4058 for (
int i = 0; i < m_iterator.Length(); ++i )
4062 void MoveBy(
int cols,
int rows ) noexcept
4064 int dx = m_iterator[0] - m_rowBegin;
4065 for (
int i = 0; i < m_iterator.Length(); ++i )
4066 m_iterator[i] -= dx;
4070 int w = m_rowEnd - m_rowBegin;
4077 int dy = rows * m_image->Width();
4078 for (
int i = 0; i < m_iterator.Length(); ++i )
4079 m_iterator[i] += dy + cols;
4115 using iterator_base = roi_pixel_iterator_base<GenericImage<P>,
sample*>;
4137 : iterator_base( image.EnsureUnique(), rect )
4157 return this->m_image !=
nullptr && !this->m_iterator.IsEmpty();
4165 return *this->m_image;
4174 return this->m_iterator[channel];
4183 operator bool() const noexcept
4185 return this->m_iterator[0] < this->m_end;
4192 sample& operator [](
int channel )
const noexcept
4194 return *this->m_iterator[channel];
4254 int w = this->m_rowEnd - this->m_rowBegin;
4255 iterator_base::MoveBy( delta%w, delta/w );
4270 int w = this->m_rowEnd - this->m_rowBegin;
4271 iterator_base::MoveBy( -delta%w, -delta/w );
4285 iterator_base::MoveBy( dx, dy );
4328 return i.m_iterator[0] == j.m_iterator[0];
4337 return i.m_iterator[0] < j.m_iterator[0];
4371 using iterator_base = roi_pixel_iterator_base<const GenericImage<P>,
const sample*>;
4393 : iterator_base( image, rect )
4413 return this->m_image !=
nullptr && !this->m_iterator.IsEmpty();
4422 return *this->m_image;
4431 return this->m_iterator[channel];
4440 operator bool() const noexcept
4442 return this->m_iterator[0] < this->m_end;
4449 const sample& operator [](
int channel )
const noexcept
4451 return *this->m_iterator[channel];
4511 int w = this->m_rowEnd - this->m_rowBegin;
4512 iterator_base::MoveBy( delta%w, delta/w );
4527 int w = this->m_rowEnd - this->m_rowBegin;
4528 iterator_base::MoveBy( -delta%w, -delta/w );
4542 iterator_base::MoveBy( dx, dy );
4585 return i.m_iterator[0] == j.m_iterator[0];
4594 return i.m_iterator[0] < j.m_iterator[0];
4600 template <
class image_type,
class iterator_base,
class sample_po
inter,
class filter_type>
4601 class filter_pixel_iterator_base :
public iterator_base
4605 filter_type m_filter;
4606 sample_pointer m_begin =
nullptr;
4608 filter_pixel_iterator_base() =
default;
4610 filter_pixel_iterator_base( image_type& image,
const filter_type& filter )
4611 : iterator_base( image )
4612 , m_filter( filter )
4613 , m_begin( iterator_base::m_iterator )
4615 JumpToNextValidSample();
4618 filter_pixel_iterator_base(
const iterator_base& i,
const filter_type& filter )
4619 : iterator_base( i )
4620 , m_filter( filter )
4621 , m_begin( iterator_base::m_iterator )
4623 JumpToNextValidSample();
4626 filter_pixel_iterator_base(
const filter_pixel_iterator_base& ) =
default;
4628 filter_pixel_iterator_base& operator =(
const filter_pixel_iterator_base& ) =
default;
4630 filter_pixel_iterator_base& operator =(
const iterator_base& i ) noexcept
4632 (void)iterator_base::operator =( i );
4633 JumpToNextValidSample();
4636 void JumpToNextValidSample() noexcept
4638 while ( this->m_iterator[0] < this->m_end && !this->m_filter( this->m_iterator ) )
4639 for (
int i = 0; i < this->m_iterator.Length(); ++i )
4640 ++this->m_iterator[i];
4643 void JumpToPrevValidSample() noexcept
4645 while ( this->m_iterator[0] > this->m_begin && !this->m_filter( this->m_iterator ) )
4646 for (
int i = 0; i < this->m_iterator.Length(); ++i )
4647 --this->m_iterator[i];
4690 public filter_pixel_iterator_base<GenericImage<P>, pixel_iterator, sample*, F>
4731 : iterator_base( image.EnsureUnique(), filter )
4740 : iterator_base( i, filter )
4760 (void)iterator_base::operator =( i );
4770 return this->m_image !=
nullptr && !this->m_iterator.IsEmpty();
4778 return *this->m_image;
4787 return this->m_filter;
4796 return this->m_filter;
4805 return this->m_iterator[channel];
4813 operator bool() const noexcept
4815 return this->m_iterator[0] < this->m_end;
4822 sample& operator [](
int channel )
const noexcept
4824 return *this->m_iterator[channel];
4834 for (
int i = 0; i < this->m_iterator.Length(); ++i )
4835 ++this->m_iterator[i];
4836 this->JumpToNextValidSample();
4848 for (
int i = 0; i < this->m_iterator.Length(); ++i )
4849 ++this->m_iterator[i];
4850 this->JumpToNextValidSample();
4861 for (
int i = 0; i < this->m_iterator.Length(); ++i )
4862 --this->m_iterator[i];
4863 this->JumpToPrevValidSample();
4875 for (
int i = 0; i < this->m_iterator.Length(); ++i )
4876 --this->m_iterator[i];
4877 this->JumpToPrevValidSample();
4890 for (
int i = 0; i < this->m_iterator.Length(); ++i )
4891 this->m_iterator[i] += delta;
4892 this->JumpToNextValidSample();
4905 for (
int i = 0; i < this->m_iterator.Length(); ++i )
4906 this->m_iterator[i] -= delta;
4907 this->JumpToPrevValidSample();
4921 for (
int i = 0; i < this->m_iterator.Length(); ++i )
4922 this->m_iterator[i] += d;
4924 this->JumpToNextValidSample();
4926 this->JumpToPrevValidSample();
4969 return i.m_iterator[0] == j.m_iterator[0];
4978 return i.m_iterator[0] < j.m_iterator[0];
5021 public filter_pixel_iterator_base<const GenericImage<P>, const_pixel_iterator, const sample*, F>
5062 : iterator_base( image, filter )
5071 : iterator_base( i, filter )
5091 (void)iterator_base::operator =( i );
5101 return this->m_image !=
nullptr && !this->m_iterator.IsEmpty();
5110 return *this->m_image;
5119 return this->m_filter;
5128 return this->m_filter;
5137 return this->m_iterator[channel];
5145 operator bool() const noexcept
5147 return this->m_iterator[0] < this->m_end;
5154 const sample& operator [](
int channel )
const noexcept
5156 return *this->m_iterator[channel];
5166 for (
int i = 0; i < this->m_iterator.Length(); ++i )
5167 ++this->m_iterator[i];
5168 this->JumpToNextValidSample();
5180 for (
int i = 0; i < this->m_iterator.Length(); ++i )
5181 ++this->m_iterator[i];
5182 this->JumpToNextValidSample();
5193 for (
int i = 0; i < this->m_iterator.Length(); ++i )
5194 --this->m_iterator[i];
5195 this->JumpToPrevValidSample();
5207 for (
int i = 0; i < this->m_iterator.Length(); ++i )
5208 --this->m_iterator[i];
5209 this->JumpToPrevValidSample();
5222 for (
int i = 0; i < this->m_iterator.Length(); ++i )
5223 this->m_iterator[i] += delta;
5224 this->JumpToNextValidSample();
5237 for (
int i = 0; i < this->m_iterator.Length(); ++i )
5238 this->m_iterator[i] -= delta;
5239 this->JumpToPrevValidSample();
5253 for (
int i = 0; i < this->m_iterator.Length(); ++i )
5254 this->m_iterator[i] += d;
5256 this->JumpToNextValidSample();
5258 this->JumpToPrevValidSample();
5301 return i.m_iterator[0] == j.m_iterator[0];
5310 return i.m_iterator[0] < j.m_iterator[0];
5316 template <
class image_type,
class sample_po
inter,
class filter_type>
5317 class roi_filter_pixel_iterator_base :
public roi_pixel_iterator_base<image_type, sample_pointer>
5321 using roi_iterator_base = roi_pixel_iterator_base<image_type, sample_pointer>;
5323 filter_type m_filter;
5324 sample_pointer m_begin =
nullptr;
5326 roi_filter_pixel_iterator_base() =
default;
5328 roi_filter_pixel_iterator_base( image_type& image,
const filter_type& filter,
const Rect& rect )
5329 : roi_iterator_base( image, rect )
5330 , m_filter( filter )
5331 , m_begin( roi_iterator_base::m_iterator )
5333 JumpToNextValidSample();
5336 roi_filter_pixel_iterator_base(
const roi_iterator_base& i,
const filter_type& filter )
5337 : roi_iterator_base( i )
5338 , m_filter( filter )
5339 , m_begin( roi_iterator_base::m_iterator )
5341 JumpToNextValidSample();
5344 roi_filter_pixel_iterator_base(
const roi_filter_pixel_iterator_base& ) =
default;
5346 roi_filter_pixel_iterator_base& operator =(
const roi_filter_pixel_iterator_base& ) =
default;
5348 roi_filter_pixel_iterator_base& operator =(
const roi_iterator_base& i ) noexcept
5350 (void)roi_iterator_base::operator =( i );
5351 JumpToNextValidSample();
5355 void JumpToNextValidSample() noexcept
5357 while ( this->m_iterator[0] < this->m_end && !this->m_filter( this->m_iterator ) )
5358 roi_iterator_base::Increment();
5361 void JumpToPrevValidSample() noexcept
5363 while ( this->m_iterator[0] > this->m_begin && !this->m_filter( this->m_iterator ) )
5364 roi_iterator_base::Decrement();
5406 using iterator_base = roi_filter_pixel_iterator_base<GenericImage<P>,
sample*, F>;
5431 : iterator_base( image.EnsureUnique(), filter, rect )
5440 : iterator_base( i, filter )
5459 (void)iterator_base::operator =( i );
5469 return this->m_image !=
nullptr && !this->m_iterator.IsEmpty();
5477 return *this->m_image;
5486 return this->m_filter;
5495 return this->m_filter;
5504 return this->m_iterator[channel];
5513 operator bool() const noexcept
5515 return this->m_iterator[0] < this->m_end;
5522 sample& operator [](
int channel )
const noexcept
5524 return *this->m_iterator[channel];
5535 this->JumpToNextValidSample();
5548 this->JumpToNextValidSample();
5560 this->JumpToPrevValidSample();
5573 this->JumpToPrevValidSample();
5588 int w = this->m_rowEnd - this->m_rowBegin;
5589 return MoveBy( delta%w, delta/w );
5603 int w = this->m_rowEnd - this->m_rowBegin;
5604 return MoveBy( -delta%w, -delta/w );
5617 sample* __restrict__ i0 = this->m_iterator[0];
5618 iterator_base::MoveBy( dx, dy );
5619 if ( this->m_iterator[0] >= i0 )
5620 this->JumpToNextValidSample();
5622 this->JumpToPrevValidSample();
5665 return i.m_iterator[0] == j.m_iterator[0];
5674 return i.m_iterator[0] < j.m_iterator[0];
5716 using iterator_base = roi_filter_pixel_iterator_base<const GenericImage<P>,
const sample*, F>;
5742 : iterator_base( image, filter, rect )
5751 : iterator_base( i, filter )
5771 (void)iterator_base::operator =( i );
5781 return this->m_image !=
nullptr && !this->m_iterator.IsEmpty();
5790 return *this->m_image;
5799 return this->m_filter;
5808 return this->m_filter;
5817 return this->m_iterator[channel];
5826 operator bool() const noexcept
5828 return this->m_iterator[0] < this->m_end;
5835 const sample& operator [](
int channel )
const noexcept
5837 return *this->m_iterator[channel];
5848 this->JumpToNextValidSample();
5861 this->JumpToNextValidSample();
5873 this->JumpToPrevValidSample();
5886 this->JumpToPrevValidSample();
5901 int w = this->m_rowEnd - this->m_rowBegin;
5902 return MoveBy( delta%w, delta/w );
5916 int w = this->m_rowEnd - this->m_rowBegin;
5917 return MoveBy( -delta%w, -delta/w );
5930 const sample* __restrict__ i0 = this->m_iterator[0];
5931 iterator_base::MoveBy( dx, dy );
5932 if ( this->m_iterator[0] >= i0 )
5933 this->JumpToNextValidSample();
5935 this->JumpToPrevValidSample();
5978 return i.m_iterator[0] == j.m_iterator[0];
5987 return i.m_iterator[0] < j.m_iterator[0];
5999 return pixel_traits::IsFloatSample();
6008 return pixel_traits::IsComplexSample();
6017 return P::BytesPerSample();
6026 return P::BitsPerSample();
6039 return image.BitsPerSample() == BitsPerSample() &&
6040 image.IsFloatSample() == IsFloatSample() &&
6041 image.IsComplexSample() == IsComplexSample();
6062 m_data =
new Data(
this );
6099 image.m_data->Attach(
this );
6100 m_data = image.m_data;
6101 m_status = image.m_status;
6106 m_data =
new Data(
this );
6107 (void)Assign( image );
6115 , m_data( image.m_data )
6117 image.m_data =
nullptr;
6135 m_data =
new Data(
this );
6136 (void)Assign( image );
6182 m_data =
new Data(
this );
6183 (void)Assign( image, rect, firstChannel, lastChannel );
6204 GenericImage(
int width,
int height, color_space colorSpace = ColorSpace::Gray )
6206 m_data =
new Data(
this );
6227 m_data =
new Data(
this );
6252 m_data =
new Data(
this, handle );
6283 GenericImage(
void*,
int width,
int height, color_space colorSpace = ColorSpace::Gray )
6308 if ( m_data !=
nullptr )
6335 return m_data->IsShared();
6350 return m_data->IsUnique();
6367 if ( m_data->IsShared() )
6371 local->m_data->Allocate( m_width, m_height, m_numberOfChannels, m_colorSpace );
6372 local->m_RGBWS = m_RGBWS;
6373 local->m_selected = m_selected;
6374 local->m_savedSelections = m_savedSelections;
6375 local->m_status = m_status;
6376 for (
int c = 0; c < m_numberOfChannels; ++c )
6377 P::Copy( (*local)[c], m_channelData( c ), NumberOfPixels() );
6379 local->m_data->Attach(
this );
6381 m_data = local->m_data;
6403 if ( !m_data->IsUnique() )
6405 Data* newData = m_data->Clone(
this );
6446 m_data->SynchronizeWithSharedImage();
6485 int numberOfChannels = 1,
6486 color_space colorSpace = ColorSpace::Gray )
6488 if ( !m_data->IsUnique() )
6490 Data* newData =
new Data(
this );
6494 m_data->Allocate( width, height, numberOfChannels, colorSpace );
6510 int numberOfChannels = 1,
6511 color_space colorSpace = ColorSpace::Gray )
6513 return AllocateData( rect.
Width(), rect.
Height(), numberOfChannels, colorSpace );
6529 if ( !m_data->IsEmpty() )
6530 if ( m_data->IsUnique() )
6531 m_data->Deallocate();
6534 Data* newData =
new Data(
this );
6598 int numberOfChannels = 1, color_space colorSpace = ColorSpace::Gray )
6600 if ( !m_data->IsUnique() )
6602 if ( m_data->IsShared() )
6603 throw Error(
"GenericImage::ImportData(): Invalid operation for an aliased shared image" );
6604 Data* newData =
new Data(
this );
6608 m_data->Import( data, width, height, numberOfChannels, colorSpace );
6649 if ( !m_data->IsUnique() )
6650 throw Error(
"GenericImage::ReleaseData(): Invalid operation for an aliased image" );
6651 sample** data = m_data->Release();
6664 return BytesPerSample() *
size_type( m_width );
6673 return BytesPerSample() * NumberOfPixels();
6684 return ChannelSize() *
size_type( m_numberOfChannels );
6704 return ChannelSize() * NumberOfAlphaChannels();
6723 PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6725 return m_channelData( channel );
6736 PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6737 return m_channelData( channel );
6743 operator bool() const noexcept
6745 return m_data !=
nullptr && !m_data->IsEmpty();
6760 PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6761 return PixelData( channel );
6770 const sample* operator [](
int channel )
const noexcept
6772 PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6773 return PixelData( channel );
6785 PCL_PRECONDITION( 0 < m_numberOfChannels )
6786 return PixelData( 0 );
6797 PCL_PRECONDITION( 0 < m_numberOfChannels )
6798 return PixelData( 0 );
6822 PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6823 PCL_PRECONDITION( 0 <= y && y < m_height )
6825 return m_channelData( channel ) + RowOffset( y );
6836 PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6837 PCL_PRECONDITION( 0 <= y && y < m_height )
6838 return m_channelData( channel ) + RowOffset( y );
6866 PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6867 PCL_PRECONDITION( 0 <= x && x < m_width )
6868 PCL_PRECONDITION( 0 <= y && y < m_height )
6870 return m_channelData( channel ) + PixelOffset( x, y );
6881 PCL_PRECONDITION( 0 <= channel && channel < m_numberOfChannels )
6882 PCL_PRECONDITION( 0 <= x && x < m_width )
6883 PCL_PRECONDITION( 0 <= y && y < m_height )
6884 return m_channelData( channel ) + PixelOffset( x, y );
6909 return PixelAddress( p.
x, p.
y, channel );
6921 return PixelAddress( p.
x, p.
y, channel );
6944 sample& operator ()(
int x,
int y,
int channel = 0 )
6946 return *PixelAddress( x, y, channel );
6965 sample operator ()(
int x,
int y,
int channel = 0 ) const noexcept
6967 return *PixelAddress( x, y, channel );
6989 return *PixelAddress( p, channel );
7007 return *PixelAddress( p, channel );
7019 return operator()( x, y, channel );
7031 return operator()( x, y, channel );
7043 return operator()( p, channel );
7056 return operator()( p, channel );
7151 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
7153 m_status = image.
Status();
7162 int n = 1 + lastChannel - firstChannel;
7171 if ( r == image.
Bounds() )
7172 for (
int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7173 P::Copy( m_channelData( c ), image[firstChannel], NumberOfPixels() );
7175 for (
int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7177 sample* f = m_channelData( c );
7179 for (
int y = 0; y < m_height; ++y, f += m_width, g += image.
Width() )
7180 P::Copy( f, g, m_width );
7187 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
7189 m_status = image.
Status();
7198 #define completeSelection (firstChannel == 0 && lastChannel == image.m_numberOfChannels-1 && r == image.Bounds())
7200 if ( m_data == image.m_data )
7203 if ( !completeSelection )
7205 GenericImage result( image, r, firstChannel, lastChannel );
7206 result.m_data->Attach(
this );
7208 m_data = result.m_data;
7216 if ( completeSelection )
7218 image.m_data->Attach(
this );
7220 m_data = image.m_data;
7225 #undef completeSelection
7227 int n = 1 + lastChannel - firstChannel;
7232 m_RGBWS = image.m_RGBWS;
7236 if ( r == image.
Bounds() )
7237 for (
int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7238 P::Copy( m_channelData( c ), image[firstChannel], NumberOfPixels() );
7240 for (
int c = 0; firstChannel <= lastChannel; ++c, ++firstChannel )
7242 sample* f = m_channelData( c );
7244 for (
int y = 0; y < m_height; ++y, f += m_width, g += image.m_width )
7245 P::Copy( f, g, m_width );
7260 return Assign( image );
7275 return Assign( image );
7278 #define TRANSFER_BODY() \
7279 if ( m_data != image.m_data ) \
7282 m_data = image.m_data; \
7283 (void)AbstractImage::operator =( image ); \
7284 image.m_data = nullptr; \
7320 #undef TRANSFER_BODY
7329 return Transfer( image );
7340 return Fill( scalar );
7348 x1.AbstractImage::Swap( x2 );
7354 #ifndef __PCL_NO_VECTOR_IMAGE_CONVERSION
7377 channel = m_channel;
7378 if ( y < 0 || y >= m_height || channel < 0 || channel >= m_numberOfChannels )
7381 P::Get( row.
Begin(), ScanLine( y, channel ), m_width );
7406 channel = m_channel;
7407 if ( x < 0 || x >= m_width || channel < 0 || channel >= m_numberOfChannels )
7410 const sample* v = PixelAddress( x, 0, channel );
7411 for (
int y = 0; y < m_height; ++y, v += m_width )
7421 return ColumnVector( x, channel );
7424 #endif // !__PCL_NO_VECTOR_IMAGE_CONVERSION
7447 template <
typename T>
7448 void GetRow( T* buffer,
int y,
int channel = -1 )
const
7450 PCL_PRECONDITION( buffer != 0 )
7452 channel = m_channel;
7453 if ( y >= 0 && y < m_height && channel >= 0 && channel < m_numberOfChannels )
7454 P::Get( buffer, ScanLine( y, channel ), m_width );
7478 template <
typename T>
7481 PCL_PRECONDITION( buffer != 0 )
7483 channel = m_channel;
7484 if ( x >= 0 && x < m_width && channel >= 0 && channel < m_numberOfChannels )
7486 const sample* v = PixelAddress( x, 0, channel );
7487 for (
int y = 0; y < m_height; ++y, ++buffer, v += m_width )
7488 P::FromSample( *buffer, *v );
7513 template <
typename T>
7516 PCL_PRECONDITION( buffer != 0 )
7518 channel = m_channel;
7519 if ( y >= 0 && y < m_height && channel >= 0 && channel < m_numberOfChannels )
7520 P::Copy( ScanLine( y, channel ), buffer, m_width );
7545 template <
typename T>
7548 PCL_PRECONDITION( buffer != 0 )
7550 channel = m_channel;
7551 if ( x >= 0 && x < m_width && channel >= 0 && channel < m_numberOfChannels )
7553 sample* v = PixelAddress( x, 0, channel );
7554 for (
int y = 0; y < m_height; ++y, ++buffer, v += m_width )
7555 *v = P::ToSample( *buffer );
7573 if ( n > 0 && m_numberOfChannels > 0 )
7576 sample** oldData = m_pixelData;
7577 sample** newData =
nullptr;
7580 newData = m_allocator.AllocateChannelSlots( m_numberOfChannels+n );
7581 for (
int i = 0; i < m_numberOfChannels; ++i )
7582 newData[i] = oldData[i];
7583 for (
int i = 0; i < n; ++i )
7584 newData[m_numberOfChannels+i] = m_allocator.AllocatePixels( m_width, m_height );
7588 if ( newData !=
nullptr )
7590 for (
int i = 0; i < n; ++i )
7591 if ( newData[m_numberOfChannels+i] !=
nullptr )
7592 m_allocator.Deallocate( newData[m_numberOfChannels+i] );
7593 m_allocator.Deallocate( newData );
7598 m_allocator.SetSharedData( m_pixelData = newData );
7599 m_allocator.SetSharedGeometry( m_width, m_height, m_numberOfChannels += n );
7600 m_allocator.Deallocate( oldData );
7628 if ( data ==
nullptr )
7629 CreateAlphaChannels( 1 );
7630 else if ( m_numberOfChannels > 0 )
7633 sample** oldData = m_pixelData;
7634 sample** newData =
nullptr;
7637 newData = m_allocator.AllocateChannelSlots( m_numberOfChannels+1 );
7638 for (
int i = 0; i < m_numberOfChannels; ++i )
7639 newData[i] = oldData[i];
7640 newData[m_numberOfChannels] = data;
7644 if ( newData !=
nullptr )
7645 m_allocator.Deallocate( newData );
7649 m_allocator.SetSharedData( m_pixelData = newData );
7650 m_allocator.SetSharedGeometry( m_width, m_height, ++m_numberOfChannels );
7651 m_allocator.Deallocate( oldData );
7681 if ( IsShared() != image.
IsShared() )
7682 throw Error(
"GenericImage::ReleaseAlphaChannel(): Cannot release pixel data between local and shared images" );
7684 if ( channel < 0 || channel >= NumberOfAlphaChannels() )
7692 sample** newData =
nullptr;
7695 newData = image.m_allocator.AllocateChannelSlots( 1 );
7696 *newData = m_pixelData[c];
7700 if ( newData !=
nullptr )
7701 image.m_allocator.Deallocate( newData );
7707 image.m_pixelData = newData;
7708 image.m_width = m_width;
7709 image.m_height = m_height;
7710 image.m_numberOfChannels = 1;
7711 image.m_colorSpace = ColorSpace::Gray;
7712 image.m_data->UpdateSharedImage();
7715 m_pixelData[c] =
nullptr;
7716 ForgetAlphaChannel( channel );
7734 if ( channel >= 0 && channel < NumberOfAlphaChannels() )
7738 m_allocator.Deallocate( m_pixelData[c] );
7739 m_pixelData[c] =
nullptr;
7740 ForgetAlphaChannel( channel );
7764 if ( channel >= 0 && channel < NumberOfAlphaChannels() )
7767 sample** oldData = m_pixelData;
7768 sample** newData = m_allocator.AllocateChannelSlots( m_numberOfChannels-1 );
7771 int c = n0 + channel;
7773 for (
int i = 0; i < c; ++i )
7774 newData[i] = oldData[i];
7775 for (
int i = c, j = c; ++j < m_numberOfChannels; ++i )
7776 newData[i] = oldData[j];
7778 m_allocator.SetSharedData( m_pixelData = newData );
7779 m_allocator.SetSharedGeometry( m_width, m_height, --m_numberOfChannels );
7781 if ( m_channel >= n0 || m_lastChannel >= n0 )
7782 ResetChannelRange();
7784 m_allocator.Deallocate( oldData );
7797 int n = m_numberOfChannels;
7802 m_allocator.Deallocate( m_pixelData[--n] ), m_pixelData[n] =
nullptr;
7804 ForgetAlphaChannels();
7821 if ( m_numberOfChannels > n0 )
7824 sample** oldData = m_pixelData;
7825 sample** newData = m_allocator.AllocateChannelSlots( n0 );
7827 for (
int i = 0; i < n0; ++i )
7828 newData[i] = oldData[i];
7830 m_allocator.SetSharedData( m_pixelData = newData );
7831 m_allocator.SetSharedGeometry( m_width, m_height, m_numberOfChannels = n0 );
7833 if ( m_channel >= n0 || m_lastChannel >= n0 )
7834 ResetChannelRange();
7836 m_allocator.Deallocate( oldData );
7880 template <
typename T>
7884 if ( !ParseSelection( r, firstChannel, lastChannel ) )
7890 if ( m_status.IsInitializationEnabled() )
7891 m_status.Initialize(
"Filling image", N*(1 + lastChannel - firstChannel) );
7893 sample v = P::ToSample( scalar );
7895 if ( r == Bounds() )
7896 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
7897 P::Fill( m_pixelData[i], v, N );
7899 for (
int i = firstChannel, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i, m_status += N )
7903 for (
int j = 0; j < h; ++j, f += m_width )
7927 template <
typename T>
7929 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
7932 if ( !ParseSelection( r, firstChannel, lastChannel ) )
7938 if ( m_status.IsInitializationEnabled() )
7939 m_status.Initialize(
"Filling image", N*(1 + lastChannel - firstChannel) );
7941 if ( r == Bounds() )
7942 for (
int i = firstChannel, c = 0; i <= lastChannel; ++i, ++c, m_status += N )
7944 sample v = (c < values.
Length()) ? P::ToSample( values[c] ) : P::MinSampleValue();
7945 P::Fill( m_pixelData[i], v, N );
7948 for (
int i = firstChannel, c = 0, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i, ++c, m_status += N )
7951 sample v = (c < values.
Length()) ? P::ToSample( values[c] ) : P::MinSampleValue();
7953 for (
int j = 0; j < h; ++j, f += m_width )
7970 template <
typename T>
7973 GenericImage result( *
this, rect, firstChannel, lastChannel );
7974 (void)result.
Fill( scalar );
7989 template <
typename T>
7991 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const
7993 GenericImage result( *
this, rect, firstChannel, lastChannel );
7994 (void)result.
Fill( values );
8014 return Fill( P::ToSample( 0.0 ), rect, firstChannel, lastChannel );
8033 return Fill( P::ToSample( 1.0 ), rect, firstChannel, lastChannel );
8051 return Fill( P::MinSampleValue(), rect, firstChannel, lastChannel );
8069 return Fill( P::MaxSampleValue(), rect, firstChannel, lastChannel );
8088 template <
typename T>
8092 if ( !ParseSelection( r, firstChannel, lastChannel ) )
8098 if ( m_status.IsInitializationEnabled() )
8099 m_status.Initialize(
"Inverting pixel samples", N*(1 + lastChannel - firstChannel) );
8101 sample v = P::ToSample( scalar );
8102 if ( r == Bounds() )
8103 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8105 sample* __restrict__ f = m_pixelData[i];
8107 for (
size_type j = 0; j < N; ++j, ++f )
8111 for (
int i = firstChannel, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i, m_status += N )
8115 for (
int j = 0; j < h; ++j, f += m_width-w )
8118 for (
int k = 0; k < w; ++k, ++f )
8136 template <
typename T>
8139 GenericImage result( *
this, rect, firstChannel, lastChannel );
8140 (void)result.
Invert( scalar );
8163 return Invert( P::MaxSampleValue(), rect, firstChannel, lastChannel );
8179 GenericImage result( *
this, rect, firstChannel, lastChannel );
8212 if ( !ParseSelection( r, firstChannel, lastChannel ) )
8218 if ( m_status.IsInitializationEnabled() )
8219 m_status.Initialize(
"Bitwise Not", N*(1 + lastChannel - firstChannel) );
8221 if ( r == Bounds() )
8222 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8224 sample* __restrict__ f = m_pixelData[i];
8226 for (
size_type j = 0; j < N; ++j, ++f )
8230 for (
int i = firstChannel, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i, m_status += N )
8234 for (
int j = 0; j < h; ++j, f += m_width-w )
8237 for (
int k = 0; k < w; ++k, ++f )
8261 template <
typename T>
8263 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
8266 if ( !ParseSelection( r, firstChannel, lastChannel ) )
8272 if ( m_status.IsInitializationEnabled() )
8273 m_status.Initialize(
"Truncating pixel samples", N*(1 + lastChannel - firstChannel) );
8275 sample b0 = P::ToSample( lowerBound );
8276 sample b1 = P::ToSample( upperBound );
8280 if ( r == Bounds() )
8281 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8283 sample* __restrict__ f = m_pixelData[i];
8285 for (
size_type j = 0; j < N; ++j, ++f )
8292 for (
int i = firstChannel, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i, m_status += N )
8296 for (
int j = 0; j < h; ++j, f += m_width-w )
8299 for (
int k = 0; k < w; ++k, ++f )
8323 template <
typename T>
8325 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const
8327 GenericImage result( *
this, rect, firstChannel, lastChannel );
8328 (void)result.
Truncate( lowerBound, upperBound );
8355 return Truncate( P::MinSampleValue(), P::MaxSampleValue(), rect, firstChannel, lastChannel );
8370 GenericImage result( *
this, rect, firstChannel, lastChannel );
8403 template <
typename T>
8405 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
8408 if ( !ParseSelection( r, firstChannel, lastChannel ) )
8412 size_type Ns = N*(1 + lastChannel - firstChannel);
8413 if ( m_status.IsInitializationEnabled() )
8414 m_status.Initialize(
"Rescaling pixel samples", Ns );
8416 sample b0 = P::ToSample( lowerBound );
8417 sample b1 = P::ToSample( upperBound );
8422 GetExtremePixelValues( v0, v1, r, firstChannel, lastChannel );
8423 if ( v0 == b0 && v1 == b1 )
8434 d = (double( b1 ) - double( b0 ))/(
double( v1 ) - double( v0 ));
8436 if ( r == Bounds() )
8437 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8439 sample* __restrict__ f = m_pixelData[i];
8448 for (
size_type j = 0; j < N; ++j, ++f )
8449 *f = P::FloatToSample( d*(*f - v0) );
8454 for (
size_type j = 0; j < N; ++j, ++f )
8455 *f = P::FloatToSample( d*(*f - v0) + b0 );
8459 P::Fill( f, b0, N );
8465 for (
int i = firstChannel, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i, m_status += N )
8476 for (
int j = 0; j < h; ++j, f += m_width-w )
8479 for (
int k = 0; k < w; ++k, ++f )
8480 *f = P::FloatToSample( d*(*f - v0) );
8486 for (
int j = 0; j < h; ++j, f += m_width-w )
8489 for (
int k = 0; k < w; ++k, ++f )
8490 *f = P::FloatToSample( d*(*f - v0) + b0 );
8497 for (
int j = 0; j < h; ++j, f += m_width )
8498 P::Fill( f, b0, w );
8505 for (
int j = 0; j < h; ++j, f += m_width )
8526 template <
typename T>
8528 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const
8530 GenericImage result( *
this, rect, firstChannel, lastChannel );
8531 (void)result.
Rescale( lowerBound, upperBound );
8553 return Rescale( P::MinSampleValue(), P::MaxSampleValue(), rect, firstChannel, lastChannel );
8568 GenericImage result( *
this, rect, firstChannel, lastChannel );
8607 template <
typename T>
8609 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
8612 if ( !ParseSelection( r, firstChannel, lastChannel ) )
8616 size_type Ns = N*(1 + lastChannel - firstChannel);
8617 if ( m_status.IsInitializationEnabled() )
8618 m_status.Initialize(
"Normalizing pixel samples", Ns );
8620 sample b0 = P::ToSample( lowerBound );
8621 sample b1 = P::ToSample( upperBound );
8626 GetExtremePixelValues( v0, v1, r, firstChannel, lastChannel );
8628 if ( v0 >= b0 && v1 <= b1 )
8639 d = (double( b1 ) - double( b0 ))/(
double( v1 ) - double( v0 ));
8641 if ( r == Bounds() )
8642 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8644 sample* __restrict__ f = m_pixelData[i];
8653 for (
size_type j = 0; j < N; ++j, ++f )
8654 *f = P::FloatToSample( d*(*f - v0) );
8659 for (
size_type j = 0; j < N; ++j, ++f )
8660 *f = P::FloatToSample( d*(*f - v0) + b0 );
8664 P::Fill( f, b0, N );
8670 for (
int i = firstChannel, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i, m_status += N )
8681 for (
int j = 0; j < h; ++j, f += m_width-w )
8684 for (
int k = 0; k < w; ++k, ++f )
8685 *f = P::FloatToSample( d*(*f - v0) );
8691 for (
int j = 0; j < h; ++j, f += m_width-w )
8694 for (
int k = 0; k < w; ++k, ++f )
8695 *f = P::FloatToSample( d*(*f - v0) + b0 );
8702 for (
int j = 0; j < h; ++j, f += m_width )
8703 P::Fill( f, b0, w );
8710 for (
int j = 0; j < h; ++j, f += m_width )
8731 template <
typename T>
8733 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const
8735 GenericImage result( *
this, rect, firstChannel, lastChannel );
8736 (void)result.
Normalize( lowerBound, upperBound );
8758 return Normalize( P::MinSampleValue(), P::MaxSampleValue(), rect, firstChannel, lastChannel );
8773 GenericImage result( *
this, rect, firstChannel, lastChannel );
8807 template <
typename T>
8809 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
8812 if ( !ParseSelection( r, firstChannel, lastChannel ) )
8818 if ( m_status.IsInitializationEnabled() )
8819 m_status.Initialize(
"Binarizing pixel samples", N*(1 + lastChannel - firstChannel) );
8821 sample t = P::ToSample( threshold );
8823 if ( r == Bounds() )
8824 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8826 sample* __restrict__ f = m_pixelData[i];
8828 for (
size_type j = 0; j < N; ++j, ++f )
8829 *f = (*f < t) ? P::MinSampleValue() : P::MaxSampleValue();
8832 for (
int c = firstChannel, w = r.
Width(), h = r.
Height(); c <= lastChannel; ++c, m_status += N )
8836 for (
int j = 0; j < h; ++j, f += m_width-w )
8839 for (
int k = 0; k < w; ++k, ++f )
8840 *f = (*f < t) ? P::MinSampleValue() : P::MaxSampleValue();
8857 template <
typename T>
8859 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const
8861 GenericImage result( *
this, rect, firstChannel, lastChannel );
8862 (void)result.
Binarize( threshold );
8884 return Binarize( (P::MinSampleValue() + P::MaxSampleValue())/2, rect, firstChannel, lastChannel );
8900 GenericImage result( *
this, rect, firstChannel, lastChannel );
8921 if ( !ParseSelection( r, firstChannel, lastChannel ) )
8927 if ( m_status.IsInitializationEnabled() )
8928 m_status.Initialize(
"Computing absolute value", N*(1 + lastChannel - firstChannel) );
8930 if ( r == Bounds() )
8931 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
8933 sample* __restrict__ f = m_pixelData[i];
8935 for (
size_type j = 0; j < N; ++j, ++f )
8939 for (
int i = firstChannel, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i, m_status += N )
8943 for (
int j = 0; j < h; ++j, f += m_width-w )
8946 for (
int k = 0; k < w; ++k, ++f )
8959 return SetAbsoluteValue( rect, firstChannel, lastChannel );
8974 GenericImage result( *
this, rect, firstChannel, lastChannel );
8986 template <
typename T>
8987 GenericImage& ApplyScalar( T scalar, image_op op = ImageOp::Mov,
8988 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
8990 if ( op == ImageOp::Div )
8991 if ( 1 + scalar == 1 )
8992 throw Error(
"Division by zero or insignificant scalar" );
8995 if ( !ParseSelection( r, firstChannel, lastChannel ) )
9001 if ( m_status.IsInitializationEnabled() )
9002 m_status.Initialize(
"Applying scalar: "
9004 +
' ' +
String( scalar ), N*(1 + lastChannel - firstChannel) );
9006 if ( r == Bounds() )
9007 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
9009 sample* __restrict__ f = m_pixelData[i];
9010 #define ITERATE( Op ) \
9012 for ( size_type j = 0; j < N; ++j, ++f ) \
9016 case ImageOp::Mov: ITERATE( Mov );
break;
9017 case ImageOp::Add: ITERATE( Add );
break;
9018 case ImageOp::Sub: ITERATE( Sub );
break;
9019 case ImageOp::Mul: ITERATE( Mul );
break;
9020 case ImageOp::Div: ITERATE( Div );
break;
9021 case ImageOp::Pow: ITERATE( Pow );
break;
9022 case ImageOp::Dif: ITERATE( Dif );
break;
9023 case ImageOp::Min: ITERATE( Min );
break;
9024 case ImageOp::Max: ITERATE( Max );
break;
9025 case ImageOp::Not: ITERATE( Not );
break;
9026 case ImageOp::Or: ITERATE( Or );
break;
9027 case ImageOp::Nor: ITERATE( Nor );
break;
9028 case ImageOp::And: ITERATE( And );
break;
9029 case ImageOp::Nand: ITERATE( Nand );
break;
9030 case ImageOp::Xor: ITERATE( Xor );
break;
9031 case ImageOp::Xnor: ITERATE( Xnor );
break;
9032 case ImageOp::ColorBurn: ITERATE( ColorBurn );
break;
9033 case ImageOp::LinearBurn: ITERATE( LinearBurn );
break;
9034 case ImageOp::Screen: ITERATE( Screen );
break;
9035 case ImageOp::ColorDodge: ITERATE( ColorDodge );
break;
9036 case ImageOp::Overlay: ITERATE( Overlay );
break;
9037 case ImageOp::SoftLight: ITERATE( SoftLight );
break;
9038 case ImageOp::HardLight: ITERATE( HardLight );
break;
9039 case ImageOp::VividLight: ITERATE( VividLight );
break;
9040 case ImageOp::LinearLight: ITERATE( LinearLight );
break;
9041 case ImageOp::PinLight: ITERATE( PinLight );
break;
9042 case ImageOp::Exclusion: ITERATE( Exclusion );
break;
9048 for (
int i = firstChannel, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i, m_status += N )
9050 sample* __restrict__ f = PixelAddress( r.
LeftTop(), i );
9051 #define ITERATE( Op ) \
9053 for ( int j = 0; j < h; ++j, f += m_width-w ) \
9056 for ( int k = 0; k < w; ++k, ++f ) \
9057 P::Op( *f, scalar ); \
9061 case ImageOp::Mov: ITERATE( Mov );
break;
9062 case ImageOp::Add: ITERATE( Add );
break;
9063 case ImageOp::Sub: ITERATE( Sub );
break;
9064 case ImageOp::Mul: ITERATE( Mul );
break;
9065 case ImageOp::Div: ITERATE( Div );
break;
9066 case ImageOp::Pow: ITERATE( Pow );
break;
9067 case ImageOp::Dif: ITERATE( Dif );
break;
9068 case ImageOp::Min: ITERATE( Min );
break;
9069 case ImageOp::Max: ITERATE( Max );
break;
9070 case ImageOp::Not: ITERATE( Not );
break;
9071 case ImageOp::Or: ITERATE( Or );
break;
9072 case ImageOp::Nor: ITERATE( Nor );
break;
9073 case ImageOp::And: ITERATE( And );
break;
9074 case ImageOp::Nand: ITERATE( Nand );
break;
9075 case ImageOp::Xor: ITERATE( Xor );
break;
9076 case ImageOp::Xnor: ITERATE( Xnor );
break;
9077 case ImageOp::ColorBurn: ITERATE( ColorBurn );
break;
9078 case ImageOp::LinearBurn: ITERATE( LinearBurn );
break;
9079 case ImageOp::Screen: ITERATE( Screen );
break;
9080 case ImageOp::ColorDodge: ITERATE( ColorDodge );
break;
9081 case ImageOp::Overlay: ITERATE( Overlay );
break;
9082 case ImageOp::SoftLight: ITERATE( SoftLight );
break;
9083 case ImageOp::HardLight: ITERATE( HardLight );
break;
9084 case ImageOp::VividLight: ITERATE( VividLight );
break;
9085 case ImageOp::LinearLight: ITERATE( LinearLight );
break;
9086 case ImageOp::PinLight: ITERATE( PinLight );
break;
9087 case ImageOp::Exclusion: ITERATE( Exclusion );
break;
9118 template <
typename T>
9120 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
9122 return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9126 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
9129 return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9130 return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9133 GenericImage&
Apply(
double scalar, image_op op = ImageOp::Mov,
9134 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
9137 return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9138 return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9142 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
9145 return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9146 return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9150 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
9153 return ApplyScalar( scalar, op, rect, firstChannel, lastChannel );
9154 return ApplyScalar( P::ToSample( scalar ), op, rect, firstChannel, lastChannel );
9175 template <
typename T>
9177 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const
9179 GenericImage result( *
this, rect, firstChannel, lastChannel );
9180 (void)result.
Apply( scalar, op );
9232 const Point& point =
Point( int_max ),
int channel = -1,
9233 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
9239 if ( !ParseChannel( channel ) )
9243 if ( p.
x == int_max || p.
y == int_max )
9248 if ( (r.
x0 -= p.
x) >= r.
x1 )
9252 else if ( p.
x >= m_width )
9257 if ( (r.
y0 -= p.
y) >= r.
y1 )
9261 else if ( p.
y >= m_height )
9267 lastChannel =
pcl::Min( lastChannel, firstChannel + m_numberOfChannels - channel - 1 );
9272 if ( m_status.IsInitializationEnabled() )
9273 m_status.Initialize(
"Applying image, op=" +
ImageOp::Id( op ), N*(1 + lastChannel - firstChannel) );
9275 if ( r == Bounds() && r == image.
Bounds() )
9276 for (
int i = channel, j = firstChannel; j <= lastChannel; ++i, ++j, m_status += N )
9278 sample* __restrict__ f = m_pixelData[i];
9279 const typename P1::sample* __restrict__ g = image[j];
9281 #define ITERATE( Op ) \
9283 for ( size_type k = 0; k < N; ++k, ++f, ++g ) \
9291 P::CopyMin( f, g, N );
9294 P::CopyMax( f, g, N );
9299 case ImageOp::Add: ITERATE( Add );
break;
9300 case ImageOp::Sub: ITERATE( Sub );
break;
9301 case ImageOp::Mul: ITERATE( Mul );
break;
9303 for (
size_type j = 0; j < N; ++j, ++f, ++g )
9307 *f = P::MaxSampleValue();
9309 case ImageOp::Pow: ITERATE( Pow );
break;
9310 case ImageOp::Dif: ITERATE( Dif );
break;
9311 case ImageOp::Not: ITERATE( Not );
break;
9312 case ImageOp::Or: ITERATE( Or );
break;
9313 case ImageOp::Nor: ITERATE( Nor );
break;
9314 case ImageOp::And: ITERATE( And );
break;
9315 case ImageOp::Nand: ITERATE( Nand );
break;
9316 case ImageOp::Xor: ITERATE( Xor );
break;
9317 case ImageOp::Xnor: ITERATE( Xnor );
break;
9318 case ImageOp::ColorBurn: ITERATE( ColorBurn );
break;
9319 case ImageOp::LinearBurn: ITERATE( LinearBurn );
break;
9320 case ImageOp::Screen: ITERATE( Screen );
break;
9321 case ImageOp::ColorDodge: ITERATE( ColorDodge );
break;
9322 case ImageOp::Overlay: ITERATE( Overlay );
break;
9323 case ImageOp::SoftLight: ITERATE( SoftLight );
break;
9324 case ImageOp::HardLight: ITERATE( HardLight );
break;
9325 case ImageOp::VividLight: ITERATE( VividLight );
break;
9326 case ImageOp::LinearLight: ITERATE( LinearLight );
break;
9327 case ImageOp::PinLight: ITERATE( PinLight );
break;
9328 case ImageOp::Exclusion: ITERATE( Exclusion );
break;
9336 for (
int i = channel, j = firstChannel, w = r.
Width(), h = r.
Height(); j <= lastChannel; ++i, ++j, m_status += N )
9338 sample* __restrict__ f = PixelAddress( p, i );
9341 #define ITERATE( Op ) \
9343 for ( int k = 0; k < h; ++k, f += m_width-w, g += image.Width()-w ) \
9346 for ( int l = 0; l < w; ++l, ++f, ++g ) \
9352 for (
int k = 0; k < h; ++k, f += m_width, g += image.
Width() )
9356 for (
int k = 0; k < h; ++k, f += m_width, g += image.
Width() )
9357 P::CopyMin( f, g, w );
9360 for (
int k = 0; k < h; ++k, f += m_width, g += image.
Width() )
9361 P::CopyMax( f, g, w );
9363 case ImageOp::Add: ITERATE( Add );
break;
9364 case ImageOp::Sub: ITERATE( Sub );
break;
9365 case ImageOp::Mul: ITERATE( Mul );
break;
9368 for (
int k = 0; k < h; ++k, f += m_width-w, g += image.
Width()-w )
9371 for (
int l = 0; l < w; ++l, ++f, ++g )
9375 *f = P::MaxSampleValue();
9378 case ImageOp::Pow: ITERATE( Pow );
break;
9379 case ImageOp::Dif: ITERATE( Dif );
break;
9380 case ImageOp::Not: ITERATE( Not );
break;
9381 case ImageOp::Or: ITERATE( Or );
break;
9382 case ImageOp::Nor: ITERATE( Nor );
break;
9383 case ImageOp::And: ITERATE( And );
break;
9384 case ImageOp::Nand: ITERATE( Nand );
break;
9385 case ImageOp::Xor: ITERATE( Xor );
break;
9386 case ImageOp::Xnor: ITERATE( Xnor );
break;
9387 case ImageOp::ColorBurn: ITERATE( ColorBurn );
break;
9388 case ImageOp::LinearBurn: ITERATE( LinearBurn );
break;
9389 case ImageOp::Screen: ITERATE( Screen );
break;
9390 case ImageOp::ColorDodge: ITERATE( ColorDodge );
break;
9391 case ImageOp::Overlay: ITERATE( Overlay );
break;
9392 case ImageOp::SoftLight: ITERATE( SoftLight );
break;
9393 case ImageOp::HardLight: ITERATE( HardLight );
break;
9394 case ImageOp::VividLight: ITERATE( VividLight );
break;
9395 case ImageOp::LinearLight: ITERATE( LinearLight );
break;
9396 case ImageOp::PinLight: ITERATE( PinLight );
break;
9397 case ImageOp::Exclusion: ITERATE( Exclusion );
break;
9421 const Point& point =
Point( int_max ),
int channel = -1,
9422 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const
9424 int c0 = (channel < 0) ? m_channel : channel;
9428 (void)result.Apply( image, op,
Point( 0 ), 0, rect, firstChannel, lastChannel );
9468 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 );
9490 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const
9492 GenericImage result( *
this, rect, firstChannel, lastChannel );
9493 (void)result.
Apply( transformation );
9519 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const;
9524 #ifndef __PCL_IMAGE_NO_BITMAP
9579 if ( p.
x == int_max || p.
y == int_max )
9584 if ( (r.
x0 -= p.
x) >= r.
x1 )
9588 else if ( p.
x >= m_width )
9593 if ( (r.
y0 -= p.
y) >= r.
y1 )
9597 else if ( p.
y >= m_height )
9603 bool hasAlpha = HasAlphaChannels();
9611 if ( m_status.IsInitializationEnabled() )
9614 sample* __restrict__ fR =
nullptr;
9615 sample* __restrict__ fG =
nullptr;
9616 sample* __restrict__ fB =
nullptr;
9617 sample* __restrict__ fA =
nullptr;
9619 for (
int i = 0; i < h; ++i, ++p.
y, m_status += w )
9621 fR = PixelAddress( p, 0 );
9622 fG = PixelAddress( p, 1 );
9623 fB = PixelAddress( p, 2 );
9625 fA = PixelAddress( p, 3 );
9629 for (
int j = 0; j < w; ++j, ++fR, ++fG, ++fB, ++fA, ++g )
9633 uint8 A = Alpha( rgba );
9637 P::Mov( *fR, Red( rgba ) );
9638 P::Mov( *fG, Green( rgba ) );
9639 P::Mov( *fB, Blue( rgba ) );
9646 P::Mov( *fR, Red( rgba ) );
9647 P::Mov( *fG, Green( rgba ) );
9648 P::Mov( *fB, Blue( rgba ) );
9652 double k = PTLUT->pDLUTA[A];
9653 double k1 = PTLUT->p1DLUT8[A];
9655 P::FromSample( v, *fR ), P::Mov( *fR, k*Red( rgba ) + k1*v );
9656 P::FromSample( v, *fG ), P::Mov( *fG, k*Green( rgba ) + k1*v );
9657 P::FromSample( v, *fB ), P::Mov( *fB, k*Blue( rgba ) + k1*v );
9665 if ( m_status.IsInitializationEnabled() )
9668 sample* __restrict__ fK =
nullptr;
9669 sample* __restrict__ fA =
nullptr;
9671 for (
int i = 0; i < h; ++i, ++p.
y, m_status += w )
9673 fK = PixelAddress( p, 0 );
9675 fA = PixelAddress( p, 1 );
9679 for (
int j = 0; j < w; ++j, ++fK, ++fA, ++g )
9682 uint8 R = Red( rgba );
9683 uint8 G = Green( rgba );
9684 uint8 B = Blue( rgba );
9685 uint8 A = Alpha( rgba );
9692 P::Mov( *fK, K/255 );
9698 P::Mov( *fK, K/255 );
9702 P::FromSample( v, *fK );
9703 P::Mov( *fK, PTLUT->pDLUTA[A]*K + PTLUT->p1DLUT8[A]*v );
9727 GenericImage result( *
this, Bounds(), 0, m_numberOfChannels-1 );
9728 (void)result.
Blend( bitmap, point, rect );
9732 #endif // !__PCL_IMAGE_NO_BITMAP
9746 template <
typename T>
9749 return Apply( scalar, ImageOp::Mov, rect, firstChannel, lastChannel );
9755 template <
typename T>
9758 return Move( scalar, rect, firstChannel, lastChannel );
9771 template <
typename T>
9774 return Apply( scalar, ImageOp::Add, rect, firstChannel, lastChannel );
9780 template <
typename T>
9783 return Add( scalar );
9796 template <
typename T>
9799 GenericImage result( *
this, rect, firstChannel, lastChannel );
9800 (void)result.
Add( scalar );
9814 template <
typename T>
9817 return Apply( scalar, ImageOp::Sub, rect, firstChannel, lastChannel );
9823 template <
typename T>
9826 return Subtract( scalar, rect, firstChannel, lastChannel );
9832 template <
typename T>
9835 return Subtract( scalar );
9848 template <
typename T>
9851 GenericImage result( *
this, rect, firstChannel, lastChannel );
9866 template <
typename T>
9869 return Apply( scalar, ImageOp::Mul, rect, firstChannel, lastChannel );
9875 template <
typename T>
9878 return Multiply( scalar, rect, firstChannel, lastChannel );
9884 template <
typename T>
9887 return Multiply( scalar );
9900 template <
typename T>
9903 GenericImage result( *
this, rect, firstChannel, lastChannel );
9921 template <
typename T>
9924 return Apply( scalar, ImageOp::Div, rect, firstChannel, lastChannel );
9930 template <
typename T>
9933 return Divide( scalar, rect, firstChannel, lastChannel );
9939 template <
typename T>
9942 return Divide( scalar );
9958 template <
typename T>
9961 GenericImage result( *
this, rect, firstChannel, lastChannel );
9962 (void)result.
Divide( scalar );
9976 template <
typename T>
9979 return Apply( scalar, ImageOp::Pow, rect, firstChannel, lastChannel );
9985 template <
typename T>
9988 return Raise( scalar, rect, firstChannel, lastChannel );
9994 template <
typename T>
9997 return Raise( scalar );
10010 template <
typename T>
10013 GenericImage result( *
this, rect, firstChannel, lastChannel );
10014 (void)result.
Raise( scalar );
10029 template <
typename T>
10032 return Apply( scalar, ImageOp::Dif, rect, firstChannel, lastChannel );
10038 template <
typename T>
10041 return SetAbsoluteDifference( scalar, rect, firstChannel, lastChannel );
10055 template <
typename T>
10058 GenericImage result( *
this, rect, firstChannel, lastChannel );
10073 template <
typename T>
10076 return Apply( scalar, ImageOp::Min, rect, firstChannel, lastChannel );
10082 template <
typename T>
10085 return SetMinimum( scalar, rect, firstChannel, lastChannel );
10099 template <
typename T>
10102 GenericImage result( *
this, rect, firstChannel, lastChannel );
10117 template <
typename T>
10120 return Apply( scalar, ImageOp::Max, rect, firstChannel, lastChannel );
10126 template <
typename T>
10129 return SetMaximum( scalar, rect, firstChannel, lastChannel );
10143 template <
typename T>
10146 GenericImage result( *
this, rect, firstChannel, lastChannel );
10162 template <
typename T>
10165 return Apply( scalar, ImageOp::Or, rect, firstChannel, lastChannel );
10179 template <
typename T>
10182 return Apply( scalar, ImageOp::And, rect, firstChannel, lastChannel );
10196 template <
typename T>
10199 return Apply( scalar, ImageOp::Xor, rect, firstChannel, lastChannel );
10213 template <
typename T>
10216 return Apply( scalar, ImageOp::Nor, rect, firstChannel, lastChannel );
10230 template <
typename T>
10233 return Apply( scalar, ImageOp::Nand, rect, firstChannel, lastChannel );
10247 template <
typename T>
10250 return Apply( scalar, ImageOp::Xnor, rect, firstChannel, lastChannel );
10265 template <
class P1>
10267 const Point& point =
Point( int_max ),
int channel = -1,
10268 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10270 return Apply( image, ImageOp::Mov, point, channel, rect, firstChannel, lastChannel );
10276 template <
class P1>
10278 const Point& point =
Point( int_max ),
int channel = -1,
10279 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10281 return Move( image, point, channel, rect, firstChannel, lastChannel );
10294 template <
class P1>
10296 const Point& point =
Point( int_max ),
int channel = -1,
10297 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10299 return Apply( image, ImageOp::Add, point, channel, rect, firstChannel, lastChannel );
10305 template <
class P1>
10308 return Add( image );
10321 template <
class P1>
10323 const Point& point =
Point( int_max ),
int channel = -1,
10324 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10326 return Apply( image, ImageOp::Sub, point, channel, rect, firstChannel, lastChannel );
10332 template <
class P1>
10334 const Point& point =
Point( int_max ),
int channel = -1,
10335 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10337 return Subtract( image, point, channel, rect, firstChannel, lastChannel );
10343 template <
class P1>
10346 return Subtract( image );
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 )
10364 return Apply( image, ImageOp::Mul, point, channel, rect, firstChannel, lastChannel );
10370 template <
class P1>
10372 const Point& point =
Point( int_max ),
int channel = -1,
10373 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10375 return Multiply( image, point, channel, rect, firstChannel, lastChannel );
10381 template <
class P1>
10384 return Multiply( image );
10401 template <
class P1>
10403 const Point& point =
Point( int_max ),
int channel = -1,
10404 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10406 return Apply( image, ImageOp::Div, point, channel, rect, firstChannel, lastChannel );
10412 template <
class P1>
10414 const Point& point =
Point( int_max ),
int channel = -1,
10415 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10417 return Divide( image, point, channel, rect, firstChannel, lastChannel );
10423 template <
class P1>
10426 return Divide( image );
10440 template <
class P1>
10442 const Point& point =
Point( int_max ),
int channel = -1,
10443 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10445 return Apply( image, ImageOp::Pow, point, channel, rect, firstChannel, lastChannel );
10451 template <
class P1>
10453 const Point& point =
Point( int_max ),
int channel = -1,
10454 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10456 return Raise( image, point, channel, rect, firstChannel, lastChannel );
10462 template <
class P1>
10465 return Raise( image );
10479 template <
class P1>
10481 const Point& point =
Point( int_max ),
int channel = -1,
10482 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10484 return Apply( image, ImageOp::Dif, point, channel, rect, firstChannel, lastChannel );
10490 template <
class P1>
10492 const Point& point =
Point( int_max ),
int channel = -1,
10493 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10495 return SetAbsoluteDifference( image, point, channel, rect, firstChannel, lastChannel );
10509 template <
class P1>
10511 const Point& point =
Point( int_max ),
int channel = -1,
10512 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10514 return Apply( image, ImageOp::Min, point, channel, rect, firstChannel, lastChannel );
10520 template <
class P1>
10522 const Point& point =
Point( int_max ),
int channel = -1,
10523 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10525 return SetMinimum( image, point, channel, rect, firstChannel, lastChannel );
10539 template <
class P1>
10541 const Point& point =
Point( int_max ),
int channel = -1,
10542 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10544 return Apply( image, ImageOp::Max, point, channel, rect, firstChannel, lastChannel );
10550 template <
class P1>
10552 const Point& point =
Point( int_max ),
int channel = -1,
10553 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10555 return SetMaximum( image, point, channel, rect, firstChannel, lastChannel );
10569 template <
class P1>
10571 const Point& point =
Point( int_max ),
int channel = -1,
10572 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10574 return Apply( image, ImageOp::Or, point, channel, rect, firstChannel, lastChannel );
10588 template <
class P1>
10590 const Point& point =
Point( int_max ),
int channel = -1,
10591 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10593 return Apply( image, ImageOp::And, point, channel, rect, firstChannel, lastChannel );
10607 template <
class P1>
10609 const Point& point =
Point( int_max ),
int channel = -1,
10610 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10612 return Apply( image, ImageOp::Xor, point, channel, rect, firstChannel, lastChannel );
10626 template <
class P1>
10628 const Point& point =
Point( int_max ),
int channel = -1,
10629 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10631 return Apply( image, ImageOp::Nor, point, channel, rect, firstChannel, lastChannel );
10645 template <
class P1>
10647 const Point& point =
Point( int_max ),
int channel = -1,
10648 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10650 return Apply( image, ImageOp::Nand, point, channel, rect, firstChannel, lastChannel );
10664 template <
class P1>
10666 const Point& point =
Point( int_max ),
int channel = -1,
10667 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10669 return Apply( image, ImageOp::Xnor, point, channel, rect, firstChannel, lastChannel );
10711 template <
class P1>
10713 const Point& point =
Point( int_max ),
int channel = -1,
10714 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10720 if ( !ParseChannel( channel ) )
10724 if ( p.
x == int_max || p.
y == int_max )
10729 if ( (r.
x0 -= p.
x) >= r.
x1 )
10733 else if ( p.
x >= m_width )
10738 if ( (r.
y0 -= p.
y) >= r.
y1 )
10742 else if ( p.
y >= m_height )
10748 lastChannel =
pcl::Min( lastChannel, firstChannel + m_numberOfChannels - channel - 1 );
10754 if ( m_status.IsInitializationEnabled() )
10755 m_status.Initialize(
"Exchanging pixel samples", N*(1 + lastChannel - firstChannel) );
10757 if ( r == Bounds() && r == image.
Bounds() )
10758 for (
int i = channel, j = firstChannel; j <= lastChannel; ++i, ++j, m_status += N )
10760 sample* __restrict__ f = m_pixelData[i];
10761 typename P1::sample* __restrict__ g = image[j];
10763 for (
size_type k = 0; k < N; ++k, ++f, ++g )
10766 P1::FromSample( *f, *g );
10767 P::FromSample( *g, t );
10771 for (
int i = channel, j = firstChannel, w = r.
Width(), h = r.
Height(); j <= lastChannel; ++i, ++j, m_status += N )
10773 sample* __restrict__ f = PixelAddress( p, i );
10776 for (
int k = 0; k < h; ++k, f += m_width-w, g += image.
Width()-w )
10779 for (
int l = 0; l < w; ++l, ++f, ++g )
10782 P1::FromSample( *f, *g );
10783 P::FromSample( *g, t );
10794 template <
class P1>
10796 const Point& point =
Point( int_max ),
int channel = -1,
10797 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
10799 return Exchange( image, point, channel, rect, firstChannel, lastChannel );
10824 int maxProcessors = 0 )
const
10827 if ( !ParseSelection( r, firstChannel, lastChannel ) )
10831 if ( m_status.IsInitializationEnabled() )
10832 m_status.Initialize(
"Computing minimum pixel sample value", N );
10835 bool useAffinity = m_parallel && Thread::IsRootThread();
10837 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
10838 threads.
Add(
new MinThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
10839 if ( threads.
Length() > 1 )
10842 for ( MinThread& thread : threads )
10843 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
10844 for ( MinThread& thread : threads )
10850 sample min = P::MinSampleValue();
10852 if ( threads[i].count > 0 )
10854 min = threads[i].min;
10855 while ( ++i < threads.
Length() )
10856 if ( threads[i].count > 0 )
10857 if ( threads[i].min < min )
10858 min = threads[i].min;
10873 int maxProcessors = 0 )
const
10875 return MinimumSampleValue( rect, firstChannel, lastChannel, maxProcessors );
10898 int firstChannel = -1,
int lastChannel = -1,
int maxProcessors = 0 )
const
10901 if ( !ParseSelection( r, firstChannel, lastChannel ) )
10905 if ( m_status.IsInitializationEnabled() )
10906 m_status.Initialize(
"Computing maximum pixel sample value", N );
10909 bool useAffinity = m_parallel && Thread::IsRootThread();
10911 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
10912 threads.
Add(
new MaxThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
10913 if ( threads.
Length() > 1 )
10916 for ( MaxThread& thread : threads )
10917 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
10918 for ( MaxThread& thread : threads )
10924 sample max = P::MinSampleValue();
10926 if ( threads[i].count > 0 )
10928 max = threads[i].max;
10929 while ( ++i < threads.
Length() )
10930 if ( threads[i].count > 0 )
10931 if ( max < threads[i].max )
10932 max = threads[i].max;
10947 int maxProcessors = 0 )
const
10949 return MaximumSampleValue( rect, firstChannel, lastChannel, maxProcessors );
10978 template <
typename T>
10980 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
10981 int maxProcessors = 0 )
const
10984 if ( !ParseSelection( r, firstChannel, lastChannel ) )
10987 P::FromSample( min, P::MinSampleValue() );
10993 if ( m_status.IsInitializationEnabled() )
10994 m_status.Initialize(
"Computing extreme pixel sample values", N );
10997 bool useAffinity = m_parallel && Thread::IsRootThread();
10999 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11000 threads.
Add(
new MinMaxThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
11001 if ( threads.
Length() > 1 )
11004 for ( MinMaxThread& thread : threads )
11005 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11006 for ( MinMaxThread& thread : threads )
11012 sample vmin = P::MinSampleValue();
11013 sample vmax = P::MinSampleValue();
11015 if ( threads[i].count > 0 )
11017 vmin = threads[i].min;
11018 vmax = threads[i].max;
11019 while ( ++i < threads.
Length() )
11020 if ( threads[i].count > 0 )
11022 if ( threads[i].min < vmin )
11023 vmin = threads[i].min;
11024 if ( vmax < threads[i].max )
11025 vmax = threads[i].max;
11032 P::FromSample( min, vmin );
11033 P::FromSample( max, vmax );
11042 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11043 int maxProcessors = 0 )
const
11045 GetExtremeSampleValues( min, max, rect, firstChannel, lastChannel, maxProcessors );
11075 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11076 int maxProcessors = 0 )
const
11079 if ( !ParseSelection( r, firstChannel, lastChannel ) )
11083 return P::MinSampleValue();
11087 if ( m_status.IsInitializationEnabled() )
11088 m_status.Initialize(
"Locating minimum pixel sample value", N );
11091 bool useAffinity = m_parallel && Thread::IsRootThread();
11093 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11094 threads.
Add(
new MinPosThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
11095 if ( threads.
Length() > 1 )
11098 for ( MinPosThread& thread : threads )
11099 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11100 for ( MinPosThread& thread : threads )
11107 sample min = P::MinSampleValue();
11109 if ( threads[i].count > 0 )
11111 min = threads[i].min;
11112 xmin = threads[i].pmin.x;
11113 ymin = threads[i].pmin.y;
11114 while ( ++i < threads.
Length() )
11115 if ( threads[i].count > 0 )
11116 if ( threads[i].min < min )
11118 min = threads[i].min;
11119 xmin = threads[i].pmin.x;
11120 ymin = threads[i].pmin.y;
11153 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11154 int maxProcessors = 0 )
const
11156 return LocateMinimumSampleValue( pmin.
x, pmin.
y, rect, firstChannel, lastChannel, maxProcessors );
11165 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11166 int maxProcessors = 0 )
const
11168 return LocateMinimumSampleValue( xmin, ymin, rect, firstChannel, lastChannel, maxProcessors );
11177 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11178 int maxProcessors = 0 )
const
11180 return LocateMinimumSampleValue( pmin, rect, firstChannel, lastChannel, maxProcessors );
11210 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11211 int maxProcessors = 0 )
const
11214 if ( !ParseSelection( r, firstChannel, lastChannel ) )
11218 return P::MaxSampleValue();
11222 if ( m_status.IsInitializationEnabled() )
11223 m_status.Initialize(
"Locating maximum pixel sample value", N );
11226 bool useAffinity = m_parallel && Thread::IsRootThread();
11228 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11229 threads.
Add(
new MaxPosThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
11230 if ( threads.
Length() > 1 )
11233 for ( MaxPosThread& thread : threads )
11234 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11235 for ( MaxPosThread& thread : threads )
11242 sample max = P::MinSampleValue();
11244 if ( threads[i].count > 0 )
11246 max = threads[i].max;
11247 xmax = threads[i].pmax.x;
11248 ymax = threads[i].pmax.y;
11249 while ( ++i < threads.
Length() )
11250 if ( threads[i].count > 0 )
11251 if ( max < threads[i].max )
11253 max = threads[i].max;
11254 xmax = threads[i].pmax.x;
11255 ymax = threads[i].pmax.y;
11288 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11289 int maxProcessors = 0 )
const
11291 return LocateMaximumSampleValue( pmax.
x, pmax.
y, rect, firstChannel, lastChannel, maxProcessors );
11300 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11301 int maxProcessors = 0 )
const
11303 return LocateMaximumSampleValue( xmax, ymax, rect, firstChannel, lastChannel, maxProcessors );
11312 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11313 int maxProcessors = 0 )
const
11315 return LocateMaximumSampleValue( pmax, rect, firstChannel, lastChannel, maxProcessors );
11354 template <
typename T>
11356 int& xmax,
int& ymax, T& max,
11357 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11358 int maxProcessors = 0 )
const
11361 if ( !ParseSelection( r, firstChannel, lastChannel ) )
11364 xmin = ymin = xmax = ymax = 0;
11365 P::FromSample( min, P::MinSampleValue() );
11371 if ( m_status.IsInitializationEnabled() )
11372 m_status.Initialize(
"Locating extreme pixel sample values", N );
11375 bool useAffinity = m_parallel && Thread::IsRootThread();
11377 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11378 threads.
Add(
new MinMaxPosThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
11379 if ( threads.
Length() > 1 )
11382 for ( MinMaxPosThread& thread : threads )
11383 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11384 for ( MinMaxPosThread& thread : threads )
11390 xmin = ymin = xmax = ymax = -1;
11391 sample vmin = P::MinSampleValue();
11392 sample vmax = P::MinSampleValue();
11394 if ( threads[i].count > 0 )
11396 vmin = threads[i].min;
11397 xmin = threads[i].pmin.x;
11398 ymin = threads[i].pmin.y;
11399 vmax = threads[i].max;
11400 xmax = threads[i].pmax.x;
11401 ymax = threads[i].pmax.y;
11402 while ( ++i < threads.
Length() )
11403 if ( threads[i].count > 0 )
11405 if ( threads[i].min < vmin )
11407 vmin = threads[i].min;
11408 xmin = threads[i].pmin.x;
11409 ymin = threads[i].pmin.y;
11411 if ( vmax < threads[i].max )
11413 vmax = threads[i].max;
11414 xmax = threads[i].pmax.x;
11415 ymax = threads[i].pmax.y;
11423 P::FromSample( min, vmin );
11424 P::FromSample( max, vmax );
11454 template <
typename T>
11456 Point& pmax, T& max,
11457 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11458 int maxProcessors = 0 )
const
11460 LocateExtremeSampleValues( pmin.
x, pmin.
y, min,
11461 pmax.
x, pmax.
y, max,
11462 rect, firstChannel, lastChannel, maxProcessors );
11491 int maxProcessors = 0 )
const
11494 if ( !ParseSelection( r, firstChannel, lastChannel ) )
11498 if ( m_status.IsInitializationEnabled() )
11499 m_status.Initialize(
"Counting pixel samples", N );
11501 if ( !this->IsRangeClippingEnabled() )
11508 bool useAffinity = m_parallel && Thread::IsRootThread();
11510 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11511 threads.
Add(
new CountThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
11512 if ( threads.
Length() > 1 )
11515 for ( CountThread& thread : threads )
11516 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11517 for ( CountThread& thread : threads )
11524 for (
const CountThread& thread : threads )
11525 count += thread.count;
11560 double Mean(
const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11561 int maxProcessors = 0 )
const
11564 if ( !ParseSelection( r, firstChannel, lastChannel ) )
11568 if ( m_status.IsInitializationEnabled() )
11569 m_status.Initialize(
"Computing mean pixel sample value", N );
11572 bool useAffinity = m_parallel && Thread::IsRootThread();
11574 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11575 threads.
Add(
new SumThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
11576 if ( threads.
Length() > 1 )
11579 for ( SumThread& thread : threads )
11580 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
11581 for ( SumThread& thread : threads )
11590 for (
const SumThread& thread : threads )
11592 double y = thread.s - e;
11633 double Median(
const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11634 int maxProcessors = 0 )
const
11637 if ( !ParseSelection( r, firstChannel, lastChannel ) )
11641 if ( m_status.IsInitializationEnabled() )
11642 m_status.Initialize(
"Computing median pixel sample value", N );
11644 if ( N <= 2560000 )
11646 SmpThread S( *
this, r, firstChannel, lastChannel, 0, r.
Height() );
11653 double m = double( *
pcl::Select( S.samples.Begin(), S.samples.At( S.n ), S.n >> 1 ) )/double( P::MaxSampleValue() );
11659 m = (m + double( *
pcl::Select( S.samples.Begin(), S.samples.At( S.n ), (S.n >> 1)-1 ) )/double( P::MaxSampleValue() ))/2;
11665 bool useAffinity = m_parallel && Thread::IsRootThread();
11671 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11672 threads <<
new MinMaxThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) );
11674 if ( threads.
Length() > 1 )
11677 for ( MinMaxThread& thread : threads )
11678 thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
11679 for ( MinMaxThread& thread : threads )
11685 sample slow = 0, shigh = 0;
11687 if ( threads[i].count > 0 )
11689 slow = threads[i].min;
11690 shigh = threads[i].max;
11691 count = threads[i].count;
11692 while ( ++i < threads.
Length() )
11693 if ( threads[i].count > 0 )
11695 if ( threads[i].min < slow )
11696 slow = threads[i].min;
11697 if ( shigh < threads[i].max )
11698 shigh = threads[i].max;
11699 count += threads[i].count;
11706 low = double( slow );
11707 high = double( shigh );
11710 const double eps = P::IsComplexSample() ? 2*std::numeric_limits<double>::epsilon() :
11711 (P::IsFloatSample() ? 2*std::numeric_limits<typename P::component>::epsilon() :
11712 0.5/
Pow2(
double( P::BitsPerSample() ) ));
11718 if ( high - low < eps )
11721 return low/double( P::MaxSampleValue() );
11725 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11726 threads <<
new HistogramThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ), low, high );
11728 double mh = 0, l0 = low, h0 = high;
11731 for (
size_type n = 0, n2 = count >> 1, step = 0, it = 0;; ++it )
11734 if ( it == 0 && step )
11738 if ( threads.
Length() > 1 )
11741 for ( HistogramThread& thread : threads )
11742 thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
11743 for ( HistogramThread& thread : threads )
11753 if ( (count & 1) == 0 )
11757 for (
int i = 0; ; n += H[i++] )
11758 if ( n + H[i] > n2 )
11760 double range = high - low;
11761 high = (range * (i + 1))/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
11762 low = (range * i)/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
11763 if ( high - low < eps )
11769 return low/double( P::MaxSampleValue() );
11775 return (low + mh)/2/double( P::MaxSampleValue() );
11822 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
11823 int maxProcessors = 0 )
const
11825 if ( k < 0 || k > 1 )
11829 if ( !ParseSelection( r, firstChannel, lastChannel ) )
11833 if ( m_status.IsInitializationEnabled() )
11834 m_status.Initialize(
"Computing order statistic", N );
11836 if ( N <= 2560000 )
11838 SmpThread S( *
this, r, firstChannel, lastChannel, 0, r.
Height() );
11843 return double( *
pcl::Select( S.samples.Begin(), S.samples.At( S.n ),
distance_type( k*(S.n - 1) ) ) )/double( P::MaxSampleValue() );
11847 bool useAffinity = m_parallel && Thread::IsRootThread();
11853 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11854 threads <<
new MinMaxThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) );
11856 if ( threads.
Length() > 1 )
11859 for ( MinMaxThread& thread : threads )
11860 thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
11861 for ( MinMaxThread& thread : threads )
11867 sample slow = 0, shigh = 0;
11869 if ( threads[i].count > 0 )
11871 slow = threads[i].min;
11872 shigh = threads[i].max;
11873 count = threads[i].count;
11874 while ( ++i < threads.
Length() )
11875 if ( threads[i].count > 0 )
11877 if ( threads[i].min < slow )
11878 slow = threads[i].min;
11879 if ( shigh < threads[i].max )
11880 shigh = threads[i].max;
11881 count += threads[i].count;
11888 low = double( slow );
11889 high = double( shigh );
11892 const double eps = P::IsComplexSample() ? 2*std::numeric_limits<double>::epsilon() :
11893 (P::IsFloatSample() ? 2*std::numeric_limits<typename P::component>::epsilon() :
11894 0.5/
Pow2(
double( P::BitsPerSample() ) ));
11900 if ( k == 0 || high - low < eps )
11903 return low/double( P::MaxSampleValue() );
11908 return high/double( P::MaxSampleValue() );
11914 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
11915 threads <<
new HistogramThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ), low, high );
11919 if ( threads.
Length() > 1 )
11922 for ( HistogramThread& thread : threads )
11923 thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
11924 for ( HistogramThread& thread : threads )
11934 for (
int i = 0; ; n += H[i++] )
11935 if ( n + H[i] > index )
11937 double range = high - low;
11938 high = (range * (i + 1))/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
11939 low = (range * i)/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
11940 if ( high - low < eps )
11944 return low/double( P::MaxSampleValue() );
11986 int maxProcessors = 0 )
const
11989 if ( !ParseSelection( r, firstChannel, lastChannel ) )
11993 if ( m_status.IsInitializationEnabled() )
11994 m_status.Initialize(
"Computing variance", N );
11997 bool useAffinity = m_parallel && Thread::IsRootThread();
11999 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12000 sumThreads.
Add(
new SumThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
12001 if ( sumThreads.
Length() > 1 )
12004 for ( SumThread& thread : sumThreads )
12005 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12006 for ( SumThread& thread : sumThreads )
12010 sumThreads[0].Run();
12015 for (
const SumThread& thread : sumThreads )
12017 double y = thread.s - e;
12031 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12032 varThreads.
Add(
new VarThread( *
this, mean, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
12033 if ( varThreads.
Length() > 1 )
12036 for ( VarThread& thread : varThreads )
12037 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12038 for ( VarThread& thread : varThreads )
12042 varThreads[0].Run();
12044 double var = 0, eps = 0;
12045 for (
const VarThread& thread : varThreads )
12046 var += thread.var, eps += thread.eps;
12050 return (var - eps*eps/n)/(n - 1);
12085 double StdDev(
const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
12086 int maxProcessors = 0 )
const
12088 return pcl::Sqrt(
Variance( rect, firstChannel, lastChannel, maxProcessors ) );
12131 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
12132 int maxProcessors = 0 )
const
12135 if ( !ParseSelection( r, firstChannel, lastChannel ) )
12139 if ( m_status.IsInitializationEnabled() )
12140 m_status.Initialize(
"Computing average absolute deviation", N );
12143 bool useAffinity = m_parallel && Thread::IsRootThread();
12145 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12146 threads.
Add(
new SumAbsDevThread( *
this, center, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
12147 if ( threads.
Length() > 1 )
12150 for ( SumAbsDevThread& thread : threads )
12151 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12152 for ( SumAbsDevThread& thread : threads )
12161 for (
const SumAbsDevThread& thread : threads )
12163 double y = thread.s - e;
12200 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
12201 int maxProcessors = 0 )
const
12204 if ( !ParseSelection( r, firstChannel, lastChannel ) )
12208 if ( m_status.IsInitializationEnabled() )
12209 m_status.Initialize(
"Computing two-sided average absolute deviation", N );
12212 bool useAffinity = m_parallel && Thread::IsRootThread();
12214 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12215 threads.
Add(
new TwoSidedSumAbsDevThread( *
this, center, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
12216 if ( threads.
Length() > 1 )
12219 for ( TwoSidedSumAbsDevThread& thread : threads )
12220 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12221 for ( TwoSidedSumAbsDevThread& thread : threads )
12227 double s0 = 0, s1 = 0;
12228 double e0 = 0, e1 = 0;
12230 for (
const TwoSidedSumAbsDevThread& thread : threads )
12232 double y = thread.s0 - e0;
12237 y = thread.s1 - e1;
12248 return { (n0 > 0) ? s0/n0 : 0.0,
12249 (n1 > 0) ? s1/n1 : 0.0 };
12287 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
12288 int maxProcessors = 0 )
const
12291 if ( !ParseSelection( r, firstChannel, lastChannel ) )
12295 if ( m_status.IsInitializationEnabled() )
12296 m_status.Initialize(
"Computing median absolute deviation", N );
12298 if ( N <= 2560000 )
12300 AbsDevSmpThread S( *
this, center, r, firstChannel, lastChannel, 0, r.
Height() );
12307 double m = *
pcl::Select( S.values.Begin(), S.values.At( S.n ), S.n >> 1 );
12313 m = (m + *
pcl::Select( S.values.Begin(), S.values.At( S.n ), (S.n >> 1)-1 ))/2;
12319 bool useAffinity = m_parallel && Thread::IsRootThread();
12325 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12326 threads <<
new ExtremeAbsDevThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ), center );
12328 if ( threads.
Length() > 1 )
12331 for ( ExtremeAbsDevThread& thread : threads )
12332 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12333 for ( ExtremeAbsDevThread& thread : threads )
12340 if ( threads[i].count > 0 )
12342 low = threads[i].minAbsDev;
12343 high = threads[i].maxAbsDev;
12344 count += threads[i].count;
12345 while ( ++i < threads.
Length() )
12346 if ( threads[i].count > 0 )
12348 if ( threads[i].minAbsDev < low )
12349 low = threads[i].minAbsDev;
12350 if ( threads[i].maxAbsDev > high )
12351 high = threads[i].maxAbsDev;
12352 count += threads[i].count;
12360 const double eps = 2*std::numeric_limits<double>::epsilon();
12361 if ( count == 0 || high - low < eps )
12368 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12369 threads <<
new AbsDevHistogramThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ), center, low, high );
12371 double mh = 0, l0 = low, h0 = high;
12374 for (
size_type n = 0, n2 = count >> 1, step = 0, it = 0;; ++it )
12377 if ( it == 0 && step )
12381 if ( threads.
Length() > 1 )
12384 for ( AbsDevHistogramThread& thread : threads )
12385 thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
12386 for ( AbsDevHistogramThread& thread : threads )
12396 if ( (count & 1) == 0 )
12400 for (
int i = 0; ; n += H[i++] )
12401 if ( n + H[i] > n2 )
12403 double range = high - low;
12404 high = (range * (i + 1))/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
12405 low = (range * i)/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + low;
12406 if ( high - low < eps )
12418 return (low + mh)/2;
12454 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
12455 int maxProcessors = 0 )
const
12458 if ( !ParseSelection( r, firstChannel, lastChannel ) )
12462 if ( m_status.IsInitializationEnabled() )
12463 m_status.Initialize(
"Computing two-sided median absolute deviation", N );
12465 if ( N <= 2560000 )
12467 TwoSidedAbsDevSmpThread S( *
this, center, r, firstChannel, lastChannel, 0, r.
Height() );
12475 bool useAffinity = m_parallel && Thread::IsRootThread();
12477 double minLow = 0, minHigh = 0, maxLow = 0, maxHigh = 0;
12481 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12482 threads <<
new TwoSidedExtremeAbsDevThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ), center );
12484 if ( threads.
Length() > 1 )
12487 for ( TwoSidedExtremeAbsDevThread& thread : threads )
12488 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12489 for ( TwoSidedExtremeAbsDevThread& thread : threads )
12496 if ( threads[i].nLow > 0 )
12498 minLow = threads[i].minAbsDevLow;
12499 maxLow = threads[i].maxAbsDevLow;
12500 nLow = threads[i].nLow;
12501 while ( ++i < threads.
Length() )
12502 if ( threads[i].nLow > 0 )
12504 if ( threads[i].minAbsDevLow < minLow )
12505 minLow = threads[i].minAbsDevLow;
12506 if ( threads[i].maxAbsDevLow > maxLow )
12507 maxLow = threads[i].maxAbsDevLow;
12508 nLow += threads[i].nLow;
12514 if ( threads[i].nHigh > 0 )
12516 minHigh = threads[i].minAbsDevHigh;
12517 maxHigh = threads[i].maxAbsDevHigh;
12518 nHigh = threads[i].nHigh;
12519 while ( ++i < threads.
Length() )
12520 if ( threads[i].nHigh > 0 )
12522 if ( threads[i].minAbsDevHigh < minHigh )
12523 minHigh = threads[i].minAbsDevHigh;
12524 if ( threads[i].maxAbsDevHigh > maxHigh )
12525 maxHigh = threads[i].maxAbsDevHigh;
12526 nHigh += threads[i].nHigh;
12535 double sideLow, sideHigh;
12537 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12538 threads <<
new TwoSidedAbsDevHistogramThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ), center, side, sideLow, sideHigh );
12540 const double eps = 2*std::numeric_limits<double>::epsilon();
12542 for ( side = 0; side < 2; ++side )
12551 sideLow = side ? minHigh : minLow;
12552 sideHigh = side ? maxHigh : maxLow;
12553 if ( sideHigh - sideLow < eps )
12559 double mh = 0, h0 = sideHigh;
12562 for (
size_type count = 0, n2 = n >> 1, step = 0, it = 0;; ++it )
12565 if ( it == 0 && step )
12569 if ( threads.
Length() > 1 )
12572 for ( TwoSidedAbsDevHistogramThread& thread : threads )
12573 thread.Start( ThreadPriority::DefaultMax, useAffinity ? i++ : -1 );
12574 for ( TwoSidedAbsDevHistogramThread& thread : threads )
12584 if ( (n & 1) == 0 )
12588 for (
int i = 0; ; count += H[i++] )
12589 if ( count + H[i] > n2 )
12591 double range = sideHigh - sideLow;
12592 sideHigh = (range * (i + 1))/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + sideLow;
12593 sideLow = (range * i)/(__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) + sideLow;
12594 if ( sideHigh - sideLow < eps )
12598 mad[side] = sideLow;
12599 goto __madNextSide;
12603 mad[side] = (sideLow + mh)/2;
12604 goto __madNextSide;
12624 return { mad[0], mad[1] };
12672 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
12673 int maxProcessors = 0 )
const
12676 if ( !ParseSelection( r, firstChannel, lastChannel ) )
12680 double kd = k * sigma;
12681 if ( kd < 0 || 1 + kd == 1 )
12687 if ( m_status.IsInitializationEnabled() )
12688 m_status.Initialize(
"Computing biweight midvariance", N );
12691 bool useAffinity = m_parallel && Thread::IsRootThread();
12693 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12694 threads.
Add(
new BWMVThread( *
this, center, kd, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
12695 if ( threads.
Length() > 1 )
12698 for ( BWMVThread& thread : threads )
12699 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12700 for ( BWMVThread& thread : threads )
12706 double num = 0, den = 0;
12708 for (
const BWMVThread& thread : threads )
12720 return (n >= 2 && 1 + den != 1) ? (reducedLength ? nr : n)*num/den : 0.0;
12752 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
12753 int maxProcessors = 0 )
const
12756 if ( !ParseSelection( r, firstChannel, lastChannel ) )
12760 double kd0 = k * sigma.
low;
12761 double kd1 = k * sigma.
high;
12762 if ( kd0 < 0 || 1 + kd0 == 1 || kd1 < 0 || 1 + kd1 == 1 )
12768 if ( m_status.IsInitializationEnabled() )
12769 m_status.Initialize(
"Computing two-sided biweight midvariance", N );
12772 bool useAffinity = m_parallel && Thread::IsRootThread();
12774 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12775 threads.
Add(
new TwoSidedBWMVThread( *
this, center, kd0, kd1, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
12776 if ( threads.
Length() > 1 )
12779 for ( TwoSidedBWMVThread& thread : threads )
12780 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12781 for ( TwoSidedBWMVThread& thread : threads )
12787 double num0 = 0, den0 = 0, num1 = 0, den1 = 0;
12788 size_type n0 = 0, n1 = 0, nr0 = 0, nr1 = 0;
12789 for (
const TwoSidedBWMVThread& thread : threads )
12791 num0 += thread.num0;
12792 den0 += thread.den0;
12793 num1 += thread.num1;
12794 den1 += thread.den1;
12807 return { (n0 >= 2 && 1 + den0 != 1) ? (reducedLength ? nr0 : n0)*num0/den0 : 0.0,
12808 (n1 >= 2 && 1 + den1 != 1) ? (reducedLength ? nr1 : n1)*num1/den1 : 0.0 };
12855 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
12856 int maxProcessors = 0 )
const
12859 if ( !ParseSelection( r, firstChannel, lastChannel ) )
12863 if ( m_status.IsInitializationEnabled() )
12864 m_status.Initialize(
"Computing percentage bend midvariance", N );
12867 bool useAffinity = m_parallel && Thread::IsRootThread();
12869 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12870 threads.
Add(
new DSmpThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
12871 if ( threads.
Length() > 1 )
12874 for ( DSmpThread& thread : threads )
12875 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12876 for ( DSmpThread& thread : threads )
12883 for ( DSmpThread& thread : threads )
12884 if ( !thread.values.IsEmpty() )
12886 values.
Add( thread.values.Begin(), thread.values.At( thread.n ) );
12887 thread.values.Clear();
12940 double Sn(
const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
int maxProcessors = 0 )
const
12943 if ( !ParseSelection( r, firstChannel, lastChannel ) )
12947 if ( m_status.IsInitializationEnabled() )
12948 m_status.Initialize(
"Computing Sn scale estimate", N );
12951 bool useAffinity = m_parallel && Thread::IsRootThread();
12953 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
12954 threads.
Add(
new DSmpThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
12955 if ( threads.
Length() > 1 )
12958 for ( DSmpThread& thread : threads )
12959 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
12960 for ( DSmpThread& thread : threads )
12967 for ( DSmpThread& thread : threads )
12968 if ( !thread.values.IsEmpty() )
12970 values.
Add( thread.values.Begin(), thread.values.At( thread.n ) );
12971 thread.values.Clear();
13023 double Qn(
const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
int maxProcessors = 0 )
const
13026 if ( !ParseSelection( r, firstChannel, lastChannel ) )
13030 if ( m_status.IsInitializationEnabled() )
13031 m_status.Initialize(
"Computing Qn scale estimate", N );
13034 bool useAffinity = m_parallel && Thread::IsRootThread();
13036 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13037 threads.
Add(
new DSmpThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
13038 if ( threads.
Length() > 1 )
13041 for ( DSmpThread& thread : threads )
13042 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13043 for ( DSmpThread& thread : threads )
13050 for ( DSmpThread& thread : threads )
13051 if ( !thread.values.IsEmpty() )
13053 values.
Add( thread.values.Begin(), thread.values.At( thread.n ) );
13054 thread.values.Clear();
13101 double Norm(
const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1,
13102 int maxProcessors = 0 )
const
13105 if ( !ParseSelection( r, firstChannel, lastChannel ) )
13109 if ( m_status.IsInitializationEnabled() )
13110 m_status.Initialize(
"Computing norm", N );
13113 bool useAffinity = m_parallel && Thread::IsRootThread();
13115 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13116 threads.
Add(
new SumThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
13117 if ( threads.
Length() > 1 )
13120 for ( SumThread& thread : threads )
13121 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13122 for ( SumThread& thread : threads )
13130 for (
const SumThread& thread : threads )
13132 double y = thread.s - e;
13140 return (1 + s != 1) ? s : 0.0;
13174 int maxProcessors = 0 )
const
13177 if ( !ParseSelection( r, firstChannel, lastChannel ) )
13181 if ( m_status.IsInitializationEnabled() )
13182 m_status.Initialize(
"Computing modulus", N );
13185 bool useAffinity = m_parallel && Thread::IsRootThread();
13187 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13188 threads.
Add(
new SumAbsThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
13189 if ( threads.
Length() > 1 )
13192 for ( SumAbsThread& thread : threads )
13193 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13194 for ( SumAbsThread& thread : threads )
13202 for (
const SumAbsThread& thread : threads )
13204 double y = thread.s - e;
13212 return (1 + s != 1) ? s : 0.0;
13244 int maxProcessors = 0 )
const
13247 if ( !ParseSelection( r, firstChannel, lastChannel ) )
13251 if ( m_status.IsInitializationEnabled() )
13252 m_status.Initialize(
"Computing sum of squares", N );
13255 bool useAffinity = m_parallel && Thread::IsRootThread();
13257 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13258 threads.
Add(
new SumSqrThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
13259 if ( threads.
Length() > 1 )
13262 for ( SumSqrThread& thread : threads )
13263 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13264 for ( SumSqrThread& thread : threads )
13272 for (
const SumSqrThread& thread : threads )
13274 double y = thread.s - e;
13282 return (1 + s != 1) ? s : 0.0;
13314 int maxProcessors = 0 )
const
13317 if ( !ParseSelection( r, firstChannel, lastChannel ) )
13321 if ( m_status.IsInitializationEnabled() )
13322 m_status.Initialize(
"Computing mean of squares", N );
13325 bool useAffinity = m_parallel && Thread::IsRootThread();
13327 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13328 threads.
Add(
new SumSqrThread( *
this, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
13329 if ( threads.
Length() > 1 )
13332 for ( SumSqrThread& thread : threads )
13333 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13334 for ( SumSqrThread& thread : threads )
13343 for (
const SumSqrThread& thread : threads )
13345 double y = thread.s - e;
13399 int maxProcessors = 0 )
const
13401 PCL_PRECONDITION( maxDegree > 0 )
13402 maxDegree =
pcl::Max( 1, maxDegree );
13405 if ( !ParseSelection( r, firstChannel, lastChannel ) )
13409 if ( m_status.IsInitializationEnabled() )
13410 m_status.Initialize(
"Computing norms", N );
13413 bool useAffinity = m_parallel && Thread::IsRootThread();
13415 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
13416 threads.
Add(
new NormThread( *
this, maxDegree, r, firstChannel, lastChannel, n, n +
int( L[i] ) ) );
13417 if ( threads.
Length() > 1 )
13420 for ( NormThread& thread : threads )
13421 thread.Start( ThreadPriority::DefaultMax, useAffinity ? n++ : -1 );
13422 for ( NormThread& thread : threads )
13428 Vector R( 0.0, maxDegree );
13429 Vector e( 0.0, maxDegree );
13430 for (
const NormThread& thread : threads )
13431 for (
int i = 0; i < maxDegree; ++i )
13433 double y = thread.R[i] - e[i];
13434 double t = R[i] + y;
13435 e[i] = (t - R[i]) - y;
13438 for (
int i = 0; i < maxDegree; ++i )
13439 if ( 1 + R[i] == 1 )
13461 if ( !ParseChannel( channel ) )
13463 return pcl::Hash64( m_channelData( channel ), ChannelSize(), seed );
13480 if ( !ParseChannel( channel ) )
13482 return pcl::Hash32( m_channelData( channel ), ChannelSize(), seed );
13491 return Hash64( channel, seed );
13516 if ( !ParseSelection( r, firstChannel, lastChannel ) )
13520 int numberOfChannels = 1 + lastChannel - firstChannel;
13522 if ( m_status.IsInitializationEnabled() )
13523 m_status.Initialize(
"Writing to raw-storage image stream", N*numberOfChannels );
13528 file.
WriteUI32( (firstChannel == 0 && lastChannel >= 2) ? m_colorSpace : ColorSpace::Gray );
13530 if ( r == Bounds() )
13532 for (
int i = firstChannel; i <= lastChannel; ++i, m_status += N )
13533 file.
Write( (
const void*)m_pixelData[i],
fsize_type( ChannelSize() ) );
13537 for (
int i = firstChannel, w = r.
Width(), h = r.
Height(); i <= lastChannel; ++i )
13540 for (
int j = 0; j < h; ++j, p += m_width, m_status += w )
13541 file.
Write( (
const void*)p, w*BytesPerSample() );
13559 const Rect& rect =
Rect( 0 ),
int firstChannel = -1,
int lastChannel = -1 )
const
13561 File file = File::CreateFileForWriting( filePath );
13562 return Write( file, rect, firstChannel, lastChannel );
13603 int width, height, numberOfChannels, colorSpace;
13606 file.
ReadUI32( numberOfChannels );
13609 AllocateData( width, height, numberOfChannels, color_space( colorSpace ) );
13616 if ( m_status.IsInitializationEnabled() )
13617 m_status.Initialize(
"Reading from raw-storage image stream", N*m_numberOfChannels );
13618 for (
int i = 0; i < m_numberOfChannels; ++i, m_status += N )
13619 file.
Read( (
void*)m_pixelData[i],
fsize_type( ChannelSize() ) );
13638 File file = File::OpenFileForReading( filePath );
13639 return Read( file );
13674 template <
typename T>
13677 if ( left == 0 && top == 0 && right == 0 && bottom == 0 )
13680 if ( m_width+left+right <= 0 || m_height+top+bottom <= 0 )
13686 Rect r( -left, -top, m_width+right, m_height+bottom );
13687 int width = r.
Width();
13688 int height = r.
Height();
13690 if ( !Intersects( r ) )
13691 return AllocateData( width, height, m_numberOfChannels, m_colorSpace ).Fill( fillValues );
13697 if ( m_status.IsInitializationEnabled() )
13698 m_status.Initialize(
String().Format(
"Crop margins: %+d, %+d, %+d, %+d",
13699 left, top, right, bottom ), N*m_numberOfChannels );
13701 sample** newData =
nullptr;
13705 newData = m_allocator.AllocateChannelSlots( m_numberOfChannels );
13707 for (
int c = 0; c < m_numberOfChannels; ++c, m_status += N )
13709 sample* __restrict__ f = newData[c] = m_allocator.AllocatePixels( N );
13710 sample v = (c < fillValues.
Length()) ? P::ToSample( fillValues[c] ) : P::MinSampleValue();
13712 for (
int i = r.
y0, j; i < r.
y1; )
13714 for ( ; i < 0; ++i )
13717 for (
int j = 0; j < width; ++j )
13722 for ( j = r.
x0; j < 0; ++j )
13725 for (
const sample* f0 = PixelAddress( j, i, c ); j < r.
x1; )
13728 if ( ++j == m_width )
13731 for ( ; j < r.
x1; ++j )
13736 if ( ++i == m_height )
13737 for ( ; i < r.
y1; ++i )
13740 for (
int j = 0; j < width; ++j )
13748 for (
int c = 0; c < m_numberOfChannels; ++c )
13750 m_allocator.Deallocate( m_pixelData[c] );
13751 m_pixelData[c] = newData[c];
13753 m_allocator.Deallocate( newData );
13756 m_allocator.SetSharedGeometry( m_width = width, m_height = height, m_numberOfChannels );
13764 m_data->Deallocate();
13771 if ( newData !=
nullptr )
13773 for (
int i = 0; i < m_numberOfChannels; ++i )
13774 if ( newData[i] !=
nullptr )
13775 m_allocator.Deallocate( newData[i] ), newData[i] =
nullptr;
13776 m_allocator.Deallocate( newData );
13795 return CropBy( left, top, right, bottom,
sample_vector() );
13808 template <
typename T>
13812 return CropBy( -r.
x0, -r.
y0, r.
x1 - m_width, r.
y1 - m_height, fillValues );
13841 template <
typename T>
13844 return CropTo(
Rect( x0, y0, x1, y1 ), fillValues );
13873 template <
typename T>
13876 return CropTo( m_rectangle, fillValues );
13916 template <
typename T>
13919 return CropBy( dx, dy, -dx, -dy, fillValues );
13944 template <
typename T>
13947 return ShiftBy( x, y, fillValues );
13976 template <
typename T>
13979 return ShiftBy( p.
x, p.
y, fillValues );
14002 template <
typename T>
14005 int dx2 = (width - m_width) >> 1;
14006 int dy2 = (height - m_height) >> 1;
14007 return CropBy( dx2, dy2, width-m_width-dx2, height-m_height-dy2, fillValues );
14031 template <
typename T>
14034 int dx = width - m_width;
14035 int dy = height - m_height;
14036 return CropBy( 0, 0, dx, dy, fillValues );
14060 template <
typename T>
14063 int dx = width - m_width;
14064 int dy = height - m_height;
14065 return CropBy( dx, 0, 0, dy, fillValues );
14089 template <
typename T>
14092 int dx = width - m_width;
14093 int dy = height - m_height;
14094 return CropBy( 0, dy, dx, 0, fillValues );
14111 return ShiftToBottomLeft( width, height,
sample_vector() );
14118 template <
typename T>
14121 int dx = width - m_width;
14122 int dy = height - m_height;
14123 return CropBy( dx, dy, 0, 0, fillValues );
14140 return ShiftToBottomRight( width, height,
sample_vector() );
14153 template <
typename T>
14156 return ShiftTo( m_point, fillValues );
14216 if ( colorSpace == m_colorSpace )
14224 if ( m_status.IsInitializationEnabled() )
14225 m_status.Initialize(
"In-place color space conversion: "
14230 int n = m_numberOfChannels;
14232 if ( m_colorSpace == ColorSpace::Gray )
14234 sample** oldData = m_pixelData;
14235 sample** newData =
nullptr;
14240 newData = m_allocator.AllocateChannelSlots( 2+n );
14243 newData[0] = oldData[0];
14246 newData[1] = m_allocator.AllocatePixels( N );
14247 ::memcpy( newData[1], oldData[0], ChannelSize() );
14248 newData[2] = m_allocator.AllocatePixels( N );
14249 ::memcpy( newData[2], oldData[0], ChannelSize() );
14252 for (
int i = 1; i < n; ++i )
14253 newData[i+2] = oldData[i];
14257 m_pixelData = newData;
14259 m_numberOfChannels += 2;
14260 m_colorSpace = ColorSpace::RGB;
14261 m_data->UpdateSharedImage();
14263 ResetChannelRange();
14265 m_allocator.Deallocate( oldData );
14269 m_data->Deallocate();
14276 if ( newData !=
nullptr )
14278 newData[0] =
nullptr;
14279 if ( newData[1] !=
nullptr )
14280 m_allocator.Deallocate( newData[1] ), newData[1] =
nullptr;
14281 if ( newData[2] !=
nullptr )
14282 m_allocator.Deallocate( newData[2] ), newData[2] =
nullptr;
14283 m_allocator.Deallocate( newData );
14288 if ( colorSpace == ColorSpace::RGB )
14299 m_parallel ? ((maxProcessors > 0) ? maxProcessors : m_maxProcessors) : 1 );
14302 for (
size_type i = 0, n = 0; i < L.Length(); n += L[i++] )
14303 threads.
Add(
new ColorSpaceConversionThread( *
this, data, colorSpace, n, n + L[i] ) );
14304 RunThreads( threads, data );
14309 if ( colorSpace == ColorSpace::Gray )
14311 sample** oldData = m_pixelData;
14312 sample** newData =
nullptr;
14316 newData = m_allocator.AllocateChannelSlots( n-2 );
14317 newData[0] = oldData[0];
14318 for (
int i = 3; i < n; ++i )
14319 newData[i-2] = oldData[i];
14321 m_pixelData = newData;
14323 m_numberOfChannels -= 2;
14324 m_colorSpace = ColorSpace::Gray;
14325 m_data->UpdateSharedImage();
14327 ResetChannelRange();
14329 m_allocator.Deallocate( oldData[1] );
14330 m_allocator.Deallocate( oldData[2] );
14331 m_allocator.Deallocate( oldData );
14335 m_data->Deallocate();
14337 if ( newData !=
nullptr )
14338 m_allocator.Deallocate( newData );
14344 m_allocator.SetSharedColor( m_colorSpace = colorSpace, m_RGBWS );
14417 template <
class P1>
14421 if ( !ParseRect( r ) )
14427 Y.AllocateData( r );
14428 if ( !Y.IsShared() )
14429 Y.SetRGBWorkingSpace( m_RGBWS );
14433 if ( m_colorSpace == ColorSpace::Gray || m_colorSpace == ColorSpace::CIEXYZ )
14435 if ( m_status.IsInitializationEnabled() )
14436 m_status.Initialize(
"Transferring pixel data", N );
14439 int cY = (m_colorSpace == ColorSpace::Gray) ? 0 : 1;
14440 if ( r == Bounds() )
14442 const sample* __restrict__ f = m_pixelData[cY];
14443 P1::Copy( g, f, N );
14447 const sample* __restrict__ f = PixelAddress( r.
LeftTop(), cY );
14448 for (
int i = 0; i < Y.Height(); ++i, f += m_width, g += Y.Width() )
14449 P1::Copy( g, f, Y.Width() );
14456 if ( m_status.IsInitializationEnabled() )
14457 m_status.Initialize(
"Computing CIE Y component", N );
14459 Array<size_type> L = OptimalThreadRows( Y.Height(), Y.Width(), maxProcessors );
14462 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
14463 threads.
Add(
new GetLuminanceThread<P1>( Y, *
this, data, r, n, n +
int( L[i] ) ) );
14464 RunThreads( threads, data );
14480 void GetLuminance(
ImageVariant& Y,
const Rect& rect =
Rect( 0 ),
int maxProcessors = 0 )
const;
14549 template <
class P1>
14553 if ( !ParseRect( r ) )
14559 L.AllocateData( r );
14560 if ( !L.IsShared() )
14561 L.SetRGBWorkingSpace( m_RGBWS );
14565 if ( m_colorSpace == ColorSpace::Gray || m_colorSpace == ColorSpace::CIELab || m_colorSpace == ColorSpace::CIELch )
14567 if ( m_status.IsInitializationEnabled() )
14568 m_status.Initialize(
"Transferring pixel data", N );
14571 if ( r == Bounds() )
14573 const sample* __restrict__ f = *m_pixelData;
14574 P1::Copy( g, f, N );
14578 const sample* __restrict__ f = PixelAddress( r.
LeftTop() );
14579 for (
int i = 0; i < L.Height(); ++i, f += m_width, g += L.Width() )
14580 P1::Copy( g, f, L.Width() );
14587 if ( m_status.IsInitializationEnabled() )
14588 m_status.Initialize(
"Computing CIE L* component", N );
14590 Array<size_type> R = OptimalThreadRows( L.Height(), L.Width(), maxProcessors );
14593 for (
int i = 0, n = 0; i < int( R.Length() ); n += int( R[i++] ) )
14594 threads.
Add(
new GetLightnessThread<P1>( L, *
this, data, r, n, n +
int( R[i] ) ) );
14595 RunThreads( threads, data );
14611 void GetLightness(
ImageVariant& L,
const Rect& rect =
Rect( 0 ),
int maxProcessors = 0 )
const;
14672 template <
class P1>
14676 if ( !ParseRect( r ) )
14682 I.AllocateData( r );
14683 if ( !I.IsShared() )
14684 I.SetRGBWorkingSpace( m_RGBWS );
14688 if ( m_colorSpace == ColorSpace::Gray || m_colorSpace == ColorSpace::HSI )
14690 if ( m_status.IsInitializationEnabled() )
14691 m_status.Initialize(
"Transferring pixel data", N );
14694 int cI = (m_colorSpace == ColorSpace::Gray) ? 0 : 2;
14695 if ( r == Bounds() )
14697 const sample* __restrict__ f = m_pixelData[cI];
14698 P1::Copy( g, f, N );
14702 const sample* __restrict__ f = PixelAddress( r.
LeftTop(), cI );
14703 for (
int i = 0; i < I.Height(); ++i, f += m_width, g += I.Width() )
14704 P1::Copy( g, f, I.Width() );
14711 if ( m_status.IsInitializationEnabled() )
14712 m_status.Initialize(
"Computing intensity component", N );
14714 Array<size_type> L = OptimalThreadRows( I.Height(), I.Width(), maxProcessors );
14717 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
14718 threads.
Add(
new GetIntensityThread<P1>( I, *
this, data, r, n, n +
int( L[i] ) ) );
14719 RunThreads( threads, data );
14735 void GetIntensity(
ImageVariant& I,
const Rect& rect =
Rect( 0 ),
int maxProcessors = 0 )
const;
14798 template <
class P1>
14801 int maxProcessors = 0 )
14804 if ( !Y.ParseRect( r ) )
14808 if ( p.
x == int_max || p.
y == int_max )
14813 if ( (r.
x0 -= p.
x) >= r.
x1 )
14817 else if ( p.
x >= m_width )
14822 if ( (r.
y0 -= p.
y) >= r.
y1 )
14826 else if ( p.
y >= m_height )
14836 if ( m_colorSpace == ColorSpace::Gray &&
14837 (Y.ColorSpace() == ColorSpace::Gray || Y.ColorSpace() == ColorSpace::CIEXYZ) )
14839 if ( m_status.IsInitializationEnabled() )
14840 m_status.Initialize(
"Transferring pixel data", N );
14842 int c0 = (Y.ColorSpace() == ColorSpace::Gray) ? 0 : 1;
14844 sample* __restrict__ f = PixelAddress( p );
14845 for (
int i = 0, w = r.
Width(), h = r.
Height(); i < h; ++i, f += m_width, g += Y.Width(), m_status += w )
14846 P::Copy( f, g, w );
14850 if ( m_status.IsInitializationEnabled() )
14851 m_status.Initialize(
"Importing CIE Y component", N );
14856 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
14857 threads.
Add(
new SetLuminanceThread<P1>( *
this, Y, data, p, r, n, n +
int( L[i] ) ) );
14858 RunThreads( threads, data );
14878 int maxProcessors = 0 );
14939 template <
class P1>
14942 int maxProcessors = 0 )
14945 if ( !L.ParseRect( r ) )
14949 if ( p.
x == int_max || p.
y == int_max )
14954 if ( (r.
x0 -= p.
x) >= r.
x1 )
14958 else if ( p.
x >= m_width )
14963 if ( (r.
y0 -= p.
y) >= r.
y1 )
14967 else if ( p.
y >= m_height )
14977 if ( m_colorSpace == ColorSpace::Gray &&
14978 (L.ColorSpace() == ColorSpace::Gray ||
14979 L.ColorSpace() == ColorSpace::CIELab || L.ColorSpace() == ColorSpace::CIELch) )
14981 if ( m_status.IsInitializationEnabled() )
14982 m_status.Initialize(
"Transferring pixel data", N );
14985 sample* __restrict__ f = PixelAddress( p );
14986 for (
int i = 0, w = r.
Width(), h = r.
Height(); i < h; ++i, f += m_width, g += L.Width(), m_status += w )
14987 P::Copy( f, g, w );
14991 if ( m_status.IsInitializationEnabled() )
14992 m_status.Initialize(
"Importing CIE L* component", N );
14997 for (
int i = 0, n = 0; i < int( R.Length() ); n += int( R[i++] ) )
14998 threads.
Add(
new SetLightnessThread<P1>( *
this, L, data, p, r, n, n +
int( R[i] ) ) );
14999 RunThreads( threads, data );
15019 int maxProcessors = 0 );
15061 const Rect& rect =
Rect( 0 ),
int channel = -1,
15065 if ( !ParseSelection( r, channel ) )
15067 if ( r == Bounds() )
15068 return compressor.
Compress( m_channelData( channel ), ChannelSize(), perf );
15091 sample** data =
nullptr;
15103 pixel_allocator allocator;
15120 LinkWithClientImage( image );
15126 Data( GenericImage* image,
void* handle )
15127 : allocator( handle )
15129 SynchronizeWithSharedImage();
15130 LinkWithClientImage( image );
15136 Data( GenericImage* image,
int width,
int height,
int numberOfChannels,
int colorSpace )
15137 : allocator( width, height, numberOfChannels, colorSpace )
15139 SynchronizeWithSharedImage();
15140 LinkWithClientImage( image );
15143 void Attach( GenericImage* image )
15145 ReferenceCounter::Attach();
15146 LinkWithClientImage( image );
15157 bool IsShared() const noexcept
15159 return allocator.IsShared();
15162 bool IsEmpty() const noexcept
15164 return data ==
nullptr;
15167 void Allocate(
int width,
int height,
int numberOfChannels, color_space colorSpace )
15169 if ( width <= 0 || height <= 0 || numberOfChannels <= 0 )
15176 throw Error(
"GenericImage::Data::Allocate(): Insufficient number of channels" );
15178 if ( data !=
nullptr )
15182 if ( numberOfChannels != geometry.numberOfChannels )
15184 sample** newData =
nullptr;
15185 int m =
pcl::Min( geometry.numberOfChannels, numberOfChannels );
15189 newData = allocator.AllocateChannelSlots( numberOfChannels );
15190 for (
int i = 0; i < m; ++i )
15191 newData[i] = data[i];
15192 for (
int i = m; i < numberOfChannels; ++i )
15193 newData[i] = allocator.AllocatePixels( width, height );
15197 for (
int i = m; i < geometry.numberOfChannels; ++i )
15198 if ( data[i] !=
nullptr )
15199 allocator.Deallocate( data[i] ), data[i] =
nullptr;
15200 allocator.Deallocate( data );
15212 if ( newData !=
nullptr )
15214 for (
int i = m; i < numberOfChannels; ++i )
15215 if ( newData[i] !=
nullptr )
15216 allocator.Deallocate( newData[i] ), newData[i] =
nullptr;
15217 allocator.Deallocate( newData );
15225 sample** newData =
nullptr;
15229 newData = allocator.AllocateChannelSlots( numberOfChannels );
15230 for (
int i = 0; i < numberOfChannels; ++i )
15231 newData[i] = allocator.AllocatePixels( width, height );
15235 for (
int i = 0; i < geometry.numberOfChannels; ++i )
15236 if ( data[i] !=
nullptr )
15237 allocator.Deallocate( data[i] ), data[i] =
nullptr;
15238 allocator.Deallocate( data );
15250 if ( newData !=
nullptr )
15252 for (
int i = 0; i < numberOfChannels; ++i )
15253 if ( newData[i] !=
nullptr )
15254 allocator.Deallocate( newData[i] ), newData[i] =
nullptr;
15255 allocator.Deallocate( newData );
15265 data = allocator.AllocateChannelSlots( numberOfChannels );
15266 for (
int i = 0; i < numberOfChannels; ++i )
15267 data[i] = allocator.AllocatePixels( width, height );
15271 if ( data !=
nullptr )
15273 for (
int i = 0; i < numberOfChannels; ++i )
15274 if ( data[i] !=
nullptr )
15275 allocator.Deallocate( data[i] ), data[i] =
nullptr;
15276 allocator.Deallocate( data );
15283 geometry.width = width;
15284 geometry.height = height;
15285 geometry.numberOfChannels = numberOfChannels;
15287 color.colorSpace = colorSpace;
15289 UpdateSharedImage();
15292 void Import( sample** newData,
int width,
int height,
int numberOfChannels, color_space colorSpace )
15294 if ( newData != data )
15298 if ( newData !=
nullptr && width > 0 && height > 0 && numberOfChannels > 0 )
15301 throw Error(
"GenericImage::Data::Import(): Insufficient number of channels" );
15305 geometry.width = width;
15306 geometry.height = height;
15307 geometry.numberOfChannels = numberOfChannels;
15309 color.colorSpace = colorSpace;
15311 UpdateSharedImage();
15318 sample** oldData = data;
15320 UpdateSharedImage();
15326 if ( data !=
nullptr )
15328 for (
int i = 0; i < geometry.numberOfChannels; ++i )
15329 if ( data[i] !=
nullptr )
15330 allocator.Deallocate( data[i] ), data[i] =
nullptr;
15331 allocator.Deallocate( data );
15333 UpdateSharedImage();
15337 Data* Clone( GenericImage* image )
const
15339 Data* clone =
nullptr;
15346 clone->data = clone->allocator.AllocateChannelSlots( geometry.numberOfChannels );
15347 for (
int i = 0; i < geometry.numberOfChannels; ++i )
15349 clone->data[i] = clone->allocator.AllocatePixels( geometry.width, geometry.height );
15350 P::Copy( clone->data[i], data[i], geometry.NumberOfPixels() );
15353 clone->geometry.Assign( geometry );
15354 clone->color.Assign( color );
15357 clone->LinkWithClientImage( image );
15362 if ( clone !=
nullptr )
15364 clone->Deallocate();
15378 void UpdateSharedImage()
15380 allocator.SetSharedData( data );
15381 allocator.SetSharedGeometry( geometry.width, geometry.height, geometry.numberOfChannels );
15382 allocator.SetSharedColor( color.colorSpace, color.RGBWS );
15385 void SynchronizeWithSharedImage()
15387 data = allocator.GetSharedData();
15388 allocator.GetSharedGeometry( geometry.width, geometry.height, geometry.numberOfChannels );
15389 allocator.GetSharedColor( color.colorSpace, color.RGBWS );
15396 void LinkWithClientImage( GenericImage* image )
15398 if ( image !=
nullptr )
15400 image->m_geometry = &geometry;
15401 image->m_color = &color;
15410 Data* m_data =
nullptr;
15416 void DetachFromData()
15418 if ( !m_data->Detach() )
15424 class RectThreadBase :
public Thread
15428 RectThreadBase(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15433 , m_firstRow( firstRow )
15434 , m_endRow( endRow )
15438 virtual void Run() = 0;
15442 const GenericImage& m_image;
15443 const Rect& m_rect;
15445 int m_firstRow, m_endRow;
15447 template <
class F>
void Execute( F process ) noexcept
15449 int w = m_rect.Width();
15450 int dw = m_image.Width() - w;
15452 if ( m_image.IsLowRangeClippingEnabled() )
15454 sample clipLow = P::ToSample( m_image.RangeClipLow() );
15455 if ( m_image.IsHighRangeClippingEnabled() )
15457 sample clipHigh = P::ToSample( m_image.RangeClipHigh() );
15458 for (
int i = m_ch1; i <= m_ch2; ++i )
15460 const sample* __restrict__ f = m_image.PixelAddress( m_rect.x0, m_rect.y0+m_firstRow, i );
15461 for (
int j = m_firstRow; j < m_endRow; ++j, f += dw )
15464 for (
int k = 0; k < w; ++k, ++f )
15465 if ( clipLow < *f )
15466 if ( *f < clipHigh )
15473 for (
int i = m_ch1; i <= m_ch2; ++i )
15475 const sample* __restrict__ f = m_image.PixelAddress( m_rect.x0, m_rect.y0+m_firstRow, i );
15476 for (
int j = m_firstRow; j < m_endRow; ++j, f += dw )
15479 for (
int k = 0; k < w; ++k, ++f )
15480 if ( clipLow < *f )
15486 else if ( m_image.IsHighRangeClippingEnabled() )
15488 sample clipHigh = P::ToSample( m_image.RangeClipHigh() );
15489 for (
int i = m_ch1; i <= m_ch2; ++i )
15491 const sample* __restrict__ f = m_image.PixelAddress( m_rect.x0, m_rect.y0+m_firstRow, i );
15492 for (
int j = m_firstRow; j < m_endRow; ++j, f += dw )
15495 for (
int k = 0; k < w; ++k, ++f )
15496 if ( *f < clipHigh )
15503 for (
int i = m_ch1; i <= m_ch2; ++i )
15505 const sample* __restrict__ f = m_image.PixelAddress( m_rect.x0, m_rect.y0+m_firstRow, i );
15506 for (
int j = m_firstRow; j < m_endRow; ++j, f += dw )
15509 for (
int k = 0; k < w; ++k, ++f )
15519 class CountThread :
public RectThreadBase
15525 CountThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15526 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15535 int w = this->m_rect.Width();
15536 int dw = this->m_image.Width() - w;
15538 if ( this->m_image.IsLowRangeClippingEnabled() )
15540 sample clipLow = P::ToSample( this->m_image.RangeClipLow() );
15541 if ( this->m_image.IsHighRangeClippingEnabled() )
15543 sample clipHigh = P::ToSample( this->m_image.RangeClipHigh() );
15544 for (
int i = this->m_ch1; i <= this->m_ch2; ++i )
15546 const sample* __restrict__ f = this->m_image.PixelAddress( this->m_rect.x0, this->m_rect.y0+this->m_firstRow, i );
15547 for (
int j = this->m_firstRow; j < this->m_endRow; ++j, f += dw )
15550 for (
int k = 0; k < w; ++k, ++f )
15551 if ( clipLow < *f )
15552 if ( *f < clipHigh )
15559 for (
int i = this->m_ch1; i <= this->m_ch2; ++i )
15561 const sample* __restrict__ f = this->m_image.PixelAddress( this->m_rect.x0, this->m_rect.y0+this->m_firstRow, i );
15562 for (
int j = this->m_firstRow; j < this->m_endRow; ++j, f += dw )
15565 for (
int k = 0; k < w; ++k, ++f )
15566 if ( clipLow < *f )
15572 else if ( this->m_image.IsHighRangeClippingEnabled() )
15574 sample clipHigh = P::ToSample( this->m_image.RangeClipHigh() );
15575 for (
int i = this->m_ch1; i <= this->m_ch2; ++i )
15577 const sample* __restrict__ f = this->m_image.PixelAddress( this->m_rect.x0, this->m_rect.y0+this->m_firstRow, i );
15578 for (
int j = this->m_firstRow; j < this->m_endRow; ++j, f += dw )
15581 for (
int k = 0; k < w; ++k, ++f )
15582 if ( *f < clipHigh )
15594 class MinThread :
public RectThreadBase
15601 MinThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15602 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15608 min = P::HighestSampleValue();
15610 this->Execute( [=](
const sample* f )
15621 class MaxThread :
public RectThreadBase
15628 MaxThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15629 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15635 max = P::LowestSampleValue();
15637 this->Execute( [=](
const sample* f )
15648 class MinMaxThread :
public RectThreadBase
15656 MinMaxThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15657 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15663 min = P::HighestSampleValue();
15664 max = P::LowestSampleValue();
15666 this->Execute( [=](
const sample* f )
15679 class ExtremePosThreadBase :
public RectThreadBase
15687 ExtremePosThreadBase(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15688 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15695 m_amin = m_amax =
nullptr;
15701 for (
int i = this->m_ch1; i <= this->m_ch2; ++i )
15702 if ( m_amin >= this->m_image[i] && m_amin < (this->m_image[i] + this->m_image.NumberOfPixels()) )
15705 pmin.x = (m_amin - this->m_image[i]) % this->m_image.Width();
15706 pmin.y = (m_amin - this->m_image[i]) / this->m_image.Width();
15710 for (
int i = this->m_ch1; i <= this->m_ch2; ++i )
15711 if ( m_amax >= this->m_image[i] && m_amax < (this->m_image[i] + this->m_image.NumberOfPixels()) )
15714 pmax.x = (m_amax - this->m_image[i]) % this->m_image.Width();
15715 pmax.y = (m_amax - this->m_image[i]) / this->m_image.Width();
15723 const sample* m_amin;
15724 const sample* m_amax;
15726 virtual void DoExecute() = 0;
15731 class MinPosThread :
public ExtremePosThreadBase
15737 MinPosThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15738 : ExtremePosThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15744 void DoExecute()
override
15746 min = P::HighestSampleValue();
15747 this->Execute( [=](
const sample* f )
15750 min = *(this->m_amin = f);
15758 class MaxPosThread :
public ExtremePosThreadBase
15764 MaxPosThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15765 : ExtremePosThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15771 void DoExecute()
override
15773 max = P::LowestSampleValue();
15774 this->Execute( [=](
const sample* f )
15777 max = *(this->m_amax = f);
15785 class MinMaxPosThread :
public ExtremePosThreadBase
15791 MinMaxPosThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15792 : ExtremePosThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15798 void DoExecute()
override
15800 min = P::HighestSampleValue();
15801 max = P::LowestSampleValue();
15802 this->Execute( [=](
const sample* f )
15805 min = *(this->m_amin = f);
15807 max = *(this->m_amax = f);
15815 class SumThread :
public RectThreadBase
15822 SumThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15823 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15838 void SumStep(
double x ) noexcept
15847 virtual void DoExecute()
15849 this->Execute( [=](
const sample* f )
15851 double v; P::FromSample( v, *f );
15859 class SumSqrThread :
public SumThread
15863 SumSqrThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15864 : SumThread( image, rect, ch1, ch2, firstRow, endRow )
15870 void DoExecute()
override
15872 this->Execute( [=](
const sample* f )
15874 double v; P::FromSample( v, *f );
15875 this->SumStep( v*v );
15882 class SumAbsThread :
public SumThread
15886 SumAbsThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15887 : SumThread( image, rect, ch1, ch2, firstRow, endRow )
15893 void DoExecute()
override
15895 this->Execute( [=](
const sample* f )
15897 double v; P::FromSample( v, *f );
15905 class NormThread :
public RectThreadBase
15912 NormThread(
const GenericImage& image,
int degree,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
15913 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15923 this->Execute( [=](
const sample* f )
15925 double v; P::FromSample( v, *f );
15926 for (
int i = 0;; )
15929 if ( ++i == R.Length() )
15941 void NormStep(
int i,
double x ) noexcept
15943 double y = x - e[i];
15944 double t = R[i] + y;
15945 e[i] = (t - R[i]) - y;
15952 class HistogramThread :
public RectThreadBase
15958 HistogramThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow,
15959 const double& low,
const double& high )
15960 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
15961 , H( __PCL_MEDIAN_HISTOGRAM_LENGTH )
15970 m_range = m_high - m_low;
15973 #ifdef __PCL_MACOSX
15974 if ( 1 + m_range != 1 )
15976 this->Execute( [=](
const sample* f )
15979 if ( *f <= m_high )
15980 ++H[
TruncInt( (__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) * (
double( *f ) - m_low)/m_range )];
15986 const double& m_low;
15987 const double& m_high;
15993 class ExtremeAbsDevThread :
public RectThreadBase
15997 double minAbsDev, maxAbsDev;
16000 ExtremeAbsDevThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow,
double center )
16001 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16002 , m_center( center )
16008 minAbsDev = std::numeric_limits<double>::max();
16011 this->Execute( [=](
const sample* f )
16013 double d; P::FromSample( d, *f );
16015 if ( d < minAbsDev )
16017 if ( d > maxAbsDev )
16030 class TwoSidedExtremeAbsDevThread :
public RectThreadBase
16034 double minAbsDevLow, minAbsDevHigh;
16035 double maxAbsDevLow, maxAbsDevHigh;
16038 TwoSidedExtremeAbsDevThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow,
double center )
16039 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16040 , m_center( center )
16046 minAbsDevLow = minAbsDevHigh = std::numeric_limits<double>::max();
16047 maxAbsDevLow = maxAbsDevHigh = 0;
16049 this->Execute( [=](
const sample* f )
16051 double x; P::FromSample( x, *f );
16052 if ( x <= m_center )
16054 double d = m_center - x;
16055 if ( d < minAbsDevLow )
16057 if ( d > maxAbsDevLow )
16063 double d = x - m_center;
16064 if ( d < minAbsDevHigh )
16066 if ( d > maxAbsDevHigh )
16080 class AbsDevHistogramThread :
public RectThreadBase
16086 AbsDevHistogramThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow,
16087 double center,
const double& low,
const double& high )
16088 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16089 , H( __PCL_MEDIAN_HISTOGRAM_LENGTH )
16090 , m_center( center )
16099 m_range = m_high - m_low;
16102 #ifdef __PCL_MACOSX
16103 if ( 1 + m_range != 1 )
16105 this->Execute( [=](
const sample* f )
16107 double d; P::FromSample( d, *f );
16111 ++H[
TruncInt( (__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) * (d - m_low)/m_range )];
16118 const double& m_low;
16119 const double& m_high;
16125 class TwoSidedAbsDevHistogramThread :
public RectThreadBase
16131 TwoSidedAbsDevHistogramThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow,
16132 double center,
const int& side,
const double& low,
const double& high )
16133 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16134 , H( __PCL_MEDIAN_HISTOGRAM_LENGTH )
16135 , m_center( center )
16145 m_range = m_high - m_low;
16148 #ifdef __PCL_MACOSX
16149 if ( 1 + m_range != 1 )
16151 this->Execute( [=](
const sample* f )
16153 double x; P::FromSample( x, *f );
16154 if ( m_side > 0 == x > m_center )
16156 double d = m_side ? x - m_center : m_center - x;
16159 ++H[
TruncInt( (__PCL_MEDIAN_HISTOGRAM_LENGTH - 1) * (d - m_low)/m_range )];
16168 const double& m_low;
16169 const double& m_high;
16175 class VarThread :
public RectThreadBase
16181 VarThread(
const GenericImage& image,
double mean,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
16182 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16190 this->Execute( [=](
const sample* f )
16192 double d; P::FromSample( d, *f );
16206 class SumAbsDevThread :
public SumThread
16210 SumAbsDevThread(
const GenericImage& image,
double center,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
16211 : SumThread( image, rect, ch1, ch2, firstRow, endRow )
16212 , m_center( center )
16220 void DoExecute()
override
16222 this->Execute( [=](
const sample* f )
16224 double v; P::FromSample( v, *f );
16225 this->SumStep(
pcl::Abs( v - m_center ) );
16232 class TwoSidedSumAbsDevThread :
public RectThreadBase
16239 TwoSidedSumAbsDevThread(
const GenericImage& image,
double center,
16240 const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
16241 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16242 , m_center( center )
16250 this->Execute( [=](
const sample* f )
16252 double v; P::FromSample( v, *f );
16253 if ( v <= m_center )
16255 s0 += m_center - v;
16260 s1 += v - m_center;
16273 class BWMVThread :
public RectThreadBase
16280 BWMVThread(
const GenericImage& image,
double center,
double kd,
16281 const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
16282 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16283 , m_center( center )
16292 this->Execute( [=](
const sample* f )
16295 double xc; P::FromSample( xc, *f ); xc -= m_center;
16296 double y = xc/m_kd;
16300 double y21 = 1 - y2;
16301 num += xc*xc * y21*y21*y21*y21;
16302 den += y21 * (1 - 5*y2);
16316 class TwoSidedBWMVThread :
public RectThreadBase
16324 TwoSidedBWMVThread(
const GenericImage& image,
double center,
double kd0,
double kd1,
16325 const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
16326 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16327 , m_center( center )
16335 num0 = den0 = num1 = den1 = 0;
16336 n0 = n1 = nr0 = nr1 = 0;
16337 this->Execute( [=](
const sample* f )
16339 double xc; P::FromSample( xc, *f ); xc -= m_center;
16340 bool low = xc <= 0;
16346 double y = xc/(low ? m_kd0 : m_kd1);
16350 double y21 = 1 - y2;
16351 double num = xc*xc * y21*y21*y21*y21;
16352 double den = y21 * (1 - 5*y2);
16378 class SmpThread :
public RectThreadBase
16382 Array<sample> samples;
16385 SmpThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
16386 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16389 *
size_type( this->m_endRow - this->m_firstRow )
16390 * (1 + this->m_ch2 - this->m_ch1);
16391 samples = Array<sample>( N );
16397 this->Execute( [=](
const sample* f )
16406 class DSmpThread :
public RectThreadBase
16410 Array<double> values;
16413 DSmpThread(
const GenericImage& image,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
16414 : RectThreadBase( image, rect, ch1, ch2, firstRow, endRow )
16417 *
size_type( this->m_endRow - this->m_firstRow )
16418 * (1 + this->m_ch2 - this->m_ch1);
16419 values = Array<double>( N );
16430 virtual void DoExecute()
16432 this->Execute( [=](
const sample* f )
16434 P::FromSample( values[n++], *f );
16441 class AbsDevSmpThread :
public DSmpThread
16445 AbsDevSmpThread(
const GenericImage& image,
double center,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
16446 : DSmpThread( image, rect, ch1, ch2, firstRow, endRow )
16447 , m_center( center )
16455 void DoExecute()
override
16457 this->Execute( [=](
const sample* f )
16459 double d; P::FromSample( d, *f );
16460 this->values[this->n++] =
pcl::Abs( d - m_center );
16467 class TwoSidedAbsDevSmpThread :
public DSmpThread
16473 TwoSidedAbsDevSmpThread(
const GenericImage& image,
double center,
const Rect& rect,
int ch1,
int ch2,
int firstRow,
int endRow )
16474 : DSmpThread( image, rect, ch1, ch2, firstRow, endRow )
16475 , m_center( center )
16483 void DoExecute()
override
16485 p = this->values.Begin();
16486 q = this->values.End();
16487 this->Execute( [=](
const sample* f )
16489 double x; P::FromSample( x, *f );
16490 if ( x <= m_center )
16491 *p++ = m_center - x;
16493 *--q = x - m_center;
16501 class ColorSpaceConversionThread :
public Thread
16505 ColorSpaceConversionThread( GenericImage& image, ThreadData& data,
16509 , m_toColorSpace( toColorSpace )
16519 const RGBColorSystem& rgbws = m_image.RGBWorkingSpace();
16521 typename P::sample* f0 = m_image[0] + m_begin;
16522 typename P::sample* f1 = m_image[1] + m_begin;
16523 typename P::sample* f2 = m_image[2] + m_begin;
16524 typename P::sample* fN = m_image[0] + m_end;
16526 for ( ; f0 < fN; ++f0, ++f1, ++f2 )
16528 RGBColorSystem::sample r0, r1, r2;
16529 P::FromSample( r0, *f0 );
16530 P::FromSample( r1, *f1 );
16531 P::FromSample( r2, *f2 );
16533 switch ( m_image.ColorSpace() )
16535 case ColorSpace::RGB :
16536 switch ( m_toColorSpace )
16538 case ColorSpace::Gray :
16539 rgbws.RGBToGray( r0, r0, r1, r2 );
16541 case ColorSpace::HSV :
16542 rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16544 case ColorSpace::HSI :
16545 rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16547 case ColorSpace::CIEXYZ :
16548 rgbws.RGBToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16550 case ColorSpace::CIELab :
16551 rgbws.RGBToCIELab( r0, r1, r2, r0, r1, r2 );
16553 case ColorSpace::CIELch :
16554 rgbws.RGBToCIELch( r0, r1, r2, r0, r1, r2 );
16560 case ColorSpace::HSV :
16561 rgbws.HSVToRGB( r0, r1, r2, r0, r1, r2 );
16562 switch ( m_toColorSpace )
16564 case ColorSpace::Gray :
16565 rgbws.RGBToGray( r0, r0, r1, r2 );
16567 case ColorSpace::RGB :
16569 case ColorSpace::HSI :
16570 rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16572 case ColorSpace::CIEXYZ :
16573 rgbws.RGBToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16575 case ColorSpace::CIELab :
16576 rgbws.RGBToCIELab( r0, r1, r2, r0, r1, r2 );
16578 case ColorSpace::CIELch :
16579 rgbws.RGBToCIELch( r0, r1, r2, r0, r1, r2 );
16585 case ColorSpace::HSI :
16586 rgbws.HSIToRGB( r0, r1, r2, r0, r1, r2 );
16587 switch ( m_toColorSpace )
16589 case ColorSpace::Gray :
16590 rgbws.RGBToGray( r0, r0, r1, r2 );
16592 case ColorSpace::RGB :
16594 case ColorSpace::HSV :
16595 rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16597 case ColorSpace::CIEXYZ :
16598 rgbws.RGBToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16600 case ColorSpace::CIELab :
16601 rgbws.RGBToCIELab( r0, r1, r2, r0, r1, r2 );
16603 case ColorSpace::CIELch :
16604 rgbws.RGBToCIELch( r0, r1, r2, r0, r1, r2 );
16610 case ColorSpace::CIEXYZ :
16611 switch ( m_toColorSpace )
16613 case ColorSpace::Gray :
16614 rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16615 rgbws.RGBToGray( r0, r0, r1, r2 );
16617 case ColorSpace::RGB :
16618 rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16620 case ColorSpace::HSV :
16621 rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16622 rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16624 case ColorSpace::HSI :
16625 rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16626 rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16628 case ColorSpace::CIELab :
16629 rgbws.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
16631 case ColorSpace::CIELch :
16632 rgbws.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
16633 rgbws.CIELabToCIELch( r0, r1, r2, r0, r1, r2 );
16639 case ColorSpace::CIELab :
16640 switch ( m_toColorSpace )
16642 case ColorSpace::Gray :
16643 rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16644 rgbws.RGBToGray( r0, r0, r1, r2 );
16646 case ColorSpace::RGB :
16647 rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16649 case ColorSpace::HSV :
16650 rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16651 rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16653 case ColorSpace::HSI :
16654 rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16655 rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16657 case ColorSpace::CIEXYZ :
16658 rgbws.CIELabToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16660 case ColorSpace::CIELch :
16661 rgbws.CIELabToCIELch( r0, r1, r2, r0, r1, r2 );
16667 case ColorSpace::CIELch :
16668 switch ( m_toColorSpace )
16670 case ColorSpace::Gray :
16671 rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16672 rgbws.RGBToGray( r0, r0, r1, r2 );
16674 case ColorSpace::RGB :
16675 rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16677 case ColorSpace::HSV :
16678 rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16679 rgbws.RGBToHSV( r0, r1, r2, r0, r1, r2 );
16681 case ColorSpace::HSI :
16682 rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16683 rgbws.RGBToHSI( r0, r1, r2, r0, r1, r2 );
16685 case ColorSpace::CIEXYZ :
16686 rgbws.CIELchToCIELab( r0, r1, r2, r0, r1, r2 );
16687 rgbws.CIELabToCIEXYZ( r0, r1, r2, r0, r1, r2 );
16689 case ColorSpace::CIELab :
16690 rgbws.CIELchToCIELab( r0, r1, r2, r0, r1, r2 );
16700 *f0 = P::ToSample( r0 );
16702 if ( m_toColorSpace != ColorSpace::Gray )
16704 *f1 = P::ToSample( r1 );
16705 *f2 = P::ToSample( r2 );
16714 GenericImage& m_image;
16715 ThreadData& m_data;
16716 color_space m_toColorSpace;
16722 template <
class P1>
16723 class GetLuminanceThread :
public Thread
16727 GetLuminanceThread( GenericImage<P1>& luminance,
const GenericImage& image, ThreadData& data,
16728 const Rect& rect,
int firstRow,
int endRow )
16729 : m_luminance( luminance )
16733 , m_firstRow( firstRow )
16734 , m_endRow( endRow )
16742 const RGBColorSystem& rgbws = m_image.RGBWorkingSpace();
16744 const typename P::sample* f0 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
16745 const typename P::sample* f1 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
16746 const typename P::sample* f2 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
16748 typename P1::sample* fY = m_luminance.ScanLine( m_firstRow );
16750 for (
int y = m_firstRow, dw = m_image.Width()-m_rect.Width();
16752 ++y, f0 += dw, f1 += dw, f2 += dw )
16754 const typename P::sample* fN = f0 + m_rect.Width();
16756 for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fY )
16758 RGBColorSystem::sample r0, r1, r2, rY;
16759 P::FromSample( r0, *f0 );
16760 P::FromSample( r1, *f1 );
16761 P::FromSample( r2, *f2 );
16763 switch ( m_image.ColorSpace() )
16765 case ColorSpace::RGB:
16766 case ColorSpace::HSV:
16767 case ColorSpace::HSI:
16768 switch ( m_image.ColorSpace() )
16770 case ColorSpace::HSV:
16771 rgbws.HSVToRGB( r0, r1, r2, r0, r1, r2 );
16773 case ColorSpace::HSI:
16774 rgbws.HSIToRGB( r0, r1, r2, r0, r1, r2 );
16779 rY = rgbws.CIEY( r0, r1, r2 );
16782 case ColorSpace::CIELch:
16783 rgbws.CIELchToCIELab( r0, r1, r2, r0, r1, r2 );
16785 case ColorSpace::CIELab:
16786 rgbws.CIELabToCIEXYZ( r0, rY, r2, r0, r1, r2 );
16794 *fY = P1::ToSample( rY );
16803 GenericImage<P1>& m_luminance;
16804 const GenericImage& m_image;
16805 ThreadData& m_data;
16806 const Rect& m_rect;
16807 int m_firstRow, m_endRow;
16812 template <
class P1>
16813 class GetLightnessThread :
public Thread
16817 GetLightnessThread( GenericImage<P1>& lightness,
const GenericImage& image, ThreadData& data,
16818 const Rect& rect,
int firstRow,
int endRow )
16819 : m_lightness( lightness )
16823 , m_firstRow( firstRow )
16824 , m_endRow( endRow )
16832 const RGBColorSystem& rgbws = m_image.RGBWorkingSpace();
16834 const typename P::sample* f0 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
16835 const typename P::sample* f1 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
16836 const typename P::sample* f2 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
16838 typename P1::sample* fL = m_lightness.ScanLine( m_firstRow );
16840 for (
int y = m_firstRow, dw = m_image.Width()-m_rect.Width();
16842 ++y, f0 += dw, f1 += dw, f2 += dw )
16844 const typename P::sample* fN = f0 + m_rect.Width();
16846 for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fL )
16848 RGBColorSystem::sample r0, r1, r2, rL;
16849 P::FromSample( r0, *f0 );
16850 P::FromSample( r1, *f1 );
16851 P::FromSample( r2, *f2 );
16853 switch ( m_image.ColorSpace() )
16855 case ColorSpace::RGB:
16856 case ColorSpace::HSV:
16857 case ColorSpace::HSI:
16858 case ColorSpace::CIEXYZ:
16859 switch ( m_image.ColorSpace() )
16861 case ColorSpace::HSV:
16862 rgbws.HSVToRGB( r0, r1, r2, r0, r1, r2 );
16864 case ColorSpace::HSI:
16865 rgbws.HSIToRGB( r0, r1, r2, r0, r1, r2 );
16867 case ColorSpace::CIEXYZ:
16868 rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16873 rL = rgbws.CIEL( r0, r1, r2 );
16881 *fL = P1::ToSample( rL );
16890 GenericImage<P1>& m_lightness;
16891 const GenericImage& m_image;
16892 ThreadData& m_data;
16893 const Rect& m_rect;
16894 int m_firstRow, m_endRow;
16899 template <
class P1>
16900 class GetIntensityThread :
public Thread
16904 GetIntensityThread( GenericImage<P1>& luminance,
const GenericImage& image, ThreadData& data,
16905 const Rect& rect,
int firstRow,
int endRow )
16906 : m_intensity( luminance )
16910 , m_firstRow( firstRow )
16911 , m_endRow( endRow )
16919 const RGBColorSystem& rgbws = m_image.RGBWorkingSpace();
16921 const typename P::sample* f0 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
16922 const typename P::sample* f1 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
16923 const typename P::sample* f2 = m_image.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
16925 typename P1::sample* fI = m_intensity.ScanLine( m_firstRow );
16927 for (
int y = m_firstRow, dw = m_image.Width()-m_rect.Width();
16929 ++y, f0 += dw, f1 += dw, f2 += dw )
16931 const typename P::sample* fN = f0 + m_rect.Width();
16933 for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fI )
16935 RGBColorSystem::sample r0, r1, r2;
16936 P::FromSample( r0, *f0 );
16937 P::FromSample( r1, *f1 );
16938 P::FromSample( r2, *f2 );
16940 switch ( m_image.ColorSpace() )
16942 case ColorSpace::RGB:
16944 case ColorSpace::HSV:
16945 rgbws.HSVToRGB( r0, r1, r2, r0, r1, r2 );
16947 case ColorSpace::CIEXYZ:
16948 rgbws.CIEXYZToRGB( r0, r1, r2, r0, r1, r2 );
16950 case ColorSpace::CIELab:
16951 rgbws.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
16953 case ColorSpace::CIELch:
16954 rgbws.CIELchToRGB( r0, r1, r2, r0, r1, r2 );
16960 *fI = P1::ToSample( rgbws.Intensity( r0, r1, r2 ) );
16969 GenericImage<P1>& m_intensity;
16970 const GenericImage& m_image;
16971 ThreadData& m_data;
16972 const Rect& m_rect;
16973 int m_firstRow, m_endRow;
16978 template <
class P1>
16979 class SetLuminanceThread :
public Thread
16983 SetLuminanceThread( GenericImage& image,
const GenericImage<P1>& luminance, ThreadData& data,
16984 const Point& target,
const Rect& rect,
int firstRow,
int endRow )
16986 , m_luminance( luminance )
16988 , m_target( target )
16990 , m_firstRow( firstRow )
16991 , m_endRow( endRow )
16999 const RGBColorSystem& sourceRGBWS = m_luminance.RGBWorkingSpace();
17000 const RGBColorSystem& targetRGBWS = m_image.RGBWorkingSpace();
17002 typename P::sample* f0 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 0 );
17003 typename P::sample* f1 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 1 );
17004 typename P::sample* f2 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 2 );
17006 if ( m_luminance.ColorSpace() == ColorSpace::Gray || m_luminance.ColorSpace() == ColorSpace::CIEXYZ )
17008 int cY = (m_luminance.ColorSpace() == ColorSpace::Gray) ? 0 : 1;
17009 const typename P1::sample* fY = m_luminance.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, cY );
17011 for (
int y = m_firstRow, dw = m_image.Width()-m_rect.Width(), dwY = m_luminance.Width()-m_rect.Width();
17013 ++y, f0 += dw, f1 += dw, f2 += dw, fY += dwY )
17015 const typename P::sample* fN = f0 + m_rect.Width();
17017 for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fY )
17019 RGBColorSystem::sample r0, r1, r2, rY;
17020 P::FromSample( r0, *f0 );
17021 P::FromSample( r1, *f1 );
17022 P::FromSample( r2, *f2 );
17023 P1::FromSample( rY, *fY );
17025 switch ( m_image.ColorSpace() )
17027 case ColorSpace::RGB:
17028 case ColorSpace::HSV:
17029 case ColorSpace::HSI:
17030 switch ( m_image.ColorSpace() )
17032 case ColorSpace::HSV:
17033 targetRGBWS.HSVToRGB( r0, r1, r2, r0, r1, r2 );
17035 case ColorSpace::HSI:
17036 targetRGBWS.HSIToRGB( r0, r1, r2, r0, r1, r2 );
17041 targetRGBWS.RGBToCIEab( r1, r2, r0, r1, r2 );
17042 targetRGBWS.CIELabToRGB( r0, r1, r2, sourceRGBWS.CIEYToCIEL( rY ), r1, r2 );
17043 switch ( m_image.ColorSpace() )
17045 case ColorSpace::HSV:
17046 targetRGBWS.RGBToHSV( r0, r1, r2, r0, r1, r2 );
17048 case ColorSpace::HSI:
17049 targetRGBWS.RGBToHSI( r0, r1, r2, r0, r1, r2 );
17056 case ColorSpace::CIEXYZ:
17057 targetRGBWS.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
17058 targetRGBWS.CIELabToCIEXYZ( r0, r1, r2, sourceRGBWS.CIEYToCIEL( rY ), r1, r2 );
17061 case ColorSpace::CIELab:
17062 case ColorSpace::CIELch:
17063 r0 = sourceRGBWS.CIEYToCIEL( rY );
17070 *f0 = P::ToSample( r0 );
17071 *f1 = P::ToSample( r1 );
17072 *f2 = P::ToSample( r2 );
17080 const typename P1::sample* g0 = m_luminance.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
17081 const typename P1::sample* g1 = m_luminance.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
17082 const typename P1::sample* g2 = m_luminance.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
17084 for (
int y = m_firstRow, dw = m_image.Width()-m_rect.Width(), dwY = m_luminance.Width()-m_rect.Width();
17086 ++y, f0 += dw, f1 += dw, f2 += dw, g0 += dwY, g1 += dwY, g2 += dwY )
17088 const typename P::sample* fN = f0 + m_rect.Width();
17090 for ( ; f0 < fN; ++f0, ++f1, ++f2, ++g0, ++g1, ++g2 )
17092 typename RGBColorSystem::sample r0, r1, r2, s0, s1, s2;
17093 P::FromSample( r0, *f0 );
17094 P::FromSample( r1, *f1 );
17095 P::FromSample( r2, *f2 );
17096 P1::FromSample( s0, *g0 );
17097 P1::FromSample( s1, *g1 );
17098 P1::FromSample( s2, *g2 );
17100 switch ( m_image.ColorSpace() )
17102 case ColorSpace::RGB:
17103 case ColorSpace::HSV:
17104 case ColorSpace::HSI:
17105 case ColorSpace::CIEXYZ:
17106 case ColorSpace::CIELab:
17107 case ColorSpace::CIELch:
17108 switch ( m_image.ColorSpace() )
17110 case ColorSpace::RGB:
17111 case ColorSpace::HSV:
17112 case ColorSpace::HSI:
17113 switch ( m_image.ColorSpace() )
17115 case ColorSpace::HSV:
17116 targetRGBWS.HSVToRGB( r0, r1, r2, r0, r1, r2 );
17118 case ColorSpace::HSI:
17119 targetRGBWS.HSIToRGB( r0, r1, r2, r0, r1, r2 );
17124 targetRGBWS.RGBToCIEab( r1, r2, r0, r1, r2 );
17126 case ColorSpace::CIEXYZ:
17127 targetRGBWS.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
17129 case ColorSpace::CIELab:
17130 case ColorSpace::CIELch:
17136 switch ( m_luminance.ColorSpace() )
17138 case ColorSpace::RGB:
17139 case ColorSpace::HSV:
17140 case ColorSpace::HSI:
17141 switch ( m_luminance.ColorSpace() )
17143 case ColorSpace::HSV:
17144 sourceRGBWS.HSVToRGB( s0, s1, s2, s0, s1, s2 );
17146 case ColorSpace::HSI:
17147 sourceRGBWS.HSIToRGB( s0, s1, s2, s0, s1, s2 );
17152 r0 = sourceRGBWS.CIEL( s0, s1, s2 );
17154 case ColorSpace::CIEXYZ:
17155 sourceRGBWS.CIEXYZToCIELab( r0, s1, s2, s0, s1, s2 );
17157 case ColorSpace::CIELab:
17158 case ColorSpace::CIELch:
17165 switch ( m_image.ColorSpace() )
17167 case ColorSpace::RGB:
17168 case ColorSpace::HSV:
17169 case ColorSpace::HSI:
17170 targetRGBWS.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
17171 switch ( m_image.ColorSpace() )
17173 case ColorSpace::HSV:
17174 targetRGBWS.RGBToHSV( r0, r1, r2, r0, r1, r2 );
17176 case ColorSpace::HSI:
17177 targetRGBWS.RGBToHSI( r0, r1, r2, r0, r1, r2 );
17183 case ColorSpace::CIEXYZ:
17184 targetRGBWS.CIELabToCIEXYZ( r0, r1, r2, r0, r1, r2 );
17186 case ColorSpace::CIELab:
17187 case ColorSpace::CIELch:
17198 *f0 = P::ToSample( r0 );
17199 *f1 = P::ToSample( r1 );
17200 *f2 = P::ToSample( r2 );
17210 GenericImage& m_image;
17211 const GenericImage<P1>& m_luminance;
17212 ThreadData& m_data;
17213 const Point& m_target;
17214 const Rect& m_rect;
17215 int m_firstRow, m_endRow;
17220 template <
class P1>
17221 class SetLightnessThread :
public Thread
17225 SetLightnessThread( GenericImage& image,
const GenericImage<P1>& lightness, ThreadData& data,
17226 const Point& target,
const Rect& rect,
int firstRow,
int endRow )
17228 , m_lightness( lightness )
17230 , m_target( target )
17232 , m_firstRow( firstRow )
17233 , m_endRow( endRow )
17241 const RGBColorSystem& sourceRGBWS = m_lightness.RGBWorkingSpace();
17242 const RGBColorSystem& targetRGBWS = m_image.RGBWorkingSpace();
17244 typename P::sample* f0 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 0 );
17245 typename P::sample* f1 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 1 );
17246 typename P::sample* f2 = m_image.PixelAddress( m_target.x, m_target.y + m_firstRow, 2 );
17248 if ( m_lightness.ColorSpace() == ColorSpace::Gray ||
17249 m_lightness.ColorSpace() == ColorSpace::CIELab || m_lightness.ColorSpace() == ColorSpace::CIELch )
17251 const typename P1::sample* fL = m_lightness.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
17253 for (
int y = m_firstRow, dw = m_image.Width()-m_rect.Width(), dwL = m_lightness.Width()-m_rect.Width();
17255 ++y, f0 += dw, f1 += dw, f2 += dw, fL += dwL )
17257 const typename P::sample* fN = f0 + m_rect.Width();
17259 for ( ; f0 < fN; ++f0, ++f1, ++f2, ++fL )
17261 RGBColorSystem::sample r0, r1, r2, rL;
17262 P::FromSample( r0, *f0 );
17263 P::FromSample( r1, *f1 );
17264 P::FromSample( r2, *f2 );
17265 P1::FromSample( rL, *fL );
17267 switch ( m_image.ColorSpace() )
17269 case ColorSpace::RGB:
17270 case ColorSpace::HSV:
17271 case ColorSpace::HSI:
17272 switch ( m_image.ColorSpace() )
17274 case ColorSpace::HSV:
17275 targetRGBWS.HSVToRGB( r0, r1, r2, r0, r1, r2 );
17277 case ColorSpace::HSI:
17278 targetRGBWS.HSIToRGB( r0, r1, r2, r0, r1, r2 );
17283 targetRGBWS.RGBToCIEab( r1, r2, r0, r1, r2 );
17284 targetRGBWS.CIELabToRGB( r0, r1, r2, rL, r1, r2 );
17285 switch ( m_image.ColorSpace() )
17287 case ColorSpace::HSV:
17288 targetRGBWS.RGBToHSV( r0, r1, r2, r0, r1, r2 );
17290 case ColorSpace::HSI:
17291 targetRGBWS.RGBToHSI( r0, r1, r2, r0, r1, r2 );
17298 case ColorSpace::CIEXYZ:
17299 r1 = targetRGBWS.CIELToCIEY( rL );
17302 case ColorSpace::CIELab:
17303 case ColorSpace::CIELch:
17311 *f0 = P::ToSample( r0 );
17312 *f1 = P::ToSample( r1 );
17313 *f2 = P::ToSample( r2 );
17321 const typename P1::sample* g0 = m_lightness.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 0 );
17322 const typename P1::sample* g1 = m_lightness.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 1 );
17323 const typename P1::sample* g2 = m_lightness.PixelAddress( m_rect.x0, m_rect.y0 + m_firstRow, 2 );
17325 for (
int y = m_firstRow, dw = m_image.Width()-m_rect.Width(), dwL = m_lightness.Width()-m_rect.Width();
17327 ++y, f0 += dw, f1 += dw, f2 += dw, g0 += dwL, g1 += dwL, g2 += dwL )
17329 const typename P::sample* fN = f0 + m_rect.Width();
17331 for ( ; f0 < fN; ++f0, ++f1, ++f2, ++g0, ++g1, ++g2 )
17333 typename RGBColorSystem::sample r0, r1, r2, s0, s1, s2;
17334 P::FromSample( r0, *f0 );
17335 P::FromSample( r1, *f1 );
17336 P::FromSample( r2, *f2 );
17337 P1::FromSample( s0, *g0 );
17338 P1::FromSample( s1, *g1 );
17339 P1::FromSample( s2, *g2 );
17341 switch ( m_image.ColorSpace() )
17343 case ColorSpace::RGB:
17344 case ColorSpace::HSV:
17345 case ColorSpace::HSI:
17346 case ColorSpace::CIEXYZ:
17347 case ColorSpace::CIELab:
17348 case ColorSpace::CIELch:
17349 switch ( m_image.ColorSpace() )
17351 case ColorSpace::RGB:
17352 case ColorSpace::HSV:
17353 case ColorSpace::HSI:
17354 switch ( m_image.ColorSpace() )
17356 case ColorSpace::HSV:
17357 targetRGBWS.HSVToRGB( r0, r1, r2, r0, r1, r2 );
17359 case ColorSpace::HSI:
17360 targetRGBWS.HSIToRGB( r0, r1, r2, r0, r1, r2 );
17365 targetRGBWS.RGBToCIEab( r1, r2, r0, r1, r2 );
17367 case ColorSpace::CIEXYZ:
17368 targetRGBWS.CIEXYZToCIELab( r0, r1, r2, r0, r1, r2 );
17370 case ColorSpace::CIELch:
17371 targetRGBWS.CIELchToCIELab( r0, r1, r2, r0, r1, r2 );
17377 switch ( m_lightness.ColorSpace() )
17379 case ColorSpace::RGB:
17380 case ColorSpace::HSV:
17381 case ColorSpace::HSI:
17382 switch ( m_lightness.ColorSpace() )
17384 case ColorSpace::HSV:
17385 sourceRGBWS.HSVToRGB( s0, s1, s2, s0, s1, s2 );
17387 case ColorSpace::HSI:
17388 sourceRGBWS.HSIToRGB( s0, s1, s2, s0, s1, s2 );
17393 r0 = sourceRGBWS.CIEL( s0, s1, s2 );
17395 case ColorSpace::CIEXYZ:
17396 r0 = sourceRGBWS.CIEYToCIEL( s1 );
17402 switch ( m_image.ColorSpace() )
17404 case ColorSpace::RGB:
17405 case ColorSpace::HSV:
17406 case ColorSpace::HSI:
17407 targetRGBWS.CIELabToRGB( r0, r1, r2, r0, r1, r2 );
17408 switch ( m_image.ColorSpace() )
17410 case ColorSpace::HSV:
17411 targetRGBWS.RGBToHSV( r0, r1, r2, r0, r1, r2 );
17413 case ColorSpace::HSI:
17414 targetRGBWS.RGBToHSI( r0, r1, r2, r0, r1, r2 );
17420 case ColorSpace::CIEXYZ:
17421 targetRGBWS.CIELabToCIEXYZ( r0, r1, r2, r0, r1, r2 );
17423 case ColorSpace::CIELch:
17424 targetRGBWS.CIELabToCIELch( r0, r1, r2, r0, r1, r2 );
17434 *f0 = P::ToSample( r0 );
17435 *f1 = P::ToSample( r1 );
17436 *f2 = P::ToSample( r2 );
17446 GenericImage& m_image;
17447 const GenericImage<P1>& m_lightness;
17448 ThreadData& m_data;
17449 const Point& m_target;
17450 const Rect& m_rect;
17451 int m_firstRow, m_endRow;
17456 #ifdef __PCL_BUILDING_PIXINSIGHT_APPLICATION
17457 friend class pi::SharedImage;
17462 #undef m_channelData
17466 #undef m_numberOfChannels
17467 #undef m_colorSpace
17470 #undef m_lastChannel
17475 #undef m_clippedLow
17476 #undef m_clippedHigh
17489 template <
class P,
typename T>
inline
17493 (void)(result += scalar);
17505 template <
class P,
typename T>
inline
17508 return image + scalar;
17516 template <
class P,
typename T>
inline
17520 (void)(result -= scalar);
17529 template <
class P,
typename T>
inline
17533 (void)(result *= scalar);
17546 template <
class P,
typename T>
inline
17549 return image * scalar;
17557 template <
class P,
typename T>
inline
17561 (void)(result /= scalar);
17570 template <
class P,
typename T>
inline
17574 (void)(result ^= scalar);
17596 template <
class P1,
class P2>
inline
17600 (void)(result += image2);
17616 template <
class P1,
class P2>
inline
17620 (void)(result -= image2);
17636 template <
class P1,
class P2>
inline
17640 (void)(result *= image2);
17657 template <
class P1,
class P2>
inline
17661 (void)(result /= image2);
17678 template <
class P1,
class P2>
inline
17682 (void)(result ^= image2);
17688 #ifndef __PCL_NO_IMAGE_INSTANTIATE
17701 using FImage = GenericImage<FloatPixelTraits>;
17710 using DImage = GenericImage<DoublePixelTraits>;
17740 using UInt8Image = GenericImage<UInt8PixelTraits>;
17750 using UInt16Image = GenericImage<UInt16PixelTraits>;
17760 using UInt32Image = GenericImage<UInt32PixelTraits>;
17782 #endif // __PCL_NO_IMAGE_INSTANTIATE
17790 #ifndef __PCL_NO_IMAGE_VARIANT_AUTO
17792 #ifndef __PCL_ImageVariant_h
17796 #endif // __PCL_NO_IMAGE_VARIANT_AUTO
17800 #endif // __PCL_Image_h