PCL
GaussianFilter.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.8.5
6 // ----------------------------------------------------------------------------
7 // pcl/GaussianFilter.h - Released 2024-12-28T16:53:48Z
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_GaussianFilter_h
53 #define __PCL_GaussianFilter_h
54 
56 
57 #include <pcl/Defs.h>
58 
59 #include <pcl/KernelFilter.h>
60 #include <pcl/Math.h>
61 
62 namespace pcl
63 {
64 
65 // ----------------------------------------------------------------------------
66 
97 class PCL_CLASS GaussianFilter : public KernelFilter
98 {
99 public:
100 
105  GaussianFilter() = default;
106 
112  GaussianFilter( float sigma, float epsilon = 0.01, const String& name = String() )
113  {
114  Initialize( sigma, epsilon, 1, 0 );
115  Rename( name );
116  }
117 
124  GaussianFilter( float sigma, float epsilon, float rho, float theta = 0, const String& name = String() )
125  {
126  Initialize( sigma, epsilon, rho, theta );
127  Rename( name );
128  }
129 
135  GaussianFilter( int n, float epsilon = 0.01, const String& name = String() )
136  {
137  Initialize( n, epsilon, 1, 0 );
138  Rename( name );
139  }
140 
147  GaussianFilter( int n, float epsilon, float rho, float theta = 0, const String& name = String() )
148  {
149  Initialize( n, epsilon, rho, theta );
150  Rename( name );
151  }
152 
156  GaussianFilter( const GaussianFilter& ) = default;
157 
162 
165  KernelFilter* Clone() const override
166  {
167  return new GaussianFilter( *this );
168  }
169 
179  SeparableFilter AsSeparableFilter( float tolerance = __PCL_DEFAULT_FILTER_SEPARABILITY_TOLERANCE ) const override
180  {
181  if ( m_rho == 1 )
182  {
183  FVector v = coefficients.RowVector( Size()>>1 );
184  return SeparableFilter( v, v );
185  }
186  return SeparableFilter();
187  }
188 
196  bool IsSeparable() const override
197  {
198  return m_rho == 1;
199  }
200 
204  GaussianFilter& operator =( const GaussianFilter& x )
205  {
206  (void)KernelFilter::operator =( x );
207  m_sigma = x.m_sigma;
208  m_epsilon = x.m_epsilon;
209  m_rho = x.m_rho;
210  m_theta = x.m_theta;
211  return *this;
212  }
213 
217  GaussianFilter& operator =( GaussianFilter&& x )
218  {
219  (void)KernelFilter::operator =( std::move( x ) );
220  m_sigma = x.m_sigma;
221  m_epsilon = x.m_epsilon;
222  m_rho = x.m_rho;
223  m_theta = x.m_theta;
224  return *this;
225  }
226 
231  float SigmaX() const
232  {
233  return m_sigma;
234  }
235 
240  float SigmaY() const
241  {
242  return m_rho*m_sigma;
243  }
244 
251  float Sigma() const
252  {
253  return SigmaX();
254  }
255 
259  float Truncation() const
260  {
261  return m_epsilon;
262  }
263 
268  float AspectRatio() const
269  {
270  return m_rho;
271  }
272 
278  float RotationAngle() const
279  {
280  return m_theta;
281  }
282 
287  double FWHMx() const
288  {
289  return 2.3548200450309493 * m_sigma;
290  }
291 
296  double FWHMy() const
297  {
298  return m_rho * FWHMx();
299  }
300 
307  double FWHM() const
308  {
309  return FWHMx();
310  }
311 
317  void Set( float sigma, float epsilon, float rho, float theta )
318  {
319  Initialize( sigma, epsilon, rho, theta );
320  }
321 
327  void Set( float sigma, float epsilon, float rho )
328  {
329  Initialize( sigma, epsilon, rho, m_theta );
330  }
331 
337  void Set( float sigma, float epsilon )
338  {
339  Initialize( sigma, epsilon, m_rho, m_theta );
340  }
341 
347  void Set( float sigma )
348  {
349  Initialize( sigma, m_epsilon, m_rho, m_theta );
350  }
351 
355  void SetSigma( float sigma )
356  {
357  Set( sigma );
358  }
359 
364  void SetTruncation( float epsilon )
365  {
366  Set( m_sigma, epsilon );
367  }
368 
373  void SetAspectRatio( float rho )
374  {
375  Set( m_sigma, m_epsilon, rho );
376  }
377 
382  void SetRotationAngle( float theta )
383  {
384  Set( m_sigma, m_epsilon, m_rho, theta );
385  }
386 
393  void Resize( int n ) override
394  {
395  Initialize( n, m_epsilon, m_rho, m_theta );
396  }
397 
401  friend void Swap( GaussianFilter& x1, GaussianFilter& x2 )
402  {
403  pcl::Swap( static_cast<KernelFilter&>( x1 ), static_cast<KernelFilter&>( x2 ) );
404  pcl::Swap( x1.m_sigma, x2.m_sigma );
405  pcl::Swap( x1.m_rho, x2.m_rho );
406  pcl::Swap( x1.m_theta, x2.m_theta );
407  pcl::Swap( x1.m_epsilon, x2.m_epsilon );
408  }
409 
410 private:
411 
412  float m_sigma = 2; // standard deviation, horizontal axis
413  float m_rho = 1; // vertical:horizontal axes ratio
414  float m_theta = 0; // rotation angle in radians, [0,+pi]
415  float m_epsilon = 0.01F; // maximum truncation error in sigma units
416 
417  void Initialize( float s, float e, float r, float a )
418  {
419  PCL_PRECONDITION( s > 0 )
420  PCL_PRECONDITION( e > 0 )
421  PCL_PRECONDITION( r >= 0 && r <= 1 )
422  PCL_PRECONDITION( a >= 0 && a <= Const<float>::pi() )
423  m_sigma = Abs( s );
424  m_epsilon = Abs( e );
425  m_rho = Range( r, 0.0F, 1.0F );
426  m_theta = Range( a, 0.0F, Const<float>::pi() );
427  KernelFilter::Resize( 1 + (Max( 1, RoundInt( m_sigma * Sqrt( -2*Ln( m_epsilon ) ) ) ) << 1) );
428  Rebuild();
429  }
430 
431  void Initialize( int n, float e, float r, float a )
432  {
433  PCL_PRECONDITION( n == 0 || n >= 3 && (n & 1) != 0 )
434  PCL_PRECONDITION( e > 0 )
435  PCL_PRECONDITION( r >= 0 && r <= 1 )
436  PCL_PRECONDITION( a >= 0 && a <= Const<float>::pi() )
437  KernelFilter::Resize( n );
438  m_epsilon = Abs( e );
439  m_sigma = (Size() >> 1)/Sqrt( -2*Ln( m_epsilon ) );
440  m_rho = Range( r, 0.0F, 1.0F );
441  m_theta = Range( a, 0.0F, Const<float>::pi() );
442  Rebuild();
443  }
444 
445  void Rebuild()
446  {
447  int size = Size();
448  if ( size == 0 )
449  return;
450 
451  float* __restrict__ h = *coefficients;
452  double sx = m_sigma;
453  double sy = m_rho * sx;
454 
455  if ( m_theta == 0 || m_rho == 1 )
456  {
457  double twosx2 = 2*sx*sx;
458  double twosy2 = 2*sy*sy;
459  for ( int n2 = size >> 1, dy = -n2; dy <= n2; ++dy )
460  if ( dy > 0 )
461  for ( int dx = 0; dx < size; ++dx, ++h )
462  *h = *(h - ((dy+dy)*size));
463  else
464  for ( int dx = -n2; dx <= n2; ++dx, ++h )
465  *h = (dx > 0) ? *(h - (dx+dx)) : float( Exp( -(dx*dx/twosx2 + dy*dy/twosy2) ) );
466  }
467  else
468  {
469  double st, ct; SinCos( double( m_theta ), st, ct );
470  double sct = st*ct;
471  double st2 = st*st;
472  double ct2 = ct*ct;
473  double twosx2 = 2*sx*sx;
474  double twosy2 = 2*sy*sy;
475  double p1 = ct2/twosx2 + st2/twosy2;
476  double p2 = sct/twosy2 - sct/twosx2;
477  double p3 = st2/twosx2 + ct2/twosy2;
478  for ( int n2 = size >> 1, dy = -n2; dy <= n2; ++dy )
479  {
480  double twop2dy = 2*p2*dy;
481  double p3dy2 = p3*dy*dy;
482  for ( int dx = -n2; dx <= n2; ++dx, ++h )
483  *h = float( Exp( -(p1*dx*dx + twop2dy*dx + p3dy2) ) );
484  }
485  }
486  }
487 };
488 
489 // ----------------------------------------------------------------------------
490 
491 } // pcl
492 
493 #endif // __PCL_GaussianFilter_h
494 
495 // ----------------------------------------------------------------------------
496 // EOF pcl/GaussianFilter.h - Released 2024-12-28T16:53:48Z
Fundamental numeric constants.
Definition: Constants.h:73
A kernel filter implementing a discrete Gaussian distribution in two dimensions.
void Set(float sigma, float epsilon, float rho, float theta)
GaussianFilter(int n, float epsilon, float rho, float theta=0, const String &name=String())
friend void Swap(GaussianFilter &x1, GaussianFilter &x2)
void SetSigma(float sigma)
void Resize(int n) override
void Set(float sigma)
float Sigma() const
GaussianFilter()=default
GaussianFilter(float sigma, float epsilon, float rho, float theta=0, const String &name=String())
float RotationAngle() const
double FWHMx() const
void Set(float sigma, float epsilon, float rho)
SeparableFilter AsSeparableFilter(float tolerance=__PCL_DEFAULT_FILTER_SEPARABILITY_TOLERANCE) const override
GaussianFilter(float sigma, float epsilon=0.01, const String &name=String())
void SetAspectRatio(float rho)
GaussianFilter(const GaussianFilter &)=default
double FWHMy() const
float AspectRatio() const
bool IsSeparable() const override
void SetRotationAngle(float theta)
KernelFilter * Clone() const override
void Set(float sigma, float epsilon)
void SetTruncation(float epsilon)
float SigmaY() const
double FWHM() const
GaussianFilter(GaussianFilter &&)=default
float Truncation() const
GaussianFilter(int n, float epsilon=0.01, const String &name=String())
float SigmaX() const
Generic vector of arbitrary length.
Definition: Vector.h:107
Kernel filter in two dimensions.
Definition: KernelFilter.h:90
Separable filter in two dimensions.
Unicode (UTF-16) string.
Definition: String.h:8146
Complex< T > Sqrt(const Complex< T > &c) noexcept
Definition: Complex.h:688
Complex< T > Exp(const Complex< T > &c) noexcept
Definition: Complex.h:728
Complex< T > Ln(const Complex< T > &c) noexcept
Definition: Complex.h:739
T Abs(const Complex< T > &c) noexcept
Definition: Complex.h:443
void SinCos(T x, T &sx, T &cx) noexcept
Definition: Math.h:1101
int RoundInt(T x) noexcept
Definition: Math.h:1550
void Swap(GenericPoint< T > &p1, GenericPoint< T > &p2) noexcept
Definition: Point.h:1459
constexpr const T & Range(const T &x, const T &a, const T &b) noexcept
Definition: Utility.h:190
constexpr const T & Max(const T &a, const T &b) noexcept
Definition: Utility.h:119
PCL root namespace.
Definition: AbstractImage.h:77