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 itkRegionBasedLevelSetFunction_h
19 #define itkRegionBasedLevelSetFunction_h
20 
21 #include "itkFiniteDifferenceFunction.h"
22 #include "itkRegularizedHeavisideStepFunction.h"
23 #include "vnl/vnl_matrix_fixed.h"
24 
25 namespace itk
26 {
27 /** \class RegionBasedLevelSetFunction
28  *
29  * \brief LevelSet function that computes a speed image based on regional integrals
30  *
31  * This class implements a level set function that computes the speed image by
32  * integrating values on the image domain.
33  *
34  * Based on the paper:
35  *
36  *        "An active contour model without edges"
37  *         T. Chan and L. Vese.
38  *         In Scale-Space Theories in Computer Vision, pages 141-151, 1999.
39  *
40  * \author Mosaliganti K., Smith B., Gelas A., Gouaillard A., Megason S.
41  *
42  *  This code was taken from the Insight Journal paper:
43  *
44  *      "Cell Tracking using Coupled Active Surfaces for Nuclei and Membranes"
45  *      http://www.insight-journal.org/browse/publication/642
46  *      https://hdl.handle.net/10380/3055
47  *
48  *  That is based on the papers:
49  *
50  *      "Level Set Segmentation: Active Contours without edge"
51  *      http://www.insight-journal.org/browse/publication/322
52  *      https://hdl.handle.net/1926/1532
53  *
54  *      and
55  *
56  *      "Level set segmentation using coupled active surfaces"
57  *      http://www.insight-journal.org/browse/publication/323
58  *      https://hdl.handle.net/1926/1533
59  *
60  * NOTE: The convention followed is
61  * inside of the level-set function is negative and outside is positive.
62  * \ingroup ITKReview
63  */
64 template< typename TInput,   // LevelSetImageType
65           typename TFeature, // FeatureImageType
66           typename TSharedData >
67 class ITK_TEMPLATE_EXPORT RegionBasedLevelSetFunction:public
68   FiniteDifferenceFunction< TInput >
69 {
70 public:
71   ITK_DISALLOW_COPY_AND_ASSIGN(RegionBasedLevelSetFunction);
72 
73   /** Standard class type aliases. */
74   using Self = RegionBasedLevelSetFunction;
75   using Superclass = FiniteDifferenceFunction< TInput >;
76   using Pointer = SmartPointer< Self >;
77   using ConstPointer = SmartPointer< const Self >;
78 
79   static constexpr unsigned int ImageDimension = Superclass::ImageDimension;
80 
81   // itkNewMacro() is not provided since this is an abstract class.
82 
83   /** Run-time type information (and related methods) */
84   itkTypeMacro(RegionBasedLevelSetFunction, FiniteDifferenceFunction);
85 
86   /** Extract some parameters from the superclass. */
87   using TimeStepType = double;
88   using ImageType = typename Superclass::ImageType;
89   using PixelType = typename Superclass::PixelType;
90   using ScalarValueType = PixelType;
91   using RadiusType = typename Superclass::RadiusType;
92   using NeighborhoodType = typename Superclass::NeighborhoodType;
93   using NeighborhoodScalesType = typename Superclass::NeighborhoodScalesType;
94   using FloatOffsetType = typename Superclass::FloatOffsetType;
95   using VectorType =
96       FixedArray< ScalarValueType, Self::ImageDimension >;
97 
98   /* This structure is derived from LevelSetFunction and stores intermediate
99   values for computing time step sizes */
100   struct GlobalDataStruct {
GlobalDataStructGlobalDataStruct101     GlobalDataStruct()
102     {
103       ScalarValueType null_value = NumericTraits< ScalarValueType >::ZeroValue();
104 
105       m_MaxCurvatureChange   = null_value;
106       m_MaxAdvectionChange   = null_value;
107       m_MaxGlobalChange      = null_value;
108     }
109 
~GlobalDataStructGlobalDataStruct110     ~GlobalDataStruct() {}
111 
112     vnl_matrix_fixed< ScalarValueType,
113                       Self::ImageDimension,
114                       Self::ImageDimension > m_dxy;
115 
116     ScalarValueType m_dx[Self::ImageDimension];
117 
118     ScalarValueType m_dx_forward[Self::ImageDimension];
119     ScalarValueType m_dx_backward[Self::ImageDimension];
120 
121     ScalarValueType m_GradMagSqr;
122     ScalarValueType m_GradMag;
123 
124     ScalarValueType m_MaxCurvatureChange;
125     ScalarValueType m_MaxAdvectionChange;
126     ScalarValueType m_MaxGlobalChange;
127   };
128 
129   using InputImageType = TInput;
130   using InputImageConstPointer = typename InputImageType::ConstPointer;
131   using InputImagePointer = typename InputImageType::Pointer;
132   using InputPixelType = typename InputImageType::PixelType;
133   using InputIndexType = typename InputImageType::IndexType;
134   using InputIndexValueType = typename InputImageType::IndexValueType;
135   using InputSizeType = typename InputImageType::SizeType;
136   using InputSizeValueType = typename InputImageType::SizeValueType;
137   using InputRegionType = typename InputImageType::RegionType;
138   using InputPointType = typename InputImageType::PointType;
139 
140   using FeatureImageType = TFeature;
141   using FeatureImageConstPointer = typename FeatureImageType::ConstPointer;
142   using FeaturePixelType = typename FeatureImageType::PixelType;
143   using FeatureIndexType = typename FeatureImageType::IndexType;
144   using FeatureSpacingType = typename FeatureImageType::SpacingType;
145   using FeatureOffsetType = typename FeatureImageType::OffsetType;
146 
147   using SharedDataType = TSharedData;
148   using SharedDataPointer = typename SharedDataType::Pointer;
149 
150   using HeavisideFunctionType = HeavisideStepFunctionBase< InputPixelType, InputPixelType >;
151   using HeavisideFunctionConstPointer = typename HeavisideFunctionType::ConstPointer;
152 
SetDomainFunction(const HeavisideFunctionType * f)153   void SetDomainFunction(const HeavisideFunctionType *f)
154   {
155     this->m_DomainFunction = f;
156   }
157 
Initialize(const RadiusType & r)158   virtual void Initialize(const RadiusType & r)
159   {
160     this->SetRadius(r);
161 
162     // Dummy neighborhood.
163     NeighborhoodType it;
164     it.SetRadius(r);
165 
166     // Find the center index of the neighborhood.
167     m_Center =  it.Size() / 2;
168 
169     // Get the stride length for each axis.
170     for ( unsigned int i = 0; i < ImageDimension; i++ )
171       {
172       m_xStride[i] = it.GetStride(i);
173       }
174   }
175 
176 #if !defined( ITK_WRAPPING_PARSER )
SetSharedData(SharedDataPointer sharedDataIn)177   void SetSharedData(SharedDataPointer sharedDataIn)
178   {
179     this->m_SharedData = sharedDataIn;
180   }
181 #endif
182 
183   void UpdateSharedData(bool forceUpdate);
184 
GetGlobalDataPointer()185   void * GetGlobalDataPointer() const override
186   {
187     return new GlobalDataStruct;
188   }
189 
190   TimeStepType ComputeGlobalTimeStep(void *GlobalData) const override;
191 
192   /** Compute the equation value. */
193   PixelType ComputeUpdate( const NeighborhoodType & neighborhood,
194                                    void *globalData, const FloatOffsetType & = FloatOffsetType(0.0) ) override;
195 
SetInitialImage(InputImageType * f)196   void SetInitialImage(InputImageType *f)
197   {
198     m_InitialImage = f;
199   }
200 
GetFeatureImage()201   virtual const FeatureImageType * GetFeatureImage() const
202   { return m_FeatureImage.GetPointer(); }
SetFeatureImage(const FeatureImageType * f)203   virtual void SetFeatureImage(const FeatureImageType *f)
204   {
205     m_FeatureImage = f;
206 
207     FeatureSpacingType spacing = m_FeatureImage->GetSpacing();
208     for ( unsigned int i = 0; i < ImageDimension; i++ )
209       {
210       this->m_InvSpacing[i] = 1 / spacing[i];
211       }
212   }
213 
214   /** Advection field.  Default implementation returns a vector of zeros. */
215   virtual VectorType AdvectionField(const NeighborhoodType &,
216                                     const FloatOffsetType &, GlobalDataStruct * = 0)  const
217   { return this->m_ZeroVectorConstant; }
218 
219   /** Nu. Area regularization values */
SetAreaWeight(const ScalarValueType & nu)220   void SetAreaWeight(const ScalarValueType & nu)
221   { this->m_AreaWeight = nu; }
GetAreaWeight()222   ScalarValueType GetAreaWeight() const
223   { return this->m_AreaWeight; }
224 
225   /** Lambda1. Internal intensity difference weight */
SetLambda1(const ScalarValueType & lambda1)226   void SetLambda1(const ScalarValueType & lambda1)
227   { this->m_Lambda1 = lambda1; }
GetLambda1()228   ScalarValueType GetLambda1() const
229   { return this->m_Lambda1; }
230 
231   /** Lambda2. External intensity difference weight */
SetLambda2(const ScalarValueType & lambda2)232   void SetLambda2(const ScalarValueType & lambda2)
233   { this->m_Lambda2 = lambda2; }
GetLambda2()234   ScalarValueType GetLambda2() const
235   { return this->m_Lambda2; }
236 
237   /** Gamma. Overlap penalty */
SetOverlapPenaltyWeight(const ScalarValueType & gamma)238   void SetOverlapPenaltyWeight(const ScalarValueType & gamma)
239   { this->m_OverlapPenaltyWeight = gamma; }
GetOverlapPenaltyWeight()240   ScalarValueType GetOverlapPenaltyWeight() const
241   { return this->m_OverlapPenaltyWeight; }
242 
243   /** Gamma. Scales all curvature weight values */
SetCurvatureWeight(const ScalarValueType c)244   virtual void SetCurvatureWeight(const ScalarValueType c)
245   { m_CurvatureWeight = c; }
GetCurvatureWeight()246   ScalarValueType GetCurvatureWeight() const
247   { return m_CurvatureWeight; }
248 
SetAdvectionWeight(const ScalarValueType & iA)249   void SetAdvectionWeight(const ScalarValueType & iA)
250   { this->m_AdvectionWeight = iA; }
GetAdvectionWeight()251   ScalarValueType GetAdvectionWeight() const
252   { return this->m_AdvectionWeight; }
253 
254   /** Weight of the laplacian smoothing term */
SetReinitializationSmoothingWeight(const ScalarValueType c)255   void SetReinitializationSmoothingWeight(const ScalarValueType c)
256   { m_ReinitializationSmoothingWeight = c; }
GetReinitializationSmoothingWeight()257   ScalarValueType GetReinitializationSmoothingWeight() const
258   { return m_ReinitializationSmoothingWeight; }
259 
260   /** Volume matching weight.  */
SetVolumeMatchingWeight(const ScalarValueType & tau)261   void SetVolumeMatchingWeight(const ScalarValueType & tau)
262   { this->m_VolumeMatchingWeight = tau; }
GetVolumeMatchingWeight()263   ScalarValueType GetVolumeMatchingWeight() const
264   { return this->m_VolumeMatchingWeight; }
265 
266   /** Pixel Volume = Number of pixels inside the level-set  */
SetVolume(const ScalarValueType & volume)267   void SetVolume(const ScalarValueType & volume)
268   { this->m_Volume = volume; }
GetVolume()269   ScalarValueType GetVolume() const
270   { return this->m_Volume; }
271 
272   /** Set function id.  */
SetFunctionId(const unsigned int & iFid)273   void SetFunctionId(const unsigned int & iFid)
274   { this->m_FunctionId = iFid; }
275 
ReleaseGlobalDataPointer(void * GlobalData)276   void ReleaseGlobalDataPointer(void *GlobalData) const override
277   { delete (GlobalDataStruct *)GlobalData; }
278 
279   virtual ScalarValueType ComputeCurvature(const NeighborhoodType &,
280                                            const FloatOffsetType &, GlobalDataStruct *gd);
281 
282   /** \brief Laplacian smoothing speed can be used to spatially modify the
283     effects of laplacian smoothing of the level set function */
284   virtual ScalarValueType LaplacianSmoothingSpeed(
285     const NeighborhoodType &,
286     const FloatOffsetType &, GlobalDataStruct * = 0) const
287   { return NumericTraits< ScalarValueType >::OneValue(); }
288 
289   /** \brief Curvature speed can be used to spatially modify the effects of
290     curvature . The default implementation returns one. */
291   virtual ScalarValueType CurvatureSpeed(const NeighborhoodType &,
292                                          const FloatOffsetType &, GlobalDataStruct * = 0
293                                          ) const
294   { return NumericTraits< ScalarValueType >::OneValue(); }
295 
296   /** This method must be defined in a subclass to implement a working function
297    * object.  This method is called before the solver begins its work to
298    * produce the speed image used as the level set function's Advection field
299    * term.  See LevelSetFunction for more information. */
CalculateAdvectionImage()300   virtual void CalculateAdvectionImage() {}
301 
302 protected:
303 
304   RegionBasedLevelSetFunction();
~RegionBasedLevelSetFunction()305   ~RegionBasedLevelSetFunction() override {}
306 
307   /** The initial level set image */
308   InputImageConstPointer m_InitialImage;
309 
310   /** The feature image */
311   FeatureImageConstPointer m_FeatureImage;
312 
313   SharedDataPointer m_SharedData;
314 
315   HeavisideFunctionConstPointer m_DomainFunction;
316 
317   /** Area regularization weight */
318   ScalarValueType m_AreaWeight;
319 
320   /** Internal functional of the level set weight */
321   ScalarValueType m_Lambda1;
322 
323   /** External functional of the level set weight */
324   ScalarValueType m_Lambda2;
325 
326   /** Overlap Penalty Weight */
327   ScalarValueType m_OverlapPenaltyWeight;
328 
329   /** Volume Regularization Weight */
330   ScalarValueType m_VolumeMatchingWeight;
331 
332   /** Volume Constraint in pixels */
333   ScalarValueType m_Volume;
334 
335   /** Curvature Regularization Weight */
336   ScalarValueType m_CurvatureWeight;
337 
338   ScalarValueType m_AdvectionWeight;
339 
340   /** Laplacian Regularization Weight */
341   ScalarValueType m_ReinitializationSmoothingWeight;
342 
343   unsigned int m_FunctionId;
344 
345   std::slice x_slice[Self::ImageDimension];
346   OffsetValueType m_Center;
347   OffsetValueType m_xStride[Self::ImageDimension];
348   double m_InvSpacing[Self::ImageDimension];
349 
350   static double m_WaveDT;
351   static double m_DT;
352 
353   void ComputeHImage();
354 
355   /** \brief Compute the global term as a combination of the internal, external,
356     overlapping and volume regularization terms.  */
357   ScalarValueType ComputeGlobalTerm(
358     const ScalarValueType & imagePixel,
359     const InputIndexType & inputIndex);
360 
361   /** \brief Compute the internal term
362   \param[in] iValue Feature Image Value
363   \param[in] iIdx Feature Image Index
364   */
365   virtual ScalarValueType ComputeInternalTerm(const FeaturePixelType & iValue,
366                                               const FeatureIndexType & iIdx) = 0;
367 
368   /** \brief Compute the external term
369   \param[in] iValue Feature Image Value
370   \param[in] iIdx Feature Image Index */
371   virtual ScalarValueType ComputeExternalTerm(const FeaturePixelType & iValue,
372                                               const FeatureIndexType & iIdx) = 0;
373 
374   /** \brief Compute the overlap term
375   \param[in] featIndex
376   \param[out] pr = \f$ \prod_{i \neq j} H(\phi_i)\f$
377   \return OverlapTerm = \f$ \sum_{i \neq j} H(\phi_i)\f$ */
378   virtual ScalarValueType ComputeOverlapParameters(const FeatureIndexType & featIndex,
379                                                    ScalarValueType & pr) = 0;
380 
381   /** \brief Compute the overlap term
382       \return \f$ \int_{p \in \Omega} H(\phi_i) dp - this->Volume \f$
383       \note the volume regularization does not depend on the spacing.
384         So the volume must be set in number of pixels (not in real world unit). */
385   ScalarValueType ComputeVolumeRegularizationTerm();
386 
387   /** \brief Compute the laplacian term
388       \return \f$ \Delta \phi - \div(\frac{\nabla \phi}{|\nabla \phi|}) \f$
389       For details see
390 
391       \par REFERENCE
392       Li, C.M. and Xu, C.Y. and Gui, C. and Fox, M.D.
393       "Level Set Evolution without Re-Initialization: A New Variational Formulation",
394       CVPR05. 2005. pp. 430-436.
395   */
396 
397   /** \brief Compute the laplacian
398   \return \f$ \Delta \phi \f$ */
399   ScalarValueType ComputeLaplacian(GlobalDataStruct *gd);
400 
401   /** \brief Compute Hessian Matrix */
402   void ComputeHessian(const NeighborhoodType & it,
403                       GlobalDataStruct *globalData);
404 
405   /** \brief Compute Parameters for the inner and outer parts. */
406   virtual void ComputeParameters() = 0;
407 
408   /** \brief Update and save the inner and outer parameters in the shared data
409     structure. */
410   virtual void UpdateSharedDataParameters() = 0;
411 
412   bool m_UpdateC;
413 
414   /** This method's only purpose is to initialize the zero vector
415    * constant. */
416   static VectorType InitializeZeroVectorConstant();
417 
418   /** Zero vector constant. */
419   static VectorType m_ZeroVectorConstant;
420 };
421 } // end namespace itk
422 
423 #ifndef ITK_MANUAL_INSTANTIATION
424 #include "itkRegionBasedLevelSetFunction.hxx"
425 #endif
426 
427 #endif
428