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 itkKLMRegionGrowImageFilter_h
19 #define itkKLMRegionGrowImageFilter_h
20 
21 #include "itkImage.h"
22 #include "itkRegionGrowImageFilter.h"
23 #include "itkKLMSegmentationBorder.h"
24 #include "itkImageRegionIterator.h"
25 #include "itkConceptChecking.h"
26 #include <algorithm>
27 #include <functional>
28 
29 namespace itk
30 {
31 /** \class KLMRegionGrowImageFilter
32  * \brief Base class for a region growing object that performs energy-based
33  * region growing for multiband images.
34  *
35  * itkKLMRegionGrowImageFilter is the base class for the KLMRegionGrowImageFilter objects.
36  * This object performs energy-based region growing for multiband images.
37  * Since this is based on G. Koepfler,C. Lopez and J. M. Morel's work
38  * described below, the acronym KLM is added at the end of the object name.
39  *
40  * The ApplyRegionGrowImageFilter() function implements the segmentation algorithm
41  * that partitions the input image into non-overlapping regions
42  * by minimizing an energy functional which trades off the similarity
43  * of regions against the length of their shared boundary. The heart of the
44  * process relies on the MergeRegion() method that calls a private function
45  * to perform the merging of region based on the piecewise constant KLM
46  * algorithm for region merging. For extensibility purposes, the MergeRegion()
47  * function is made virtual. Extensions can be made possible using
48  * function overloading or overriding the virtual function in a derived
49  * class. It starts by breaking the image into many small regions and fitting
50  * the regions to a polynomial model.  The algorithm iteratively merges into
51  * one region the two adjoining regions which are most alike in terms
52  * of the specified polynomial model given the length of the border
53  * between the two regions.  Internally, the energy functional is
54  * evaluated using a Lagrangian parameter called lambda which is also
55  * called the scale parameter as it controls the coarseness of the
56  * segmentation where a small value of lambda corresponds to a finer
57  * segmentation with more regions and a large value corresponds to a
58  * coarse segmentation with fewer regions.  Since the algorithm grows
59  * regions by merging like regions, the internal value of lambda
60  * increases as the number of regions decreases.
61  *
62  * The user can stop the merging of regions using the
63  * SetMaximumNumberOfRegions() and SetMaximumLambda() functions.
64  * The SetMaximumNumberOfRegions() function is publicly
65  * inherited from its base class and internally sets the m_MaximumNumberOfRegions
66  * parameter. The SetMaximumLambda() function sets the m_MaximumLambda
67  * parameter. If the
68  * number of regions in the image is equal to m_MaximumNumberOfRegions or if the
69  * internal energy functional becomes greater than m_MaximumLambda, then the
70  * merging iterations will stop.  Note that a larger energy function
71  * value for m_MaximumLambda
72  * will result in fewer boundaries and fewer regions, while a smaller value
73  * for m_MaximumLambda will result in more boundaries and more regions. To have
74  * m_MaximumNumberOfRegions control exactly the number of output regions, m_MaximumLamda
75  * should be set to a very large number. To have m_MaximumLambda control exactly
76  * the number of output regions, m_MaximumNumberOfRegions should be set to 2. As a
77  * default value, m_MaximumLambda is set to 1000 and m_MaximumNumberOfRegions
78  * is set to 2.
79  *
80  * Currently implementation puts equal weight to the multichannel values.
81  * In future improvements we plan to allow the user to control the weights
82  * associated with each individual channels.
83  *
84  * It is templated over the type of input and output image. This object
85  * supports data handling of multiband images. The object accepts images
86  * in vector format, where each pixel is a vector and each element of the
87  * vector corresponds to an entry from 1 particular band of a multiband
88  * dataset. We expect the user to provide the input to the routine in vector
89  * format. A single band image is treated as a vector image with a single
90  * element for every vector.
91  *
92  * This algorithm implementation takes a multiband image stored in vector
93  * format as input and produces two outputs. Using the ImageToImageFilter,
94  * the piecewise constant approximation image is the output calculated
95  * using the process update mechanism. The second output, i.e., the
96  * image with the region labels (segmentation image) is returned at
97  * users request by calling GetLabelledImage() function. This function
98  * returns a reference to the labelled image determined using the KLM
99  * algorithm. The algorithm supports 2D and 3D data sets only. The input
100  * image dimensions must be exact multiples of the user specified gridsizes.
101  * Appropriate padding must be performed by the user if any image which
102  * are not multiples of the gridsizes are used.
103  *
104  * For more information about the algorithm, see G. Koepfler, C. Lopez
105  * and J. M. Morel, ``A Multiscale Algorithm for Image Segmentation by
106  * Variational Method,'' {\em SIAM Journal of Numerical Analysis},
107  * vol. 31, pp. 282-299, 1994.
108  *
109  * Algorithm details:
110  *
111  * This function segments a two-dimensional input image into
112  * non-overlapping atomic regions \f$ O_i, i=1,2,\ldots,N \f$, where
113  * \f$ N \f$ is the
114  * total number of region, by minimizing the following energy functional
115  * (also known as the simplified Mumford and Shah functional):
116  * \f$
117  * E(u,K)=\int_{\Omega-K}||u(r,c)-g(r,c)||^2{d{\Omega}}+\lambda\cdot{L(K)}
118  * \f$,
119  * where \f$ \Omega \f$ denotes the domain of an image, \f$ g(r,c) \f$
120  * is the input image, and \f$ u(r,c) \f$ is an approximation of
121  * \f$ g(r,c) \f$.  Furthermore, \f$ u(r,c) \f$ is defined to be
122  * piecewise constant in regions \f$ O_i \f$.  If
123  * \f$ \partial O_i \f$ represents the boundary of the region,
124  * \f$ K=\bigcup_{i=1}^N\partial{O_i} \f$ denotes the set of all region
125  * boundaries and \f$ L(K) \f$ is the total length of the boundaries.  The
126  * parameter \f$ \lambda \f$ controls the coarseness of the segmentation
127  * (i.e. a larger \f$ \lambda \f$ will result in fewer boundaries).
128  *
129  * Starting with small, piecewise-constant initial regions the algorithm
130  * iteratively merges the two adjacent regions \f$ O_i \f$ and
131  * \f$ O_j \f$ which  most
132  * decrease the energy functional.  In other words, the merging criterion
133  * is based on the difference between the current energy
134  * \f$ E(u,K) \f$ and the
135  * energy that would result after a merge,
136  * \f$ E(\hat{u},K-\partial(O_i,O_j)) \f$,
137  * where \f$ \hat{u} \f$ is the piecewise constant approximation of the
138  * input image \f$ g \f$, and \f$ \partial(O_i,O_j) \f$ is the common boundary
139  * between region \f$ O_i \f$ and \f$ O_j \f$.  It can be shown that
140  * \f$ E(u,K)-E(\hat{u},K-\partial(O_i,O_j))=
141  * \lambda\cdot{L(\partial(O_i,O_j))}-
142  * {\frac{(|O_i| \cdot |O_j|)}{(|O_i|+|O_j|)}} \|c_i-c_j\|^2 \f$.
143  *
144  * Once two regions are merged the following update equations are used
145  * to calculated the constant approximation of the new region:
146  *
147  * \f$ c_{i,j} = \frac{(c_i |O_i| + c_j |O_j|)}{(|O_i| + |O_j|)} \f$.
148  *
149  * Again, the merging of regions continues until the desired number of
150  * regions has been reached or until the desired coarseness (specified
151  * by the scale parameter \f$ \lambda \f$) has been reached.
152  *
153  * The two outputs are possible to derive from the object:
154  * (1) u, the piecewise constant approximation (mean of the regions)
155  *     to the input image set; This is currently generated by the
156  *     process object pipeline and the
157  * (2) the labelled regions in the input image set is generated by the
158  *     GetLabelledImage() function.
159  *
160  * \ingroup RegionGrowingSegmentation
161  * \ingroup ITKKLMRegionGrowing
162  */
163 
164 template< typename TInputImage, typename TOutputImage >
165 class ITK_TEMPLATE_EXPORT KLMRegionGrowImageFilter:public RegionGrowImageFilter< TInputImage, TOutputImage >
166 {
167 public:
168   ITK_DISALLOW_COPY_AND_ASSIGN(KLMRegionGrowImageFilter);
169 
170   /** Standard class type aliases. */
171   using Self = KLMRegionGrowImageFilter;
172   using Superclass = RegionGrowImageFilter< TInputImage, TOutputImage >;
173   using Pointer = SmartPointer< Self >;
174   using ConstPointer = SmartPointer< const Self >;
175 
176   /** Method for creation through the object factory. */
177   itkNewMacro(Self);
178 
179   /** Run-time type information (and related methods). */
180   itkTypeMacro(KLMRegionGrowImageFilter, RegionGrowImageFilter);
181 
182   /** Type definition for the input image. */
183   using InputImageType = TInputImage;
184   using InputImagePointer = typename TInputImage::Pointer;
185   using InputImageConstPointer = typename TInputImage::ConstPointer;
186 
187   /** Type definition for the input image pixel type. */
188   using InputImagePixelType = typename TInputImage::PixelType;
189 
190   /** Type definition for the input image pixel vector type. */
191   using InputImageVectorType = typename TInputImage::PixelType::VectorType;
192 
193   /** InputImageVectorDimension enumeration. */
194   static constexpr unsigned int InputImageVectorDimension = InputImagePixelType::Dimension;
195 
196   /** Type definition for the input image index type. */
197   using InputImageIndexType = typename TInputImage::IndexType;
198 
199   /** Type definition for the image iterators to be used. */
200   using InputImageIterator = ImageRegionIterator< TInputImage >;
201   using InputImageConstIterator = ImageRegionConstIterator< TInputImage >;
202 
203   /** Type definition for the image region type. */
204   using InputRegionType = typename TInputImage::RegionType;
205 
206   /** Type definition for the input grid size type used to create
207     * initial atomic regions. */
208   using GridSizeType = typename Superclass::GridSizeType;
209 
210   /** Type definition for the output image. */
211   using OutputImageType = TOutputImage;
212   using OutputImagePointer = typename TOutputImage::Pointer;
213 
214   /** InputImageDimension enumeration. */
215   static constexpr unsigned int InputImageDimension = TInputImage::ImageDimension;
216 
217   /** OutputImageDimension enumeration. */
218   static constexpr unsigned int OutputImageDimension = TOutputImage::ImageDimension;
219 
220   /** Type definition for the output image pixel type. */
221   using OutputImagePixelType = typename TOutputImage::PixelType;
222 
223   /** Type definition for the output image pixel vector type. */
224   using OutputImageVectorType = typename TOutputImage::PixelType::VectorType;
225 
226   /** OutputImageVectorDimension enumeration. */
227   static constexpr unsigned int OutputImageVectorDimension = OutputImagePixelType::Dimension;
228 
229   /** Type definition for the output image index type. */
230   using OutputImageIndexType = typename TOutputImage::IndexType;
231 
232   /** Type definition for the output image iterators.  */
233   using OutputImageIterator = ImageRegionIterator< TOutputImage >;
234 
235   /** type definition for the region label type. */
236   using RegionLabelType = typename KLMSegmentationRegion::RegionLabelType;
237 
238   /** The dimension of the labelled image. */
239   static constexpr RegionLabelType LabelImageDimension = InputImageDimension;
240 
241   /** Type definition for the labelled image pixel type. */
242   using LabelImageType = Image< RegionLabelType, Self::LabelImageDimension >;
243 
244   /** Type definition for the labelled image pointer.  */
245   using LabelImagePointer = typename LabelImageType::Pointer;
246 
247   /** Type definition for the labelled image pixel type. */
248   using LabelImagePixelType = typename LabelImageType::PixelType;
249 
250   /** Type definition for the labelled image index type. */
251   using LabelImageIndexType = typename LabelImageType::IndexType;
252 
253   /** Type definition for the labelled image iterators.  */
254   using LabelImageIterator = ImageRegionIterator< LabelImageType >;
255 
256   /** Storage type for the mean region intensity. */
257   using MeanRegionIntensityType = vnl_vector< double >;
258 
259   /** Type definition for the smart border type. */
260   using BorderType = KLMSegmentationBorder;
261 
262   /** Type definition for the smart border pointers object. */
263   using KLMSegmentationBorderArrayPtr = KLMDynamicBorderArray< BorderType >;
264 
265   /** Set/Get the desired threshold parameter for lambda. See
266    * itkSegmentationBorder documentation for details regarding this
267    * parameter.  */
268   itkSetMacro(MaximumLambda, double);
269   itkGetConstReferenceMacro(MaximumLambda, double);
270 
271   /** Set/Get the desired number of regions. */
272   itkSetMacro(NumberOfRegions, unsigned int);
273   itkGetConstReferenceMacro(NumberOfRegions, unsigned int);
274 
275   /** Generate labelled image. */
276   LabelImagePointer GetLabelledImage();
277 
278   /** Function that prints all the region information.  */
279   void PrintAlgorithmRegionStats();
280 
281   /** Function that prints all the border information.  */
282   void PrintAlgorithmBorderStats();
283 
284 #ifdef ITK_USE_CONCEPT_CHECKING
285   // Begin concept checking
286   itkConceptMacro( InputHasNumericTraitsCheck,
287                    ( Concept::HasNumericTraits< typename InputImagePixelType::ValueType > ) );
288   itkConceptMacro( SameDimension,
289                    ( Concept::SameDimension< Self::InputImageDimension,
290                                              Self::OutputImageDimension > ) );
291 #if defined(THIS_CONCEPT_FAILS_ON_GCC)
292   /** The input pixel type must be the same as that of the output image. */
293   itkConceptMacro( SameVectorDimension,
294                    ( Concept::SameDimension< Self::InputImageVectorDimension,
295                                              Self::OutputImageVectorDimension > ) );
296 #endif
297   // End concept checking
298 #endif
299 
300 protected:
301   KLMRegionGrowImageFilter();
302   ~KLMRegionGrowImageFilter() override = default;
303   void PrintSelf(std::ostream & os, Indent indent) const override;
304 
305   /**
306    * Standard pipeline method.
307    */
308   void GenerateData() override;
309 
310   /** KLMRegionGrowImageFilter needs the entire input. Therefore
311    * it must provide an implementation GenerateInputRequestedRegion().
312    * \sa ProcessObject::GenerateInputRequestedRegion(). */
313   void GenerateInputRequestedRegion() override;
314 
315   /** KLMRegionGrowImageFilter will produce all of the output.
316    * Therefore it must provide an implementation of
317    * EnlargeOutputRequestedRegion().
318    * \sa ProcessObject::EnlargeOutputRequestedRegion() */
319   void EnlargeOutputRequestedRegion(DataObject *) override;
320 
321   /** This is the interface function that calls the specific algorithm
322    * implementation of region growing. */
323   void ApplyRegionGrowImageFilter() override;
324 
325   /** Function to merge two regions.
326    * The smaller label is always assigned to the new region.  This is
327    * consistent with the connected components algorithm. */
328   void MergeRegions() override;
329 
330   /** Generate output approximated image. */
331   virtual void GenerateOutputImage();
332 
333   /** Function that calls the KLM region growing algorithm. */
334   void ApplyKLM();
335 
336   /** Initialize the RegionGrowImageFilter algorithm. */
337   void InitializeKLM();
338 
339   /** Generate the labelled image. */
340   LabelImagePointer GenerateLabelledImage(LabelImageType *labelImagePtr);
341 
342   /** Calculate the statistics representing the region. In this
343    * case we compute the mean region intensity and the area of the
344    * initial N-dimensional rectangular area. This is the function that
345    * can be overriden in order to enable a different statistical
346    * representation for region initialization. */
347   virtual void InitializeRegionParameters(InputRegionType region);
348 
349   /** Function to resolve the region labels to be consecutively ordered.
350    * Each initial atomic region is given a new label and the aggregrate
351    * region area and mean intensity. */
352   virtual void ResolveRegions();
353 
354 private:
355   using InputImageSizeType = typename TInputImage::SizeType;
356   using KLMSegmentationRegionPtr = typename KLMSegmentationRegion::Pointer;
357   using KLMSegmentationBorderPtr = typename KLMSegmentationBorder::Pointer;
358 
359   double       m_MaximumLambda{1000};
360   unsigned int m_NumberOfRegions{0};
361 
362   /** Local variables. */
363 
364   double       m_InternalLambda{0};
365   unsigned int m_InitialNumberOfRegions{0};
366   double       m_TotalBorderLength{0.0};
367 
368   std::vector< KLMSegmentationRegionPtr >      m_RegionsPointer;
369   std::vector< KLMSegmentationBorderPtr >      m_BordersPointer;
370   std::vector< KLMSegmentationBorderArrayPtr > m_BordersDynamicPointer;
371   KLMSegmentationBorderArrayPtr *              m_BorderCandidate{nullptr};
372 
373   MeanRegionIntensityType m_InitialRegionMean;
374   double                  m_InitialRegionArea{0};
375 }; // class KLMRegionGrowImageFilter
376 } // namespace itk
377 
378 #ifndef ITK_MANUAL_INSTANTIATION
379 #include "itkKLMRegionGrowImageFilter.hxx"
380 #endif
381 
382 #endif
383