957 lines
28 KiB
C++
957 lines
28 KiB
C++
// ____ ______ __
|
|
// / __ \ / ____// /
|
|
// / /_/ // / / /
|
|
// / ____// /___ / /___ PixInsight Class Library
|
|
// /_/ \____//_____/ PCL 2.4.23
|
|
// ----------------------------------------------------------------------------
|
|
// pcl/StructuringElement.h - Released 2022-03-12T18:59:29Z
|
|
// ----------------------------------------------------------------------------
|
|
// This file is part of the PixInsight Class Library (PCL).
|
|
// PCL is a multiplatform C++ framework for development of PixInsight modules.
|
|
//
|
|
// Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved.
|
|
//
|
|
// Redistribution and use in both source and binary forms, with or without
|
|
// modification, is permitted provided that the following conditions are met:
|
|
//
|
|
// 1. All redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// 2. All redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
|
|
// of their contributors, may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission. For written
|
|
// permission, please contact info@pixinsight.com.
|
|
//
|
|
// 4. All products derived from this software, in any form whatsoever, must
|
|
// reproduce the following acknowledgment in the end-user documentation
|
|
// and/or other materials provided with the product:
|
|
//
|
|
// "This product is based on software from the PixInsight project, developed
|
|
// by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
|
|
//
|
|
// Alternatively, if that is where third-party acknowledgments normally
|
|
// appear, this acknowledgment must be reproduced in the product itself.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
|
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
// EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
|
|
// INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
|
|
// DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#ifndef __PCL_StructuringElement_h
|
|
#define __PCL_StructuringElement_h
|
|
|
|
/// \file pcl/StructuringElement.h
|
|
|
|
#include <pcl/Defs.h>
|
|
#include <pcl/Diagnostics.h>
|
|
|
|
#include <pcl/Atomic.h>
|
|
#include <pcl/AutoLock.h>
|
|
#include <pcl/Math.h>
|
|
#include <pcl/Rotate.h> // Reverse()
|
|
#include <pcl/StringList.h> // BitmapStructure
|
|
#include <pcl/Utility.h>
|
|
#include <pcl/Vector.h>
|
|
|
|
#include <memory.h>
|
|
|
|
namespace pcl
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class StructuringElement
|
|
* \brief Abstract base class of all PCL structuring elements.
|
|
*
|
|
* %StructuringElement defines a square multiway structure that can be used,
|
|
* along with a MorphologicalOperator, to build a MorphologicalTransformation.
|
|
*
|
|
* A structure is a square matrix of Boolean elements. When an element is true
|
|
* we say that that element \e exists. Nonexistent (false) structure elements
|
|
* are ignored when a morphological operator is applied to an image.
|
|
*
|
|
* A <em>structuring element</em> works for morphological transformations in a
|
|
* similar way to a <em>kernel filter</em> for spatial convolutions: the
|
|
* structure is placed centered on a pixel of the image being processed, and
|
|
* only those neighbor pixels falling behind existing structure elements are
|
|
* taken into account to compute the result of a morphological operator. When
|
|
* this operation is repeated for each pixel in an image, it implements a
|
|
* <em>morphological transformation</em>.
|
|
*
|
|
* %StructuringElement holds a <em>multiway structure</em>. Each way is
|
|
* actually a separate structure, so a multiway structure actually groups a
|
|
* set of structures with the same dimensions. When a multiway structure is
|
|
* used to apply a morphological operator, the operator is first applied
|
|
* through each way in the structure, and the result is the same operator
|
|
* applied to the partial results.
|
|
*
|
|
* This class is thread-safe. This means that multiple execution threads can
|
|
* access the same %StructuringElement instance concurrently to perform
|
|
* morphological transformations.
|
|
*
|
|
* \sa MorphologicalOperator, MorphologicalTransformation
|
|
*/
|
|
class PCL_CLASS StructuringElement
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Represents an element of a structure existence mask.
|
|
*/
|
|
typedef uint32 existence_mask_element;
|
|
|
|
/*!
|
|
* Represents a structure existence mask.
|
|
*/
|
|
typedef GenericVector<existence_mask_element> existence_mask;
|
|
|
|
/*!
|
|
* Represents a set of structure existence masks.
|
|
*/
|
|
typedef GenericVector<existence_mask> existence_mask_set;
|
|
|
|
/*!
|
|
* A vector type used to store the number of existing structure elements.
|
|
*/
|
|
typedef GenericVector<int> existence_mask_count;
|
|
|
|
/*!
|
|
* Constructs a default \e box %StructuringElement object of the specified
|
|
* \a size in pixels and number of ways \a n.
|
|
*/
|
|
StructuringElement( int size = 3, int n = 1 )
|
|
: m_size( Max( 3, size|1 ) )
|
|
, m_mask( Max( 1, n ) )
|
|
, m_count( 0, Max( 1, n ) )
|
|
{
|
|
PCL_PRECONDITION( size >= 3 )
|
|
PCL_PRECONDITION( (size & 1) != 0 )
|
|
PCL_PRECONDITION( n >= 1 )
|
|
for ( int k = 0; k < NumberOfWays(); ++k )
|
|
m_mask[k] = existence_mask( existence_mask_element( 0 ), NumberOfElements() );
|
|
}
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
StructuringElement( const StructuringElement& x )
|
|
: m_size( x.m_size )
|
|
, m_mask( x.NumberOfWays() )
|
|
, m_count( 0, x.NumberOfWays() )
|
|
{
|
|
for ( int k = 0; k < NumberOfWays(); ++k )
|
|
m_mask[k] = existence_mask( existence_mask_element( 0 ), NumberOfElements() );
|
|
}
|
|
|
|
/*!
|
|
* Destroys a %StructuringElement object.
|
|
*/
|
|
virtual ~StructuringElement()
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* Returns a pointer to a dynamically allocated duplicate of this
|
|
* structuring element.
|
|
*/
|
|
virtual StructuringElement* Clone() const = 0;
|
|
|
|
/*!
|
|
* Copy assignment operator. Returns a reference to this object.
|
|
*/
|
|
StructuringElement& operator =( const StructuringElement& x )
|
|
{
|
|
if ( &x != this )
|
|
{
|
|
volatile AutoLock lock( m_mutex );
|
|
m_size = x.m_size;
|
|
m_mask = existence_mask_set( x.NumberOfWays() );
|
|
m_count = existence_mask_count( 0, x.NumberOfWays() );
|
|
m_reflected = false;
|
|
m_initialized = 0;
|
|
for ( int k = 0; k < NumberOfWays(); ++k )
|
|
m_mask[k] = existence_mask( existence_mask_element( 0 ), NumberOfElements() );
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/*!
|
|
* Returns the number of ways in this structure.
|
|
*/
|
|
int NumberOfWays() const
|
|
{
|
|
return int( m_mask.Length() );
|
|
}
|
|
|
|
/*!
|
|
* Returns the size of this structure in pixels.
|
|
*/
|
|
int Size() const
|
|
{
|
|
return m_size;
|
|
}
|
|
|
|
/*!
|
|
* Returns the total number of structure elements, or Size()*Size(). Note
|
|
* that this includes both existing and nonexistent structure elements.
|
|
*/
|
|
int NumberOfElements() const
|
|
{
|
|
return m_size*m_size;
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this is a <em>box structure</em>. All elements in a box
|
|
* structure are <em>existing elements</em>.
|
|
*
|
|
* The default implementation of this member function returns true if all
|
|
* elements in the k-th way are reported as existing elements by the
|
|
* ElementExists() member function.
|
|
*
|
|
* \note This is a performance-critical routine. When possible, derived
|
|
* classes should reimplement it in more efficient ways (for example, a
|
|
* circular structure is never a box structure).
|
|
*/
|
|
virtual bool IsBox( int k ) const
|
|
{
|
|
PCL_PRECONDITION( k >= 0 && k < NumberOfWays() )
|
|
Initialize();
|
|
return m_count[k] == NumberOfElements();
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff a given element exists in this structure.
|
|
*
|
|
* \param i column position (X-coordinate) of the requested structure
|
|
* element. Must be 0 <= i < n, where n is the structure size.
|
|
*
|
|
* \param j row position (Y-coordinate) of the requested structure
|
|
* element. Must be 0 <= j < n, where n is the structure size.
|
|
*
|
|
* \param k Way index. Must be 0 <= k < m, where m is the number of ways
|
|
* defined in this structure.
|
|
*/
|
|
virtual bool ElementExists( int i, int j, int k ) const
|
|
{
|
|
PCL_PRECONDITION( i >= 0 && i < m_size )
|
|
PCL_PRECONDITION( j >= 0 && j < m_size )
|
|
PCL_PRECONDITION( k >= 0 && k < NumberOfWays() )
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
* Gets the subset of pixel sample values that correspond to existing
|
|
* elements in a way of this structure.
|
|
*
|
|
* \param[out] h1 %Vector of samples from the input \a h array that
|
|
* correspond to existing structure elements.
|
|
*
|
|
* \param[out] nh1 The number of existing elements in the k-th way of
|
|
* this structure. This is also the number of samples
|
|
* stored in the \a h1 vector.
|
|
*
|
|
* \param h Input array of samples. Must be the starting address of a
|
|
* square matrix of \a n samples stored in row order, where \a n
|
|
* is the number of elements in this structure (equal to
|
|
* NumberOfElements()).
|
|
*
|
|
* \param k Way index. Must be 0 <= k < m, where m is the number of ways
|
|
* defined in this structure.
|
|
*
|
|
* \note This function is thread-safe.
|
|
*/
|
|
template <typename T>
|
|
void PeekElements( T* h1, int& nh1, const T* h, int k ) const
|
|
{
|
|
PCL_PRECONDITION( h1 != 0 )
|
|
PCL_PRECONDITION( h != 0 )
|
|
PCL_PRECONDITION( k >= 0 && k < NumberOfWays() )
|
|
Initialize();
|
|
nh1 = 0;
|
|
for ( existence_mask::const_iterator m = m_mask[k].Begin(), m1 = m_mask[k].End(); m < m1; ++m, ++h )
|
|
if ( *m )
|
|
{
|
|
*h1++ = *h;
|
|
++nh1;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Reflects this structure.
|
|
*
|
|
* Structure reflection is equivalent to a 180 degrees rotation of the
|
|
* underlying structure mask for each way. This member function is called
|
|
* internally by MorphologicalTransformation to apply dilation operators.
|
|
*/
|
|
void Reflect()
|
|
{
|
|
Initialize();
|
|
for ( existence_mask_set::iterator i = m_mask.Begin(); i != m_mask.End(); ++i )
|
|
pcl::Reverse( i->Begin(), i->End() );
|
|
m_reflected = !m_reflected;
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this structure has been reflected. Note that after an
|
|
* even number of successive reflections (which is a no-op) this member
|
|
* function will return false.
|
|
*/
|
|
bool IsReflected() const
|
|
{
|
|
return m_reflected;
|
|
}
|
|
|
|
/*!
|
|
* Initializes the internal <em>existence tables</em>.
|
|
*
|
|
* A structure is a square matrix of Boolean elements. When an element is
|
|
* true we say that that element \e exists. Nonexistent (false) structure
|
|
* elements are ignored when a morphological operator is applied to
|
|
* transform an image.
|
|
*
|
|
* StructuringElement (and derived classes) uses a set of precomputed
|
|
* <em>existence tables</em> that greatly improves performance of
|
|
* morphological transformations, especially for complex structures. Calling
|
|
* this member function forces the immediate calculation of existence
|
|
* tables, if they haven't already been calculated previously. If the
|
|
* existence tables already exist, this function does nothing.
|
|
*
|
|
* You normally should not need to call this member function directly, as
|
|
* existence tables are automatically calculated when required.
|
|
*
|
|
* \note This is a thread-safe routine. It can be safely called from
|
|
* multiple running threads.
|
|
*/
|
|
void Initialize() const
|
|
{
|
|
if ( !m_initialized )
|
|
{
|
|
volatile AutoLock lock( m_mutex );
|
|
if ( m_initialized.Load() == 0 )
|
|
{
|
|
int N = NumberOfWays();
|
|
for ( int k = 0; k < N; ++k )
|
|
{
|
|
m_count[k] = 0; // redundant, but doesn't hurt
|
|
existence_mask::iterator m = m_mask[k].Begin();
|
|
for ( int i = 0; i < m_size; ++i )
|
|
for ( int j = 0; j < m_size; ++j, ++m )
|
|
if ( ElementExists( i, j, k ) )
|
|
{
|
|
*m = 1;
|
|
++m_count[k];
|
|
}
|
|
else
|
|
*m = 0;
|
|
}
|
|
|
|
m_initialized.Store( 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
/*
|
|
* Structure size.
|
|
*/
|
|
int m_size;
|
|
|
|
/*
|
|
* Element existence masks (one mask per way).
|
|
* An element exists iff its corresponding mask element is nonzero.
|
|
*/
|
|
mutable existence_mask_set m_mask;
|
|
|
|
/*
|
|
* Number of existing elements for each way.
|
|
*/
|
|
mutable existence_mask_count m_count;
|
|
|
|
/*
|
|
* Flag true when the structure has been reflected.
|
|
*/
|
|
bool m_reflected = false;
|
|
|
|
/*
|
|
* Flag true when existence masks have been calculated.
|
|
*/
|
|
mutable AtomicInt m_initialized;
|
|
|
|
/*
|
|
* Thread synchronization.
|
|
*/
|
|
mutable Mutex m_mutex;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class BoxStructure
|
|
* \brief Standard box (square) structure.
|
|
*
|
|
* A <em>block structure</em> defines all of its elements. For example, a box
|
|
* structure of size 5 is:
|
|
*
|
|
* <pre>
|
|
* x x x x x
|
|
* x x x x x
|
|
* x x x x x
|
|
* x x x x x
|
|
* x x x x x
|
|
* </pre>
|
|
*
|
|
* where existing elements are marked as 'x'.
|
|
*
|
|
* \sa CircularStructure, OrthogonalStructure, DiagonalStructure, StarStructure
|
|
*/
|
|
class PCL_CLASS BoxStructure : public StructuringElement
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs a standard block structure of the specified \a size.
|
|
*/
|
|
BoxStructure( int size )
|
|
: StructuringElement( size, 1 )
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
BoxStructure( const BoxStructure& ) = default;
|
|
|
|
/*!
|
|
*/
|
|
StructuringElement* Clone() const override
|
|
{
|
|
return new BoxStructure( *this );
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this is a <em>box structure</em>. All elements in a box
|
|
* structure are <em>existing elements</em>.
|
|
*
|
|
* As reimplemented by %BoxStructure, this member function always
|
|
* returns true.
|
|
*/
|
|
bool IsBox( int k ) const override
|
|
{
|
|
PCL_PRECONDITION( k == 0 )
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class CircularStructure
|
|
* \brief Standard circular structure.
|
|
*
|
|
* The <em>standard circular structure</em> of size 7 is defined as follows:
|
|
*
|
|
* <pre>
|
|
* · · x x x · ·
|
|
* · x x x x x ·
|
|
* x x x x x x x
|
|
* x x x x x x x
|
|
* x x x x x x x
|
|
* · x x x x x ·
|
|
* · · x x x · ·
|
|
* </pre>
|
|
*
|
|
* where existing elements are marked as 'x' and nonexisting elements are
|
|
* denoted as '·'.
|
|
*
|
|
* Circular structures can help in preserving small structures, especially
|
|
* rounded ones, like stars.
|
|
*
|
|
* \sa ThreeWayStructure, OrthogonalStructure, DiagonalStructure, StarStructure
|
|
*/
|
|
class PCL_CLASS CircularStructure : public StructuringElement
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs a standard circular structure of the specified \a diameter.
|
|
*/
|
|
CircularStructure( int diameter )
|
|
: StructuringElement( diameter, 1 )
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
CircularStructure( const CircularStructure& ) = default;
|
|
|
|
/*!
|
|
*/
|
|
StructuringElement* Clone() const override
|
|
{
|
|
return new CircularStructure( *this );
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this is a <em>box structure</em>. All elements in a box
|
|
* structure are <em>existing elements</em>.
|
|
*
|
|
* As reimplemented by %CircularStructure, this member function always
|
|
* returns false.
|
|
*/
|
|
bool IsBox( int k ) const override
|
|
{
|
|
PCL_PRECONDITION( k == 0 )
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool ElementExists( int i, int j, int k ) const override
|
|
{
|
|
PCL_PRECONDITION( i >= 0 && i < Size() )
|
|
PCL_PRECONDITION( j >= 0 && j < Size() )
|
|
PCL_PRECONDITION( k == 0 )
|
|
float n2 = 0.5F*Size();
|
|
float di = i+0.5F - n2;
|
|
float dj = j+0.5F - n2;
|
|
return di*di + dj*dj <= n2*n2;
|
|
}
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class OrthogonalStructure
|
|
* \brief Standard orthogonal structure.
|
|
*
|
|
* An <em>orthogonal structure</em> of size 5 is defined as follows:
|
|
*
|
|
* <pre>
|
|
* · · x · ·
|
|
* · · x · ·
|
|
* x x x x x
|
|
* · · x · ·
|
|
* · · x · ·
|
|
* </pre>
|
|
*
|
|
* where existing elements are marked as 'x' and nonexisting elements are
|
|
* denoted as '·'.
|
|
*
|
|
* \sa ThreeWayStructure, CircularStructure, DiagonalStructure, StarStructure
|
|
*/
|
|
class PCL_CLASS OrthogonalStructure : public StructuringElement
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs an orthogonal structure of the specified \a size.
|
|
*/
|
|
OrthogonalStructure( int size )
|
|
: StructuringElement( size, 1 )
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
OrthogonalStructure( const OrthogonalStructure& ) = default;
|
|
|
|
/*!
|
|
*/
|
|
StructuringElement* Clone() const override
|
|
{
|
|
return new OrthogonalStructure( *this );
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this is a <em>box structure</em>. All elements in a box
|
|
* structure are <em>existing elements</em>.
|
|
*
|
|
* As reimplemented by %OrthogonalStructure, this member function always
|
|
* returns false.
|
|
*/
|
|
bool IsBox( int k ) const override
|
|
{
|
|
PCL_PRECONDITION( k == 0 )
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool ElementExists( int i, int j, int k ) const override
|
|
{
|
|
PCL_PRECONDITION( i >= 0 && i < Size() )
|
|
PCL_PRECONDITION( j >= 0 && j < Size() )
|
|
PCL_PRECONDITION( k == 0 )
|
|
int n2 = Size() >> 1;
|
|
return i == n2 || j == n2;
|
|
}
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class DiagonalStructure
|
|
* \brief Standard diagonal structure.
|
|
*
|
|
* A <em>diagonal structure</em> of size 5 is defined as follows:
|
|
*
|
|
* <pre>
|
|
* x · · · x
|
|
* · x · x ·
|
|
* · · x · ·
|
|
* · x · x ·
|
|
* x · · · x
|
|
* </pre>
|
|
*
|
|
* where existing elements are marked as 'x' and nonexisting elements are
|
|
* denoted as '·'.
|
|
*
|
|
* \sa ThreeWayStructure, CircularStructure, OrthogonalStructure, StarStructure
|
|
*/
|
|
class PCL_CLASS DiagonalStructure : public StructuringElement
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs a diagonal structure of the specified \a size.
|
|
*/
|
|
DiagonalStructure( int size )
|
|
: StructuringElement( size, 1 )
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
DiagonalStructure( const DiagonalStructure& ) = default;
|
|
|
|
/*!
|
|
*/
|
|
StructuringElement* Clone() const override
|
|
{
|
|
return new DiagonalStructure( *this );
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this is a <em>box structure</em>. All elements in a box
|
|
* structure are <em>existing elements</em>.
|
|
*
|
|
* As reimplemented by %DiagonalStructure, this member function always
|
|
* returns false.
|
|
*/
|
|
bool IsBox( int k ) const override
|
|
{
|
|
PCL_PRECONDITION( k == 0 )
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool ElementExists( int i, int j, int k ) const override
|
|
{
|
|
PCL_PRECONDITION( i >= 0 && i < Size() )
|
|
PCL_PRECONDITION( j >= 0 && j < Size() )
|
|
PCL_PRECONDITION( k == 0 )
|
|
return j == i || j == Size()-i-1;
|
|
}
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class StarStructure
|
|
* \brief Standard star structure.
|
|
*
|
|
* A <em>star structure</em> of size 7 is defined as follows:
|
|
*
|
|
* <pre>
|
|
* · · · x · · ·
|
|
* · x · x · x ·
|
|
* · · x x x · ·
|
|
* x x x x x x x
|
|
* · · x x x · ·
|
|
* · x · x · x ·
|
|
* · · · x · · ·
|
|
* </pre>
|
|
*
|
|
* where existing elements are marked as 'x' and nonexisting elements are
|
|
* denoted as '·'.
|
|
*
|
|
* \sa ThreeWayStructure, CircularStructure, OrthogonalStructure,
|
|
* DiagonalStructure
|
|
*/
|
|
class PCL_CLASS StarStructure : public StructuringElement
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs a star structure of the specified \a size.
|
|
*/
|
|
StarStructure( int size )
|
|
: StructuringElement( size, 1 )
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
StarStructure( const StarStructure& ) = default;
|
|
|
|
/*!
|
|
*/
|
|
StructuringElement* Clone() const override
|
|
{
|
|
return new StarStructure( *this );
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this is a <em>box structure</em>. All elements in a box
|
|
* structure are <em>existing elements</em>.
|
|
*
|
|
* As reimplemented by %StarStructure, this member function always
|
|
* returns false.
|
|
*/
|
|
bool IsBox( int k ) const override
|
|
{
|
|
PCL_PRECONDITION( k == 0 )
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool ElementExists( int i, int j, int k ) const override
|
|
{
|
|
PCL_PRECONDITION( i >= 0 && i < Size() )
|
|
PCL_PRECONDITION( j >= 0 && j < Size() )
|
|
PCL_PRECONDITION( k == 0 )
|
|
int n2 = Size() >> 1;
|
|
if ( i == n2 || j == n2 )
|
|
return true;
|
|
if ( j == i || j == Size()-i-1 )
|
|
{
|
|
float n2 = 0.5F*Size();
|
|
float di = i+0.5F - n2;
|
|
float dj = j+0.5F - n2;
|
|
return di*di + dj*dj <= n2*n2;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class ThreeWayStructure
|
|
* \brief Standard three-way structure.
|
|
*
|
|
* The <em>standard three-way structure</em> of size 5 is defined as follows:
|
|
*
|
|
* <pre>
|
|
* Way #0 Way #1 Way #2
|
|
*
|
|
* · · x · · x · · · x · · · · ·
|
|
* · · x · · · x · x · · · · · ·
|
|
* x x · x x · · · · · · · x · ·
|
|
* · · x · · · x · x · · · · · ·
|
|
* · · x · · x · · · x · · · · ·
|
|
* </pre>
|
|
*
|
|
* where existing elements are marked as 'x' and nonexisting elements are
|
|
* denoted as '·'.
|
|
*
|
|
* The standard three-way structure leads to ranking operations where data
|
|
* from different spatial directions are ranked separately. When used to apply
|
|
* morphological operators, standard three-way structures can preserve edges
|
|
* better than box structures, especially when applied recursively.
|
|
*
|
|
* \sa CircularStructure, OrthogonalStructure, DiagonalStructure, StarStructure
|
|
*/
|
|
class PCL_CLASS ThreeWayStructure : public StructuringElement
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs a standard three-way structure of the specified \a size.
|
|
*/
|
|
ThreeWayStructure( int size )
|
|
: StructuringElement( size, 3 )
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
ThreeWayStructure( const ThreeWayStructure& ) = default;
|
|
|
|
/*!
|
|
*/
|
|
StructuringElement* Clone() const override
|
|
{
|
|
return new ThreeWayStructure( *this );
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this is a <em>box structure</em>. All elements in a box
|
|
* structure are <em>existing elements</em>.
|
|
*
|
|
* As reimplemented by %ThreeWayStructure, this member function always
|
|
* returns false.
|
|
*/
|
|
bool IsBox( int k ) const override
|
|
{
|
|
PCL_PRECONDITION( k >= 0 && k < 3 )
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool ElementExists( int i, int j, int k ) const override
|
|
{
|
|
PCL_PRECONDITION( i >= 0 && i < Size() )
|
|
PCL_PRECONDITION( j >= 0 && j < Size() )
|
|
PCL_PRECONDITION( k >= 0 && k < 3 )
|
|
int n2 = Size() >> 1;
|
|
switch ( k )
|
|
{
|
|
default:
|
|
case 0: // central element
|
|
return i == n2 && j == n2;
|
|
case 1: // horizontal and vertical elements
|
|
return i == n2 || j == n2;
|
|
case 2: // diagonal elements
|
|
return (j == i || j == Size()-i-1) && i != n2;
|
|
}
|
|
}
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class BitmapStructure
|
|
* \brief A structuring element where static strings are used to define custom
|
|
* existence matrices.
|
|
*
|
|
* %BitmapStructure allows you to build a structuring element using character
|
|
* strings to define the existence of structure elements. Each string defines a
|
|
* structure way, where 'x' characters correspond to existing structure
|
|
* elements. For example, the following array of static strings:
|
|
*
|
|
* <pre>
|
|
* const char* B[] = { "--x--"
|
|
* "-xxx-"
|
|
* "xxxxx"
|
|
* "-xxx-"
|
|
* "--x--",
|
|
* //
|
|
* "-xxx-"
|
|
* "xxxxx"
|
|
* "xxxxx"
|
|
* "xxxxx"
|
|
* "-xxx-" };
|
|
* </pre>
|
|
*
|
|
* would define a 5x5 structure with two ways. 'x' characters define existing
|
|
* elements; other character values ('-' in this case) are interpreted as
|
|
* nonexistent elements. The corresponding %BitmapStructure object would be
|
|
* constructed as follows:
|
|
*
|
|
* <tt>BitmapStructure S( B, 5, 2 );</tt>
|
|
*
|
|
* This class is a convenient, straightforward approach to defining multi-way
|
|
* custom structuring elements that can be used directly with the
|
|
* MorphologicalTransformation class.
|
|
*/
|
|
class PCL_CLASS BitmapStructure : public StructuringElement
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Represents a structure bitmap. Each bitmap defines the existence matrix
|
|
* for a \e way of the structuring element.
|
|
*/
|
|
typedef IsoString bitmap;
|
|
|
|
/*!
|
|
* Represents a set of bitmaps used to define the structure ways in a
|
|
* %BitmapStructure object.
|
|
*/
|
|
typedef IsoStringList bitmap_set;
|
|
|
|
/*!
|
|
* Constructs a %BitmapStructure object of the specified \a size and \a n
|
|
* number of ways.
|
|
*
|
|
* \param bitmaps An array of null-terminated strings representing the
|
|
* set of ways in this structuring element. There must be
|
|
* \a n contiguous null-terminated strings of length
|
|
* \a size*size characters at the address specified by
|
|
* this argument. In these strings, 'x' characters
|
|
* correspond to existing structure elements; other
|
|
* character values will be interpreted as nonexistent
|
|
* structure elements.
|
|
*
|
|
* \param size Size of this structure. Must be an odd integer >= 3.
|
|
*
|
|
* \param n Number of ways in this structure. Must be >= 1.
|
|
*/
|
|
BitmapStructure( const char** bitmaps, int size, int n = 1 )
|
|
: StructuringElement( size, n )
|
|
{
|
|
PCL_PRECONDITION( bitmaps != nullptr )
|
|
PCL_PRECONDITION( *bitmaps != '\0' )
|
|
for ( int i = 0; i < NumberOfWays(); ++i )
|
|
m_bitmaps.Add( bitmap( bitmaps[i] ) );
|
|
}
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
BitmapStructure( const BitmapStructure& ) = default;
|
|
|
|
/*!
|
|
*/
|
|
StructuringElement* Clone() const override
|
|
{
|
|
return new BitmapStructure( *this );
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool ElementExists( int i, int j, int k ) const override
|
|
{
|
|
PCL_PRECONDITION( i >= 0 && i < Size() )
|
|
PCL_PRECONDITION( j >= 0 && j < Size() )
|
|
PCL_PRECONDITION( k >= 0 && k < NumberOfWays() )
|
|
return m_bitmaps[k][i + j*Size()] == 'x';
|
|
}
|
|
|
|
protected:
|
|
|
|
bitmap_set m_bitmaps;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
} // pcl
|
|
|
|
#endif // __PCL_StructuringElement_h
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// EOF pcl/StructuringElement.h - Released 2022-03-12T18:59:29Z
|