1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkKLMSegmentationBorder_h
19 #define itkKLMSegmentationBorder_h
20 
21 #include "itkSegmentationBorder.h"
22 #include "itkKLMSegmentationRegion.h"
23 #include "itkMacro.h"
24 #include "ITKKLMRegionGrowingExport.h"
25 
26 #include "itkMath.h"
27 #include "vnl/vnl_vector.h"
28 #include "itkMath.h"
29 
30 namespace itk
31 {
32 /** \class KLMDynamicBorderArray
33  * \brief  Object maintaining a reference to a list of borders associated
34  * with a region.
35  *
36  * This is a tiny class similar to smart pointers that maintains a reference
37  * to a list of borders pointed by a region.
38  *
39  * \ingroup RegionGrowingSegmentation
40  * \ingroup ITKKLMRegionGrowing
41  */
42 
43 template< typename TBorder >
44 class KLMDynamicBorderArray
45 {
46 public:
47   /** Greater than operators defined to work with both static objects
48    * or pointer to objects.  In the degenerate
49    *  case of an image where all (or many) Lambda's are equal to some
50    *  constant value, this operator will ensure that the future
51    *  merged regions do not gain more borders than other regions,
52    *  thus avoiding pathologically slow behavior.
53    */
54   bool operator>(const KLMDynamicBorderArray< TBorder > & rhs) const
55   {
56     if ( Math::ExactlyEquals(m_Pointer->GetLambda(), rhs.m_Pointer->GetLambda()) )
57       {
58       if ( m_Pointer->GetLambda() < 0 )
59         {
60         return ( m_Pointer > rhs.m_Pointer );
61         }
62       else
63         {
64         // The purpose of this comparison is to not let any one region
65         // get more borders than another region.  In the degenerate
66         // case of an image where the Lambdas are always equal to some
67         // constant C, allowing a single region to be repeatedly
68         // merged so that it gains many borders will result in
69         // pathologically slow behavior.
70         double v1 = std::max(
71           static_cast< double >( m_Pointer->GetRegion1()->GetRegionBorderSize() ),
72           static_cast< double >( m_Pointer->GetRegion2()->GetRegionBorderSize() ) );
73 
74         double v2 = std::max(
75           static_cast< double >( rhs.m_Pointer->GetRegion1()->GetRegionBorderSize() ),
76           static_cast< double >( rhs.m_Pointer->GetRegion2()->GetRegionBorderSize() ) );
77 
78         return ( v1 > v2 );
79         }
80       }
81     return ( m_Pointer->GetLambda() > rhs.m_Pointer->GetLambda() );
82   }
83 
84   bool operator>(const KLMDynamicBorderArray< TBorder > *rhs) const
85   {
86     if ( m_Pointer->GetLambda() == rhs->m_Pointer->GetLambda() )
87       {
88       if ( m_Pointer->GetLambda() < 0 )
89         {
90         return ( m_Pointer > rhs->m_Pointer );
91         }
92       else
93         {
94         // The purpose of this comparison is to not let any one region
95         // get more borders than another region.  In the degenerate
96         // case of an image where the Lambdas are always equal to some
97         // constant C, allowing a single region to be repeatedly
98         // merged so that it gains many borders will result in
99         // pathologically slow behavior.
100         double v1 = std::max(
101           static_cast< double >( m_Pointer->GetRegion1()->GetRegionBorderSize() ),
102           static_cast< double >( m_Pointer->GetRegion2()->GetRegionBorderSize() ) );
103 
104         double v2 = std::max(
105           static_cast< double >( rhs->m_Pointer->GetRegion1()->GetRegionBorderSize() ),
106           static_cast< double >( rhs->m_Pointer->GetRegion2()->GetRegionBorderSize() ) );
107 
108         return ( v1 > v2 );
109         }
110       }
111     return ( m_Pointer->GetLambda() > rhs->m_Pointer->GetLambda() );
112   }
113 
114   TBorder *m_Pointer;
115 };
116 
117 /** \class KLMSegmentationBorder
118  * \brief Base class for KLMSegmentationBorder object
119  *
120  * itkKLMSegmentationBorder is the base class for the KLMSegmentationBorder
121  * objects. It provides the basic function definitons that are inherent to a
122  * KLMSegmentationBorder objects.
123  *
124  * This class implements the border object that is used in particular with
125  * the KLM algorithm (see also KLMRegionGrowImageFilter). The border is
126  * defined by the adjacency of two regions. The parameter Lambda ascertains
127  * the importance of the border in defining the regions. The higher the
128  * values of Lambda the more dominant is its presence in the a region. In
129  * case of removal of a border during the region growing process the one with
130  * least Lambda value is eliminated.
131  *
132  * \ingroup RegionGrowingSegmentation
133  * \ingroup ITKKLMRegionGrowing
134  */
135 
136 // Forward reference because of circular dependencies
137 class ITK_FORWARD_EXPORT KLMSegmentationRegion;
138 
139 class ITKKLMRegionGrowing_EXPORT KLMSegmentationBorder:public SegmentationBorder
140 {
141 public:
142   ITK_DISALLOW_COPY_AND_ASSIGN(KLMSegmentationBorder);
143 
144   /** Standard class type aliases. */
145   using Self = KLMSegmentationBorder;
146   using Superclass = SegmentationBorder;
147   using Pointer = SmartPointer< Self >;
148   using ConstPointer = SmartPointer< const Self >;
149 
150   /** Method for creation through the object factory. */
151   itkNewMacro(Self);
152 
153   /** Run-time type information (and related methods). */
154   itkTypeMacro(KLMSegmentationBorder, SegmentationBorder);
155 
156   /** Set the region 1 associated with the border */
157   void SetRegion1(KLMSegmentationRegion *Region1);
158 
159   /** Get the region 1 associated with the border. */
160   KLMSegmentationRegion * GetRegion1();
161 
162   /** Set the region 2 associated with the border. */
163   void SetRegion2(KLMSegmentationRegion *Region2);
164 
165   /** Get the region 2 associated with the border. */
166   KLMSegmentationRegion * GetRegion2();
167 
168   /** Set/Get the Lambda parameter associate with the borders
169    * in the KLM algorithm */
170   itkSetMacro(Lambda, double);
171   itkGetConstReferenceMacro(Lambda, double);
172 
173   /** Evaluate the Lambda for a given border. */
174   void EvaluateLambda();
175 
176   /** Print the data associated with each border. */
177   void PrintBorderInfo();
178 
179 protected:
180   /** Constructor. */
181   KLMSegmentationBorder();
182 
183   /** Destructor. */
184   ~KLMSegmentationBorder() override;
185 
186   /** Print self identity */
187   void PrintSelf(std::ostream & os, Indent indent) const override;
188 
189 private:
190   double                 m_Lambda;
191   KLMSegmentationRegion *m_Region1;
192   KLMSegmentationRegion *m_Region2;
193 };
194 } // end namespace itk
195 
196 #endif
197