PCL
StructuringElement.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.7.0
6 // ----------------------------------------------------------------------------
7 // pcl/StructuringElement.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_StructuringElement_h
53 #define __PCL_StructuringElement_h
54 
56 
57 #include <pcl/Defs.h>
58 #include <pcl/Diagnostics.h>
59 
60 #include <pcl/Atomic.h>
61 #include <pcl/AutoLock.h>
62 #include <pcl/Math.h>
63 #include <pcl/Rotate.h> // Reverse()
64 #include <pcl/StringList.h> // BitmapStructure
65 #include <pcl/Utility.h>
66 #include <pcl/Vector.h>
67 
68 #include <memory.h>
69 
70 namespace pcl
71 {
72 
73 // ----------------------------------------------------------------------------
74 
107 class PCL_CLASS StructuringElement
108 {
109 public:
110 
115 
120 
125 
130 
135  StructuringElement( int size = 3, int n = 1 )
136  : m_size( Max( 3, size|1 ) )
137  , m_mask( Max( 1, n ) )
138  , m_count( 0, Max( 1, n ) )
139  {
140  PCL_PRECONDITION( size >= 3 )
141  PCL_PRECONDITION( (size & 1) != 0 )
142  PCL_PRECONDITION( n >= 1 )
143  for ( int k = 0; k < NumberOfWays(); ++k )
144  m_mask[k] = existence_mask( existence_mask_element( 0 ), NumberOfElements() );
145  }
146 
151  : m_size( x.m_size )
152  , m_mask( x.NumberOfWays() )
153  , m_count( 0, x.NumberOfWays() )
154  {
155  for ( int k = 0; k < NumberOfWays(); ++k )
156  m_mask[k] = existence_mask( existence_mask_element( 0 ), NumberOfElements() );
157  }
158 
163  {
164  }
165 
170  virtual StructuringElement* Clone() const = 0;
171 
175  StructuringElement& operator =( const StructuringElement& x )
176  {
177  if ( &x != this )
178  {
179  volatile AutoLock lock( m_mutex );
180  m_size = x.m_size;
181  m_mask = existence_mask_set( x.NumberOfWays() );
182  m_count = existence_mask_count( 0, x.NumberOfWays() );
183  m_reflected = false;
184  m_initialized = 0;
185  for ( int k = 0; k < NumberOfWays(); ++k )
186  m_mask[k] = existence_mask( existence_mask_element( 0 ), NumberOfElements() );
187  }
188  return *this;
189  }
190 
194  int NumberOfWays() const
195  {
196  return int( m_mask.Length() );
197  }
198 
202  int Size() const
203  {
204  return m_size;
205  }
206 
211  int NumberOfElements() const
212  {
213  return m_size*m_size;
214  }
215 
228  virtual bool IsBox( int k ) const
229  {
230  PCL_PRECONDITION( k >= 0 && k < NumberOfWays() )
231  Initialize();
232  return m_count[k] == NumberOfElements();
233  }
234 
247  virtual bool ElementExists( int i, int j, int k ) const
248  {
249  PCL_PRECONDITION( i >= 0 && i < m_size )
250  PCL_PRECONDITION( j >= 0 && j < m_size )
251  PCL_PRECONDITION( k >= 0 && k < NumberOfWays() )
252  return true;
253  }
254 
276  template <typename T>
277  void PeekElements( T* h1, int& nh1, const T* h, int k ) const
278  {
279  PCL_PRECONDITION( h1 != 0 )
280  PCL_PRECONDITION( h != 0 )
281  PCL_PRECONDITION( k >= 0 && k < NumberOfWays() )
282  Initialize();
283  nh1 = 0;
284  for ( existence_mask::const_iterator m = m_mask[k].Begin(), m1 = m_mask[k].End(); m < m1; ++m, ++h )
285  if ( *m )
286  {
287  *h1++ = *h;
288  ++nh1;
289  }
290  }
291 
299  void Reflect()
300  {
301  Initialize();
302  for ( existence_mask_set::iterator i = m_mask.Begin(); i != m_mask.End(); ++i )
303  pcl::Reverse( i->Begin(), i->End() );
304  m_reflected = !m_reflected;
305  }
306 
312  bool IsReflected() const
313  {
314  return m_reflected;
315  }
316 
338  void Initialize() const
339  {
340  if ( !m_initialized )
341  {
342  volatile AutoLock lock( m_mutex );
343  if ( m_initialized.Load() == 0 )
344  {
345  int N = NumberOfWays();
346  for ( int k = 0; k < N; ++k )
347  {
348  m_count[k] = 0; // redundant, but doesn't hurt
349  existence_mask::iterator m = m_mask[k].Begin();
350  for ( int i = 0; i < m_size; ++i )
351  for ( int j = 0; j < m_size; ++j, ++m )
352  if ( ElementExists( i, j, k ) )
353  {
354  *m = 1;
355  ++m_count[k];
356  }
357  else
358  *m = 0;
359  }
360 
361  m_initialized.Store( 1 );
362  }
363  }
364  }
365 
366 private:
367 
368  /*
369  * Structure size.
370  */
371  int m_size;
372 
373  /*
374  * Element existence masks (one mask per way).
375  * An element exists iff its corresponding mask element is nonzero.
376  */
377  mutable existence_mask_set m_mask;
378 
379  /*
380  * Number of existing elements for each way.
381  */
382  mutable existence_mask_count m_count;
383 
384  /*
385  * Flag true when the structure has been reflected.
386  */
387  bool m_reflected = false;
388 
389  /*
390  * Flag true when existence masks have been calculated.
391  */
392  mutable AtomicInt m_initialized;
393 
394  /*
395  * Thread synchronization.
396  */
397  mutable Mutex m_mutex;
398 };
399 
400 // ----------------------------------------------------------------------------
401 
421 class PCL_CLASS BoxStructure : public StructuringElement
422 {
423 public:
424 
428  BoxStructure( int size )
429  : StructuringElement( size, 1 )
430  {
431  }
432 
436  BoxStructure( const BoxStructure& ) = default;
437 
440  StructuringElement* Clone() const override
441  {
442  return new BoxStructure( *this );
443  }
444 
452  bool IsBox( int k ) const override
453  {
454  PCL_PRECONDITION( k == 0 )
455  return true;
456  }
457 };
458 
459 // ----------------------------------------------------------------------------
460 
485 class PCL_CLASS CircularStructure : public StructuringElement
486 {
487 public:
488 
492  CircularStructure( int diameter )
493  : StructuringElement( diameter, 1 )
494  {
495  }
496 
501 
504  StructuringElement* Clone() const override
505  {
506  return new CircularStructure( *this );
507  }
508 
516  bool IsBox( int k ) const override
517  {
518  PCL_PRECONDITION( k == 0 )
519  return false;
520  }
521 
524  bool ElementExists( int i, int j, int k ) const override
525  {
526  PCL_PRECONDITION( i >= 0 && i < Size() )
527  PCL_PRECONDITION( j >= 0 && j < Size() )
528  PCL_PRECONDITION( k == 0 )
529  float n2 = 0.5F*Size();
530  float di = i+0.5F - n2;
531  float dj = j+0.5F - n2;
532  return di*di + dj*dj <= n2*n2;
533  }
534 };
535 
536 // ----------------------------------------------------------------------------
537 
557 class PCL_CLASS OrthogonalStructure : public StructuringElement
558 {
559 public:
560 
565  : StructuringElement( size, 1 )
566  {
567  }
568 
573 
576  StructuringElement* Clone() const override
577  {
578  return new OrthogonalStructure( *this );
579  }
580 
588  bool IsBox( int k ) const override
589  {
590  PCL_PRECONDITION( k == 0 )
591  return false;
592  }
593 
596  bool ElementExists( int i, int j, int k ) const override
597  {
598  PCL_PRECONDITION( i >= 0 && i < Size() )
599  PCL_PRECONDITION( j >= 0 && j < Size() )
600  PCL_PRECONDITION( k == 0 )
601  int n2 = Size() >> 1;
602  return i == n2 || j == n2;
603  }
604 };
605 
606 // ----------------------------------------------------------------------------
607 
627 class PCL_CLASS DiagonalStructure : public StructuringElement
628 {
629 public:
630 
634  DiagonalStructure( int size )
635  : StructuringElement( size, 1 )
636  {
637  }
638 
643 
646  StructuringElement* Clone() const override
647  {
648  return new DiagonalStructure( *this );
649  }
650 
658  bool IsBox( int k ) const override
659  {
660  PCL_PRECONDITION( k == 0 )
661  return false;
662  }
663 
666  bool ElementExists( int i, int j, int k ) const override
667  {
668  PCL_PRECONDITION( i >= 0 && i < Size() )
669  PCL_PRECONDITION( j >= 0 && j < Size() )
670  PCL_PRECONDITION( k == 0 )
671  return j == i || j == Size()-i-1;
672  }
673 };
674 
675 // ----------------------------------------------------------------------------
676 
699 class PCL_CLASS StarStructure : public StructuringElement
700 {
701 public:
702 
706  StarStructure( int size )
707  : StructuringElement( size, 1 )
708  {
709  }
710 
714  StarStructure( const StarStructure& ) = default;
715 
718  StructuringElement* Clone() const override
719  {
720  return new StarStructure( *this );
721  }
722 
730  bool IsBox( int k ) const override
731  {
732  PCL_PRECONDITION( k == 0 )
733  return false;
734  }
735 
738  bool ElementExists( int i, int j, int k ) const override
739  {
740  PCL_PRECONDITION( i >= 0 && i < Size() )
741  PCL_PRECONDITION( j >= 0 && j < Size() )
742  PCL_PRECONDITION( k == 0 )
743  int n2 = Size() >> 1;
744  if ( i == n2 || j == n2 )
745  return true;
746  if ( j == i || j == Size()-i-1 )
747  {
748  float n2 = 0.5F*Size();
749  float di = i+0.5F - n2;
750  float dj = j+0.5F - n2;
751  return di*di + dj*dj <= n2*n2;
752  }
753  return false;
754  }
755 };
756 
757 // ----------------------------------------------------------------------------
758 
785 class PCL_CLASS ThreeWayStructure : public StructuringElement
786 {
787 public:
788 
792  ThreeWayStructure( int size )
793  : StructuringElement( size, 3 )
794  {
795  }
796 
801 
804  StructuringElement* Clone() const override
805  {
806  return new ThreeWayStructure( *this );
807  }
808 
816  bool IsBox( int k ) const override
817  {
818  PCL_PRECONDITION( k >= 0 && k < 3 )
819  return false;
820  }
821 
824  bool ElementExists( int i, int j, int k ) const override
825  {
826  PCL_PRECONDITION( i >= 0 && i < Size() )
827  PCL_PRECONDITION( j >= 0 && j < Size() )
828  PCL_PRECONDITION( k >= 0 && k < 3 )
829  int n2 = Size() >> 1;
830  switch ( k )
831  {
832  default:
833  case 0: // central element
834  return i == n2 && j == n2;
835  case 1: // horizontal and vertical elements
836  return i == n2 || j == n2;
837  case 2: // diagonal elements
838  return (j == i || j == Size()-i-1) && i != n2;
839  }
840  }
841 };
842 
843 // ----------------------------------------------------------------------------
844 
880 class PCL_CLASS BitmapStructure : public StructuringElement
881 {
882 public:
883 
888  using bitmap = IsoString;
889 
895 
913  BitmapStructure( const char** bitmaps, int size, int n = 1 )
914  : StructuringElement( size, n )
915  {
916  PCL_PRECONDITION( bitmaps != nullptr )
917  PCL_PRECONDITION( *bitmaps != '\0' )
918  for ( int i = 0; i < NumberOfWays(); ++i )
919  m_bitmaps.Add( bitmap( bitmaps[i] ) );
920  }
921 
925  BitmapStructure( const BitmapStructure& ) = default;
926 
929  StructuringElement* Clone() const override
930  {
931  return new BitmapStructure( *this );
932  }
933 
936  bool ElementExists( int i, int j, int k ) const override
937  {
938  PCL_PRECONDITION( i >= 0 && i < Size() )
939  PCL_PRECONDITION( j >= 0 && j < Size() )
940  PCL_PRECONDITION( k >= 0 && k < NumberOfWays() )
941  return m_bitmaps[k][i + j*Size()] == 'x';
942  }
943 
944 protected:
945 
946  bitmap_set m_bitmaps;
947 };
948 
949 // ----------------------------------------------------------------------------
950 
951 } // pcl
952 
953 #endif // __PCL_StructuringElement_h
954 
955 // ----------------------------------------------------------------------------
956 // EOF pcl/StructuringElement.h - Released 2024-06-18T15:48:54Z
Atomic operations on integers.
Definition: Atomic.h:95
Automatic mutex lock/unlock.
Definition: AutoLock.h:84
A structuring element where static strings are used to define custom existence matrices.
BitmapStructure(const char **bitmaps, int size, int n=1)
bool ElementExists(int i, int j, int k) const override
StructuringElement * Clone() const override
BitmapStructure(const BitmapStructure &)=default
Standard box (square) structure.
StructuringElement * Clone() const override
bool IsBox(int k) const override
BoxStructure(const BoxStructure &)=default
Standard circular structure.
bool IsBox(int k) const override
bool ElementExists(int i, int j, int k) const override
StructuringElement * Clone() const override
CircularStructure(const CircularStructure &)=default
Standard diagonal structure.
bool IsBox(int k) const override
DiagonalStructure(const DiagonalStructure &)=default
StructuringElement * Clone() const override
bool ElementExists(int i, int j, int k) const override
Generic vector of arbitrary length.
Definition: Vector.h:107
const T * const_iterator
Definition: Vector.h:128
Eight-bit string (ISO/IEC-8859-1 or UTF-8 string)
Definition: String.h:5425
Adaptive mutual exclusion lock variable.
Definition: Mutex.h:209
Standard orthogonal structure.
StructuringElement * Clone() const override
bool ElementExists(int i, int j, int k) const override
bool IsBox(int k) const override
OrthogonalStructure(const OrthogonalStructure &)=default
Standard star structure.
StructuringElement * Clone() const override
bool IsBox(int k) const override
bool ElementExists(int i, int j, int k) const override
StarStructure(const StarStructure &)=default
Abstract base class of all PCL structuring elements.
StructuringElement(const StructuringElement &x)
virtual bool IsBox(int k) const
virtual bool ElementExists(int i, int j, int k) const
StructuringElement(int size=3, int n=1)
virtual StructuringElement * Clone() const =0
void PeekElements(T *h1, int &nh1, const T *h, int k) const
Standard three-way structure.
StructuringElement * Clone() const override
ThreeWayStructure(const ThreeWayStructure &)=default
bool IsBox(int k) const override
bool ElementExists(int i, int j, int k) const override
unsigned int uint32
Definition: Defs.h:666
constexpr const T & Max(const T &a, const T &b) noexcept
Definition: Utility.h:119
PCL root namespace.
Definition: AbstractImage.h:77