PCL
HistogramTransformation.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.4.0
6 // ----------------------------------------------------------------------------
7 // pcl/HistogramTransformation.h - Released 2020-07-31T19:33:04Z
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-2020 Pleiades Astrophoto S.L. All Rights Reserved.
13 //
14 // Redistribution and use in both source and binary forms, with or without
15 // modification, is permitted provided that the following conditions are met:
16 //
17 // 1. All redistributions of source code must retain the above copyright
18 // notice, this list of conditions and the following disclaimer.
19 //
20 // 2. All redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
25 // of their contributors, may be used to endorse or promote products derived
26 // from this software without specific prior written permission. For written
27 // permission, please contact info@pixinsight.com.
28 //
29 // 4. All products derived from this software, in any form whatsoever, must
30 // reproduce the following acknowledgment in the end-user documentation
31 // and/or other materials provided with the product:
32 //
33 // "This product is based on software from the PixInsight project, developed
34 // by Pleiades Astrophoto and its contributors (http://pixinsight.com/)."
35 //
36 // Alternatively, if that is where third-party acknowledgments normally
37 // appear, this acknowledgment must be reproduced in the product itself.
38 //
39 // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
40 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
43 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
45 // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
46 // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 // POSSIBILITY OF SUCH DAMAGE.
50 // ----------------------------------------------------------------------------
51 
52 #ifndef __PCL_HistogramTransformation_h
53 #define __PCL_HistogramTransformation_h
54 
56 
57 #include <pcl/Defs.h>
58 
59 #include <pcl/Array.h>
61 #include <pcl/ParallelProcess.h>
62 
63 namespace pcl
64 {
65 
66 // ----------------------------------------------------------------------------
67 
68 class PCL_CLASS Histogram;
69 
77 {
78 public:
79 
84 
103  HistogramTransformation( double mb = 0.5,
104  double sc = 0, double hc = 1,
105  double lr = 0, double hr = 1 )
106  {
107  PCL_PRECONDITION( mb >= 0 && mb <= 1 )
108  PCL_PRECONDITION( sc >= 0 && sc <= 1 )
109  PCL_PRECONDITION( hc >= 0 && hc <= 1 )
110  PCL_PRECONDITION( lr <= 0 )
111  PCL_PRECONDITION( hr >= 1 )
112  m_midtonesBalance = pcl::Range( mb, 0.0, 1.0 );
113  m_clipLow = pcl::Range( sc, 0.0, 1.0 );
114  m_clipHigh = pcl::Range( hc, 0.0, 1.0 );
115  if ( m_clipHigh < m_clipLow )
116  pcl::Swap( m_clipLow, m_clipHigh );
117  m_expandLow = Min( lr, 0.0 );
118  m_expandHigh = Max( 1.0, hr );
119  UpdateFlags();
120  }
121 
126 
131 
136  {
137  }
138 
142  HistogramTransformation& operator =( const HistogramTransformation& ) = default;
143 
147  HistogramTransformation& operator =( HistogramTransformation&& ) = default;
148 
153  {
154  return 1 + m_transformChain.Length();
155  }
156 
161  const HistogramTransformation& operator []( size_type index ) const
162  {
163  return (index == 0) ? *this : m_transformChain[index-1];
164  }
165 
170  HistogramTransformation& operator []( size_type index )
171  {
172  return (index == 0) ? *this : m_transformChain[index-1];
173  }
174 
181  {
182  return *this;
183  }
184 
191  {
192  return *this;
193  }
194 
199  void Add( const HistogramTransformation& H )
200  {
201  m_transformChain.Add( H );
202  }
203 
206  double MidtonesBalance() const
207  {
208  return m_midtonesBalance;
209  }
210 
213  double ShadowsClipping() const
214  {
215  return m_clipLow;
216  }
217 
220  double HighlightsClipping() const
221  {
222  return m_clipHigh;
223  }
224 
227  double LowRange() const
228  {
229  return m_expandLow;
230  }
231 
234  double HighRange() const
235  {
236  return m_expandHigh;
237  }
238 
242  {
243  return m_midtonesBalance == 0.5
244  && m_clipLow == 0 && m_clipHigh == 1
245  && m_expandLow == 0 && m_expandHigh == 1;
246  }
247 
250  bool IsIdentityTransformationSet() const;
251 
254  void SetMidtonesBalance( double b )
255  {
256  PCL_PRECONDITION( b >= 0 && b <= 1 )
257  m_midtonesBalance = pcl::Range( b, 0.0, 1.0 );
258  UpdateFlags();
259  }
260 
263  void SetShadowsClipping( double c )
264  {
265  PCL_PRECONDITION( c >= 0 && c <= 1 )
266  m_clipLow = pcl::Range( c, 0.0, 1.0 );
267  if ( m_clipHigh < m_clipLow )
268  pcl::Swap( m_clipLow, m_clipHigh );
269  UpdateFlags();
270  }
271 
274  void SetHighlightsClipping( double c )
275  {
276  PCL_PRECONDITION( c >= 0 && c <= 1 )
277  m_clipHigh = pcl::Range( c, 0.0, 1.0 );
278  if ( m_clipHigh < m_clipLow )
279  pcl::Swap( m_clipLow, m_clipHigh );
280  UpdateFlags();
281  }
282 
285  void SetClipping( double sc, double hc )
286  {
287  PCL_PRECONDITION( sc >= 0 && sc <= 1 )
288  PCL_PRECONDITION( hc >= 0 && hc <= 1 )
289  m_clipLow = pcl::Range( sc, 0.0, 1.0 );
290  m_clipHigh = pcl::Range( hc, 0.0, 1.0 );
291  if ( m_clipHigh < m_clipLow )
292  pcl::Swap( m_clipLow, m_clipHigh );
293  UpdateFlags();
294  }
295 
298  void SetLowRange( double r )
299  {
300  PCL_PRECONDITION( r <= 0 )
301  m_expandLow = Min( 0.0, r );
302  UpdateFlags();
303  }
304 
307  void SetHighRange( double r )
308  {
309  PCL_PRECONDITION( r >= 1 )
310  m_expandHigh = Max( 1.0, r );
311  UpdateFlags();
312  }
313 
316  void SetRange( double lr, double hr )
317  {
318  PCL_PRECONDITION( lr <= 0 )
319  PCL_PRECONDITION( hr >= 1 )
320  m_expandLow = Min( 0.0, lr );
321  m_expandHigh = Max( 1.0, hr );
322  UpdateFlags();
323  }
324 
329  void Reset()
330  {
331  m_midtonesBalance = 0.5;
332  m_clipLow = 0;
333  m_clipHigh = 1;
334  m_expandLow = 0;
335  m_expandHigh = 1;
336  m_transformChain.Clear();
337  UpdateFlags();
338  }
339 
340  // Avoid "hides virtual function in base" warnings by clang
342 
345  void Apply( double*, size_type, double x0 = 0, double x1 = 1 ) const;
346 
349  void Apply( float*, size_type, float x0 = 0, float x1 = 1 ) const;
350 
353  void Apply( Histogram& dstH, const Histogram& srcH ) const;
354 
357  void Make8BitLUT( uint8* ) const;
358 
361  void Make16BitLUT( uint8* ) const;
362 
365  void Make16BitLUT( uint16* ) const;
366 
369  void Make20BitLUT( uint8* ) const;
370 
373  void Make20BitLUT( uint16* ) const;
374 
377  void Make24BitLUT( uint8* ) const;
378 
381  void Make24BitLUT( uint16* ) const;
382 
388  static double MidtonesTransferFunction( double m, double x )
389  {
390  /*
391  * Bulirsch-Stoer algorithm for a diagonal rational interpolation
392  * function with three fixed data points: (0,0) (m,1/2) (1,1).
393  *
394  * This is the MTF function after direct substitution in the B-S
395  * equations:
396  *
397  * double r = 1 + 0.5/((x - m)/(x - 1)/2 - 1);
398  * return r + r/(x/(x - 1) * (1 - r/(r - 0.5)) - 1);
399  *
400  * We can simplify:
401  *
402  * double r = (m - 1)/(x + m - 2);
403  *
404  * and then we can further simplify to:
405  *
406  * return (m - 1)*x/((2*m - 1)*x - m);
407  *
408  * Finally, precalculating (m - 1) we can save a multiplication.
409  */
410  if ( x > 0 ) // guard us against degenerate cases
411  {
412  if ( x < 1 )
413  {
414  double m1 = m - 1;
415  return m1*x/((m + m1)*x - m);
416  }
417  return 1;
418  }
419  return 0;
420  }
421 
425  static double MTF( double m, double x )
426  {
427  return MidtonesTransferFunction( m, x );
428  }
429 
433  void Transform( double& value ) const
434  {
435  if ( m_flags.hasClipping )
436  value = m_flags.hasDelta ? ((value <= m_clipLow) ? 0.0 : ((value >= m_clipHigh) ? 1.0 : (value - m_clipLow)/m_flags.d)) : m_clipLow;
437  if ( m_flags.hasMTF )
438  value = HistogramTransformation::MTF( m_midtonesBalance, value );
439  if ( m_flags.hasRange )
440  value = (value - m_expandLow)/m_flags.dr;
441  }
442 
448  struct Flags
449  {
450  double d = 1.0;
451  double dr = 1.0;
452  bool hasClipping = false;
453  bool hasMTF = false;
454  bool hasRange = false;
455  bool hasDelta = false;
456 
460  Flags() = default;
461 
465  Flags( const Flags& ) = default;
466 
472  {
473  hasClipping = H.m_clipLow != 0 || H.m_clipHigh != 1;
474  hasMTF = H.m_midtonesBalance != 0.5;
475  hasRange = H.m_expandLow != 0 || H.m_expandHigh != 1;
476  hasDelta = false;
477  if ( hasClipping )
478  {
479  d = H.m_clipHigh - H.m_clipLow;
480  hasDelta = 1 + d != 1;
481  }
482  if ( hasRange )
483  dr = H.m_expandHigh - H.m_expandLow;
484  }
485  };
486 
491  {
492  return m_flags;
493  }
494 
495 private:
496 
497  double m_midtonesBalance = 0.5; // midtones balance
498  double m_clipLow = 0; // shadows clipping point
499  double m_clipHigh = 1; // highlights clipping point
500  double m_expandLow = 0; // shadows dynamic range expansion
501  double m_expandHigh = 1; // highlights dynamic range expansion
502  Flags m_flags; // transformation flags
503  transformation_list m_transformChain; // more transformations
504 
508  void UpdateFlags()
509  {
510  m_flags = Flags( *this );
511  }
512 
513  void Apply( pcl::Image& ) const override;
514  void Apply( pcl::DImage& ) const override;
515  void Apply( pcl::UInt8Image& ) const override;
516  void Apply( pcl::UInt16Image& ) const override;
517  void Apply( pcl::UInt32Image& ) const override;
518 
519  friend class LUT2408Thread;
520  friend class LUT2416Thread;
521 };
522 
523 // ----------------------------------------------------------------------------
524 
525 } // pcl
526 
527 #endif // __PCL_HistogramTransformation_h
528 
529 // ----------------------------------------------------------------------------
530 // EOF pcl/HistogramTransformation.h - Released 2020-07-31T19:33:04Z
Array< HistogramTransformation > transformation_list
Complex< T1 > operator*(const Complex< T1 > &c1, const Complex< T2 > &c2)
Definition: Complex.h:550
unsigned char uint8
Definition: Defs.h:576
void Swap(GenericPoint< T > &p1, GenericPoint< T > &p2)
Definition: Point.h:1404
void Add(const HistogramTransformation &H)
PCL root namespace.
Definition: AbstractImage.h:76
Multiple histogram transformation.
16-bit unsigned integer image.
constexpr const T & Range(const T &x, const T &a, const T &b)
Definition: Utility.h:190
size_t size_type
Definition: Defs.h:543
void Apply(FI i, FI j, F f)
Definition: Utility.h:249
static double MidtonesTransferFunction(double m, double x)
constexpr const T & Max(const T &a, const T &b)
Definition: Utility.h:119
unsigned short uint16
Definition: Defs.h:588
constexpr const T & Min(const T &a, const T &b)
Definition: Utility.h:90
Discrete image histogram function.
Definition: Histogram.h:75
void SetRange(double lr, double hr)
64-bit floating point real image.
32-bit unsigned integer image.
8-bit unsigned integer image.
virtual void Apply(pcl::Image &image) const
Root base class of all PCL image transformations.
Flags(const HistogramTransformation &H)
static double MTF(double m, double x)
Characterizes a histogram transformation pertaining to a histogram transformation chain...
void SetClipping(double sc, double hc)
32-bit floating point real image.
void Transform(double &value) const
A process using multiple concurrent execution threads.
HistogramTransformation(double mb=0.5, double sc=0, double hc=1, double lr=0, double hr=1)