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