PCL
GeometricTransformation.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.7.0
6 // ----------------------------------------------------------------------------
7 // pcl/GeometricTransformation.h - Released 2024-06-18T15:48:54Z
8 // ----------------------------------------------------------------------------
9 // This file is part of the PixInsight Class Library (PCL).
10 // PCL is a multiplatform C++ framework for development of PixInsight modules.
11 //
12 // Copyright (c) 2003-2024 Pleiades Astrophoto S.L. All Rights Reserved.
13 //
14 // Redistribution and use in both source and binary forms, with or without
15 // modification, is permitted provided that the following conditions are met:
16 //
17 // 1. All redistributions of source code must retain the above copyright
18 // notice, this list of conditions and the following disclaimer.
19 //
20 // 2. All redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
25 // of their contributors, may be used to endorse or promote products derived
26 // from this software without specific prior written permission. For written
27 // permission, please contact info@pixinsight.com.
28 //
29 // 4. All products derived from this software, in any form whatsoever, must
30 // reproduce the following acknowledgment in the end-user documentation
31 // and/or other materials provided with the product:
32 //
33 // "This product is based on software from the PixInsight project, developed
34 // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
35 //
36 // Alternatively, if that is where third-party acknowledgments normally
37 // appear, this acknowledgment must be reproduced in the product itself.
38 //
39 // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
40 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
43 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
45 // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
46 // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 // POSSIBILITY OF SUCH DAMAGE.
50 // ----------------------------------------------------------------------------
51 
52 #ifndef __PCL_GeometricTransformation_h
53 #define __PCL_GeometricTransformation_h
54 
56 
57 #include <pcl/Defs.h>
58 #include <pcl/Diagnostics.h>
59 
61 #include <pcl/PixelInterpolation.h>
62 
63 namespace pcl
64 {
65 
66 // ----------------------------------------------------------------------------
67 
77 class PCL_CLASS GeometricTransformation : public virtual ImageTransformation
78 {
79 public:
80 
85 
90 
95 
99  GeometricTransformation& operator =( const GeometricTransformation& ) = default;
100 
105 
110  {
111  }
112 
127  virtual void GetNewSizes( int& width, int& height ) const = 0;
128 
132  virtual bool SupportsGammaCorrection() const
133  {
134  return false;
135  }
136 
140  bool IsGammaCorrectionEnabled() const
141  {
142  return m_gammaCorrected;
143  }
144 
148  void EnableGammaCorrection( bool enable = true )
149  {
150  m_gammaCorrected = enable;
151  }
152 
156  void DisableGammaCorrection( bool disable = true )
157  {
158  EnableGammaCorrection( !disable );
159  }
160 
164  const RGBColorSystem& RGBWorkingSpace() const
165  {
166  return m_rgbws.IsNull() ? RGBColorSystem::sRGB : *m_rgbws;
167  }
168 
172  void SetRGBWorkingSpace( const RGBColorSystem& rgbws )
173  {
174  m_rgbws = new RGBColorSystem( rgbws );
175  }
176 
180  void ClearRGBWorkingSpace()
181  {
182  m_rgbws.Destroy();
183  }
184 
188  template <class P>
189  void ApplyGammaCorrection( typename P::sample* samples, size_type length,
190  AbstractImage::ThreadData& threadData, int maxProcessors = PCL_MAX_PROCESSORS ) const
191  {
192  if ( m_rgbws.IsNull() || m_rgbws->IsSRGB() )
193  ApplySRGBGammaCorrection<P>( samples, length, threadData, maxProcessors );
194  else
195  ApplyGammaExponentCorrection<P>( samples, length, m_rgbws->Gamma(), threadData, maxProcessors );
196  }
197 
201  template <class P>
202  void ApplyInverseGammaCorrection( typename P::sample* samples, size_type length,
203  AbstractImage::ThreadData& threadData, int maxProcessors = PCL_MAX_PROCESSORS ) const
204  {
205  if ( m_rgbws.IsNull() || m_rgbws->IsSRGB() )
206  ApplyInverseSRGBGammaCorrection<P>( samples, length, threadData, maxProcessors );
207  else
208  ApplyInverseGammaExponentCorrection<P>( samples, length, m_rgbws->Gamma(), threadData, maxProcessors );
209  }
210 
231  template <class P>
232  static void ApplyGammaExponentCorrection( typename P::sample* samples, size_type length, double gamma,
233  AbstractImage::ThreadData& threadData, int maxProcessors = PCL_MAX_PROCESSORS )
234  {
235  PCL_PRECONDITION( gamma > 0 )
236  if ( samples != nullptr )
237  if ( length > 0 )
238  if ( gamma != 1 )
239  {
240  Array<size_type> L = pcl::Thread::OptimalThreadLoads( length, 1024/*overheadLimit*/, maxProcessors );
242  for ( size_type i = 0, n = 0; i < L.Length(); n += L[i++] )
243  threads.Add( new GammaThread<P>( threadData, gamma, samples, n, n + L[i] ) );
244  AbstractImage::RunThreads( threads, threadData );
245  threads.Destroy();
246  }
247  }
248 
270  template <class P>
271  static void ApplyInverseGammaExponentCorrection( typename P::sample* samples, size_type length, double gamma,
272  AbstractImage::ThreadData& threadData, int maxProcessors = PCL_MAX_PROCESSORS )
273  {
274  PCL_PRECONDITION( gamma > 0 )
275  if ( samples != nullptr )
276  if ( length > 0 )
277  if ( gamma != 1 )
278  {
279  Array<size_type> L = pcl::Thread::OptimalThreadLoads( length, 1024/*overheadLimit*/, maxProcessors );
281  for ( size_type i = 0, n = 0; i < L.Length(); n += L[i++] )
282  threads.Add( new GammaInvThread<P>( threadData, gamma, samples, n, n + L[i] ) );
283  AbstractImage::RunThreads( threads, threadData );
284  threads.Destroy();
285  }
286  }
287 
305  template <class P>
306  static void ApplySRGBGammaCorrection( typename P::sample* samples, size_type length,
307  AbstractImage::ThreadData& threadData, int maxProcessors = PCL_MAX_PROCESSORS )
308  {
309  if ( samples != nullptr )
310  if ( length > 0 )
311  {
312  Array<size_type> L = pcl::Thread::OptimalThreadLoads( length, 1024/*overheadLimit*/, maxProcessors );
314  for ( size_type i = 0, n = 0; i < L.Length(); n += L[i++] )
315  threads.Add( new SRGBGammaThread<P>( threadData, samples, n, n + L[i] ) );
316  AbstractImage::RunThreads( threads, threadData );
317  threads.Destroy();
318  }
319  }
320 
338  template <class P>
339  static void ApplyInverseSRGBGammaCorrection( typename P::sample* samples, size_type length,
340  AbstractImage::ThreadData& threadData, int maxProcessors = PCL_MAX_PROCESSORS )
341  {
342  if ( samples != nullptr )
343  if ( length > 0 )
344  {
345  Array<size_type> L = pcl::Thread::OptimalThreadLoads( length, 1024/*overheadLimit*/, maxProcessors );
347  for ( size_type i = 0, n = 0; i < L.Length(); n += L[i++] )
348  threads.Add( new SRGBGammaInvThread<P>( threadData, samples, n, n + L[i] ) );
349  AbstractImage::RunThreads( threads, threadData );
350  threads.Destroy();
351  }
352  }
353 
354 protected:
355 
356  bool m_gammaCorrected = false;
358 
359  template <class P>
360  class GammaThread : public pcl::Thread
361  {
362  public:
363 
364  using sample_type = typename P::sample;
365 
366  GammaThread( AbstractImage::ThreadData& data, double gamma, sample_type* samples, size_type start, size_type end )
367  : m_data( data )
368  , m_gamma( gamma )
369  , m_samples( samples )
370  , m_start( start )
371  , m_end( end )
372  {
373  }
374 
375  PCL_HOT_FUNCTION void Run() override
376  {
378 
379  sample_type* __restrict__ f = m_samples + m_start;
380  for ( size_type i = m_start; i < m_end; ++i, ++f )
381  {
382  double x; P::FromSample( x, *f );
383  *f = P::ToSample( pcl::Pow( x, m_gamma ) );
384 
385  UPDATE_THREAD_MONITOR( 256 )
386  }
387  }
388 
389  private:
390 
391  AbstractImage::ThreadData& m_data;
392  double m_gamma;
393  sample_type* m_samples;
394  size_type m_start;
395  size_type m_end;
396  };
397 
398  template <class P>
399  class GammaInvThread : public pcl::Thread
400  {
401  public:
402 
403  using sample_type = typename P::sample;
404 
405  GammaInvThread( AbstractImage::ThreadData& data, double gamma, sample_type* samples, size_type start, size_type end )
406  : m_data( data )
407  , m_gammaInv( 1/gamma )
408  , m_samples( samples )
409  , m_start( start )
410  , m_end( end )
411  {
412  }
413 
414  PCL_HOT_FUNCTION void Run() override
415  {
417 
418  sample_type* __restrict__ f = m_samples + m_start;
419  for ( size_type i = m_start; i < m_end; ++i, ++f )
420  {
421  double x; P::FromSample( x, *f );
422  *f = P::ToSample( pcl::Pow( x, m_gammaInv ) );
423 
424  UPDATE_THREAD_MONITOR( 256 )
425  }
426  }
427 
428  private:
429 
430  AbstractImage::ThreadData& m_data;
431  double m_gammaInv;
432  sample_type* m_samples;
433  size_type m_start;
434  size_type m_end;
435  };
436 
437  template <class P>
438  class SRGBGammaThread : public pcl::Thread
439  {
440  public:
441 
442  using sample_type = typename P::sample;
443 
444  SRGBGammaThread( AbstractImage::ThreadData& data, sample_type* samples, size_type start, size_type end )
445  : m_data( data )
446  , m_samples( samples )
447  , m_start( start )
448  , m_end( end )
449  {
450  }
451 
452  PCL_HOT_FUNCTION void Run() override
453  {
455 
456  sample_type* __restrict__ f = m_samples + m_start;
457  for ( size_type i = m_start; i < m_end; ++i, ++f )
458  {
459  double x; P::FromSample( x, *f );
460  *f = P::ToSample( RGBColorSystem::SRGBToLinear( x ) );
461 
462  UPDATE_THREAD_MONITOR( 256 )
463  }
464  }
465 
466  private:
467 
468  AbstractImage::ThreadData& m_data;
469  sample_type* m_samples;
470  size_type m_start;
471  size_type m_end;
472  };
473 
474  template <class P>
475  class SRGBGammaInvThread : public pcl::Thread
476  {
477  public:
478 
479  using sample_type = typename P::sample;
480 
481  SRGBGammaInvThread( AbstractImage::ThreadData& data, sample_type* samples, size_type start, size_type end )
482  : m_data( data )
483  , m_samples( samples )
484  , m_start( start )
485  , m_end( end )
486  {
487  }
488 
489  PCL_HOT_FUNCTION void Run() override
490  {
492 
493  sample_type* __restrict__ f = m_samples + m_start;
494  for ( size_type i = m_start; i < m_end; ++i, ++f )
495  {
496  double x; P::FromSample( x, *f );
497  *f = P::ToSample( RGBColorSystem::LinearToSRGB( x ) );
498 
499  UPDATE_THREAD_MONITOR( 256 )
500  }
501  }
502 
503  private:
504 
505  AbstractImage::ThreadData& m_data;
506  sample_type* m_samples;
507  size_type m_start;
508  size_type m_end;
509  };
510 };
511 
512 // ----------------------------------------------------------------------------
513 
528 {
529 public:
530 
540  : m_interpolation( &p )
541  {
542  PCL_CHECK( m_interpolation != nullptr )
543  }
544 
554 
559  : GeometricTransformation( std::move( x ) )
560  , m_interpolation( x.m_interpolation )
561  , m_unclipped( x.m_unclipped )
562  {
563  x.m_interpolation = nullptr;
564  }
565 
578 
583  {
584  GeometricTransformation::operator =( std::move( x ) );
585  m_interpolation = x.m_interpolation;
586  x.m_interpolation = nullptr;
587  m_unclipped = x.m_unclipped;
588  return *this;
589  }
590 
596  {
597  PCL_CHECK( m_interpolation != nullptr )
598  return *m_interpolation;
599  }
600 
606  {
607  PCL_CHECK( m_interpolation != nullptr )
608  return *m_interpolation;
609  }
610 
624  {
625  m_interpolation = &p;
626  PCL_CHECK( m_interpolation != nullptr )
627  }
628 
640  {
641  return m_unclipped;
642  }
643 
648  void EnableUnclippedInterpolation( bool enable = true )
649  {
650  m_unclipped = enable;
651  }
652 
657  void DisableUnclippedInterpolation( bool disable = true )
658  {
659  EnableUnclippedInterpolation( !disable );
660  }
661 
662 protected:
663 
664  PixelInterpolation* m_interpolation = nullptr;
665  bool m_unclipped = false;
666 };
667 
668 // ----------------------------------------------------------------------------
669 
670 } // pcl
671 
672 #endif // __PCL_GeometricTransformation_h
673 
674 // ----------------------------------------------------------------------------
675 // EOF pcl/GeometricTransformation.h - Released 2024-06-18T15:48:54Z
static void RunThreads(ReferenceArray< thread > &threads, ThreadData &data, bool useAffinity=true)
Generic dynamic array.
Definition: Array.h:100
A smart pointer able to generate dynamically allocated copies of the objects pointed to by other smar...
Definition: AutoPointer.h:696
Abstract base class of all PCL geometric image transformations.
GeometricTransformation(GeometricTransformation &&)=default
static void ApplyInverseSRGBGammaCorrection(typename P::sample *samples, size_type length, AbstractImage::ThreadData &threadData, int maxProcessors=PCL_MAX_PROCESSORS)
virtual void GetNewSizes(int &width, int &height) const =0
GeometricTransformation & operator=(const GeometricTransformation &)=default
static void ApplyGammaExponentCorrection(typename P::sample *samples, size_type length, double gamma, AbstractImage::ThreadData &threadData, int maxProcessors=PCL_MAX_PROCESSORS)
GeometricTransformation(const GeometricTransformation &)=default
static void ApplySRGBGammaCorrection(typename P::sample *samples, size_type length, AbstractImage::ThreadData &threadData, int maxProcessors=PCL_MAX_PROCESSORS)
static void ApplyInverseGammaExponentCorrection(typename P::sample *samples, size_type length, double gamma, AbstractImage::ThreadData &threadData, int maxProcessors=PCL_MAX_PROCESSORS)
Root base class of all PCL image transformations.
Abstract base class of all PCL interpolating geometric image transformations.
InterpolatingGeometricTransformation(const InterpolatingGeometricTransformation &)=default
InterpolatingGeometricTransformation(InterpolatingGeometricTransformation &&x)
const PixelInterpolation & Interpolation() const
Abstract root base class for all pixel interpolation algorithms.
static const RGBColorSystem sRGB
static double LinearToSRGB(double x)
static double SRGBToLinear(double x)
Dynamic array of pointers to objects providing direct iteration and element access by reference.
void Destroy(iterator i, size_type n=1)
void Add(const ReferenceArray &x)
Client-side interface to a PixInsight thread.
Definition: Thread.h:130
static Array< size_type > OptimalThreadLoads(size_type count, size_type overheadLimit=1u, int maxThreads=PCL_MAX_PROCESSORS)
Complex< T1 > Pow(const Complex< T1 > &c, T2 x) noexcept
Definition: Complex.h:747
size_t size_type
Definition: Defs.h:609
#define INIT_THREAD_MONITOR()
Declares and initializes local variables used for synchronization of thread status monitoring.
#define UPDATE_THREAD_MONITOR(N)
Synchronized status monitoring of a set of image processing threads.
PCL root namespace.
Definition: AbstractImage.h:77
Thread synchronization data for status monitoring of parallel image processing tasks.