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 itkNormalVectorDiffusionFunction_h 19 #define itkNormalVectorDiffusionFunction_h 20 21 #include "itkNormalVectorFunctionBase.h" 22 #include "itkNumericTraits.h" 23 #include <cmath> 24 25 namespace itk 26 { 27 /** 28 * \class NormalVectorDiffusionFunction 29 * 30 * \brief This class defines all the necessary functionality for performing 31 * isotropic and anisotropic diffusion operations on vector neighborhoods from 32 * a sparse image. 33 * 34 * \par 35 * This class implements the actual computations for performing isotropic and 36 * anisotropic diffusion operations on a neighborhood of unit length 37 * vectors. Moreover, this processing is intrinsic to a manifold as specified 38 * by the ManifoldNormal member variables in the nodes of the sparse image. 39 * 40 * \par 41 * Since the only difference between isotropic and anisotropic diffusion is the 42 * exectution of 1 extra line of code, we have implemented both in this class 43 * and made the choice between the two depend on a parameter (see below). 44 45 * \par PARAMETERS 46 * The choice between is isotropic/anisotropic diffusion is made by the 47 * parameter NormalProcessType. A value of 0 corresponds to isotropic diffusion 48 * whereas a value of 1 corresponds to anisotropic diffusion. If anisotropic 49 * diffusion is chosen, the parameter ConductanceParameter should be set. This 50 * conductance parameter determines the level of feature preservation. 51 * 52 * \par IMPORTANT 53 * This class works on SparseImage neighborhoods. Before using this class 54 * please read the documentation for SparseImage. Also the documentation for 55 * ImplicitManifoldNormalVectorField class will be helpful in understanding how 56 * to use this class as a function object. 57 * \ingroup ITKLevelSets 58 */ 59 template< typename TSparseImageType > 60 class ITK_TEMPLATE_EXPORT NormalVectorDiffusionFunction: 61 public NormalVectorFunctionBase< TSparseImageType > 62 { 63 public: 64 ITK_DISALLOW_COPY_AND_ASSIGN(NormalVectorDiffusionFunction); 65 66 /** Standard class type alias. */ 67 using Self = NormalVectorDiffusionFunction; 68 using Superclass = NormalVectorFunctionBase< TSparseImageType >; 69 using Pointer = SmartPointer< Self >; 70 using ConstPointer = SmartPointer< const Self >; 71 72 /** Run-time type information (and related methods) */ 73 itkTypeMacro(NormalVectorDiffusionFunction, NormalVectorFunctionBase); 74 75 /** Image dimension derived from the superclass. */ 76 static constexpr unsigned int ImageDimension = Superclass::ImageDimension; 77 78 /** Standard New macro. */ 79 itkNewMacro(Self); 80 81 /** Typedefs from the superclass. */ 82 using TimeStepType = typename Superclass::TimeStepType; 83 using RadiusType = typename Superclass::RadiusType; 84 using NeighborhoodType = typename Superclass::NeighborhoodType; 85 using NeighborhoodScalesType = typename Superclass::NeighborhoodScalesType; 86 using FloatOffsetType = typename Superclass::FloatOffsetType; 87 using IndexType = typename Superclass::IndexType; 88 using SparseImageType = typename Superclass::SparseImageType; 89 using NodeType = typename Superclass::NodeType; 90 using NodeValueType = typename Superclass::NodeValueType; 91 using NormalVectorType = typename Superclass::NormalVectorType; 92 93 /** This method is used to choose between isotropic/anisotropic filtering. A 94 parameter value of 0 indicates isotropic diffusion and is the 95 default. Parameter value 1 is anisotropic diffusion. When using 96 anisotropic diffusion the conductance parameter should also be set. */ SetNormalProcessType(int npt)97 void SetNormalProcessType(int npt) 98 { m_NormalProcessType = npt; } 99 100 /** This method returns the isotropic/anisotropic filtering parameter. */ GetNormalProcessType()101 int GetNormalProcessType() const 102 { return m_NormalProcessType; } 103 104 /** This method sets the conductance parameter used in anisotropic 105 * filtering. Useful values for processing 2D and 3D shapes are between 106 * 0.1 and 0.25. Lower values preserve more shape features, higher values 107 * smooth more. As the conductance parameter large, the processing becomes 108 * isotropic. Default is 0. */ SetConductanceParameter(NodeValueType cp)109 void SetConductanceParameter(NodeValueType cp) 110 { 111 m_ConductanceParameter = cp + static_cast< NodeValueType >( 0.001 ); 112 // we add a minimum conductance to avoid divide by zero 113 // can make this a parameter. 114 m_FluxStopConstant = static_cast< NodeValueType > 115 ( -1.0 / ( m_ConductanceParameter * m_ConductanceParameter ) ); 116 } 117 118 /** This method returns the conductance parameter. */ GetConductanceParameter()119 NodeValueType GetConductanceParameter() const 120 { return m_ConductanceParameter; } 121 122 /** This method returns the internal variable FluxStopConstant. */ GetFluxStopConstant()123 NodeValueType GetFluxStopConstant() const 124 { return m_FluxStopConstant; } 125 126 /** This function is called from LevelSetNormalImageFilter for all of the 127 * nodes to compute and store the flux vectors (first derivatives of the 128 * normal vectors. ComputeUpdateNormal then takes derivatives of the flux 129 * vectors. This way we avoid repeating the same flux computations. */ 130 void PrecomputeSparseUpdate(NeighborhoodType & it) const override; 131 132 /** The actual update rule for the normal vectors. */ 133 NormalVectorType ComputeSparseUpdate(NeighborhoodType & neighborhood, 134 void *globalData, 135 const FloatOffsetType & offset) const override; 136 137 protected: 138 NormalVectorDiffusionFunction(); 139 ~NormalVectorDiffusionFunction() override = default; 140 void PrintSelf(std::ostream & os, Indent indent) const override; 141 142 /** The method called in anisotropic diffusion to inhibit diffusion across 143 areas with large curvature. */ FluxStopFunction(const NodeValueType v)144 NodeValueType FluxStopFunction(const NodeValueType v) const 145 { 146 // the slow exp function could be replaced with a lookup table 147 if ( v <= 0.0 ) { return NumericTraits< NodeValueType >::OneValue(); } 148 else { return static_cast< NodeValueType >( std::exp(m_FluxStopConstant * v) ); } 149 } 150 151 private: 152 /** The conductance parameter used for anisotropic diffusion. */ 153 NodeValueType m_ConductanceParameter; 154 155 /** The internal variable used in the FluxStopFunction. It is computed from 156 * ConductanceParameter. */ 157 NodeValueType m_FluxStopConstant; 158 159 /** The isotropic/anisotropic filtering choice parameter. */ 160 int m_NormalProcessType; 161 162 }; 163 } // end namespace itk 164 165 #ifndef ITK_MANUAL_INSTANTIATION 166 #include "itkNormalVectorDiffusionFunction.hxx" 167 #endif 168 169 #endif 170