MeshSmoothing.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2016 Imperial College London
5  * Copyright 2013-2016 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_MeshSmoothing_H
21 #define MIRTK_MeshSmoothing_H
22 
23 #include "mirtk/MeshFilter.h"
24 
25 #include "mirtk/Array.h"
26 
27 class vtkDataArray;
28 
29 
30 namespace mirtk {
31 
32 
33 /**
34  * Smooth scalars and/or points of triangulated surface mesh
35  */
36 class MeshSmoothing : public MeshFilter
37 {
38  mirtkObjectMacro(MeshSmoothing);
39 
40  // ---------------------------------------------------------------------------
41  // Types
42 
43 public:
44 
45  /// Enumeration of smoothing kernel functions
47  {
48  Default, ///< Undefined weighting function, use default
49  Combinatorial, ///< Uniform node weights / "umbrella operator"
50  InverseDistance, ///< Inverse node distance
51  Gaussian, ///< Gaussian node weights
52  AnisotropicGaussian, ///< Anisotropic Gaussian node weights
53  NormalDeviation ///< Weight by cosine of angle made up by normals
54  };
55 
56  /// List of point data array names
57  typedef Array<string> ArrayNames;
58 
59  /// Vector of point data arrays to be smoothed
60  typedef Array<vtkSmartPointer<vtkDataArray> > DataArrays;
61 
62  // ---------------------------------------------------------------------------
63  // Attributes
64 
65 private:
66 
67  /// Input point mask, only points with mask value != 0 are modified
68  mirtkPublicAttributeMacro(vtkSmartPointer<vtkDataArray>, Mask);
69 
70  /// Number of smoothing iterations
71  mirtkPublicAttributeMacro(int, NumberOfIterations);
72 
73  /// Relaxation / scale factor for odd iterations
74  mirtkPublicAttributeMacro(double, Lambda);
75 
76  /// Relaxation / scale factor for even iterations
77  ///
78  /// By default, when _Mu is set to NaN, a _Mu value equal to _Lambda is used.
79  /// A negative _Mu value, greater in magnitude than _Lambda, can be used
80  /// to perform a low-pass filtering of the surface mesh as described in:
81  /// Taubin, G., Curve and Surface Smoothing without Shrinkage, ICCV 1995.
82  mirtkPublicAttributeMacro(double, Mu);
83 
84  /// Smoothing kernel parameter
85  ///
86  /// In case of a Gaussian smoothing kernel, if the sigma value is negative,
87  /// the standard deviation of the Gaussian kernel is set to the average
88  /// edge length times the absolute value of \c _Sigma. If _Sigma is zero,
89  /// the average edge length is used as standard deviation. The _Sigma attribute
90  /// is set to the actual used standard deviation after the filter execution.
91  ///
92  /// In case of the inverse distance weighting, the _Sigma value is added to
93  /// the edge length before computing the inverse value.
94  mirtkPublicAttributeMacro(double, Sigma);
95 
96  /// Smoothing kernel parameter in direction of maximum curvature
97  ///
98  /// \note The direction of maximum principle curvature is orthogonal to the
99  /// direction in which the surface is most bended! It is the direction
100  /// with the most variance, i.e., along ridges, not orthogonal to these.
101  ///
102  /// This parameter is only used by the anisotropic Gaussian kernel.
103  /// By default, i.e., when _Sigma2 = 0, the standard deviation along the
104  /// direction of maximum change is half the standard deviation along the
105  /// direction of minimum change. Hence, the surface points or data values are
106  /// smoothed less in the direction of maximum change (i.e., maximum curvature).
107  /// If the sigma value is negative, the standard deviation is set to the
108  /// average edge length times the absolute value of \c _Sigma2.
109  ///
110  /// When an array of local geometry tensors is used instead of the direction
111  /// of minimum and/or maximum change, the default is to use an isotropic
112  /// Gaussian kernel in the local coordinate system defined by the tensor.
113  /// In this case the axes of the local coordinate system are expected to be
114  /// scaled anisotropically as in case of the curvature tensor, for example.
115  mirtkPublicAttributeMacro(double, MaximumDirectionSigma);
116 
117  /// Smoothing kernel function
118  mirtkPublicAttributeMacro(WeightFunction, Weighting);
119 
120  /// Name of input point data array with local geometry tensor used for anisotropic smoothing
121  ///
122  /// For example, the local curvature tensors can be computed using
123  /// PolyDataCurvature and used for anisotropic Gaussian smoothing.
124  /// The input point data array is then named PolyDataCurvature::TENSOR.
125  mirtkPublicAttributeMacro(string, GeometryTensorName);
126 
127  /// Name of input point data array with direction along which to smooth less
128  /// \note This array is only used if no _GeometryTensorName is specified.
129  mirtkPublicAttributeMacro(string, MinimumDirectionName);
130 
131  /// Name of input point data array with direction along which to smooth more
132  /// \note This array is only used if no _GeometryTensorName is specified.
133  mirtkPublicAttributeMacro(string, MaximumDirectionName);
134 
135  /// Whether to average values of adjacent nodes only or to
136  /// also include the node's values themselves in the average
137  ///
138  /// \note In case of an InverseDistance node weighting, the values of the
139  /// node itself are only included in the average if _Sigma > .0.
140  mirtkPublicAttributeMacro(bool, AdjacentValuesOnly);
141 
142  /// Whether to smooth the node positions, i.e., input geometry
143  mirtkPublicAttributeMacro(bool, SmoothPoints);
144 
145  /// Smooth magnitude of (vector-valued) data arrays
146  mirtkPublicAttributeMacro(bool, SmoothMagnitude);
147 
148  /// Smooth (vector-valued) data arrays by only considering those adjacent
149  /// vectors which have a positive dot product with the data vector at the
150  /// current node position
151  mirtkPublicAttributeMacro(bool, SignedSmoothing);
152 
153  /// Names of input point data arrays to be smoothed
154  mirtkPublicAttributeMacro(ArrayNames, SmoothArrays);
155 
156  /// Array vtkDataSetAttributes::AttributeTypes
157  mirtkAttributeMacro(Array<int>, AttributeTypes);
158 
159  /// Input point data arrays to be smoothed
160  mirtkAttributeMacro(DataArrays, InputArrays);
161 
162  /// Output point data arrays
163  mirtkAttributeMacro(DataArrays, OutputArrays);
164 
165  /// Verbosity of output messages
166  mirtkPublicAttributeMacro(int, Verbose);
167 
168  /// Copy attributes of this class from another instance
169  void CopyAttributes(const MeshSmoothing &);
170 
171  // ---------------------------------------------------------------------------
172  // Construction/Destruction
173 
174 public:
175 
176  /// Constructor
177  MeshSmoothing();
178 
179  /// Copy constructor
180  MeshSmoothing(const MeshSmoothing &);
181 
182  /// Assignment operator
184 
185  /// Destructor
186  virtual ~MeshSmoothing();
187 
188  /// Add named point data array to list of arrays to be smoothed
189  ///
190  /// \param[in] name Name of data array to smooth.
191  /// \param[in] attr Array attribute type, see vtkDataSetAttributes::AttributeTypes.
192  /// When vtkDataSetAttributes::VECTORS, an array with 3 components
193  /// is treated as 3D direction vectors and the smoothing is
194  /// performed independent of the sign of the direction.
195  void SmoothArray(const char *name, int attr = -1);
196 
197  // ---------------------------------------------------------------------------
198  // Execution
199 
200 protected:
201 
202  /// Initialize filter after input and parameters are set
203  virtual void Initialize();
204 
205  /// Execute filter
206  virtual void Execute();
207 
208  /// Finalize filter execution
209  virtual void Finalize();
210 
211  // ---------------------------------------------------------------------------
212  // Alternative VTK-like interface
213 
214 public:
215 
216  /// Set number of smoothing iterations
217  mirtkSetMacro(NumberOfIterations, int);
218 
219  /// Get number of smoothing iterations
220  mirtkGetMacro(NumberOfIterations, int);
221 
222  /// Set relaxation factor
223  mirtkSetMacro(Lambda, double);
224 
225  /// Get relaxation factor
226  mirtkGetMacro(Lambda, double);
227 
228  /// Set smoothing kernel standard deviation
229  mirtkSetMacro(Sigma, double);
230 
231  /// Get smoothing kernel standard deviation
232  mirtkGetMacro(Sigma, double);
233 
234  /// Set smoothing kernel standard deviation in direction of maximum curvature
235  mirtkSetMacro(MaximumDirectionSigma, double);
236 
237  /// Get smoothing kernel standard deviation in direction of maximum curvature
238  mirtkGetMacro(MaximumDirectionSigma, double);
239 
240  /// Enable/disable averaging of adjacent node values only
241  mirtkOnOffMacro(AdjacentValuesOnly);
242 
243  /// Enable/disable smoothing of node positions
244  mirtkOnOffMacro(SmoothPoints);
245 
246 };
247 
248 ////////////////////////////////////////////////////////////////////////////////
249 // Inline definitions
250 ////////////////////////////////////////////////////////////////////////////////
251 
252 // -----------------------------------------------------------------------------
253 template <>
254 inline bool FromString(const char *str, MeshSmoothing::WeightFunction &value)
255 {
256  const string lstr = ToLower(Trim(str));
257  if (lstr == "combinatorial") value = MeshSmoothing::Combinatorial;
258  else if (lstr == "inversedistance") value = MeshSmoothing::InverseDistance;
259  else if (lstr == "gaussian") value = MeshSmoothing::Gaussian;
260  else if (lstr == "anisotropicgaussian") value = MeshSmoothing::AnisotropicGaussian;
261  else {
262  value = MeshSmoothing::Default;
263  return (lstr == "default");
264  }
265  return true;
266 }
267 
268 // -----------------------------------------------------------------------------
269 inline void MeshSmoothing::SmoothArray(const char *name, int attr)
270 {
271  _SmoothArrays.push_back(name);
272  _AttributeTypes.push_back(attr);
273 }
274 
275 
276 } // namespace mirtk
277 
278 #endif // MIRTK_MeshSmoothing_H
Anisotropic Gaussian node weights.
Definition: MeshSmoothing.h:52
MeshSmoothing & operator=(const MeshSmoothing &)
Assignment operator.
string Trim(const string &str, const string &what=" \\)
virtual ~MeshSmoothing()
Destructor.
virtual void Initialize()
Initialize filter after input and parameters are set.
Array< string > ArrayNames
List of point data array names.
Definition: MeshSmoothing.h:57
MeshSmoothing()
Constructor.
string ToLower(const string &)
Convert string to lowercase letters.
Definition: IOConfig.h:41
virtual void Execute()
Execute filter.
mirtkSetMacro(NumberOfIterations, int)
Set number of smoothing iterations.
Array< vtkSmartPointer< vtkDataArray > > DataArrays
Vector of point data arrays to be smoothed.
Definition: MeshSmoothing.h:60
Undefined weighting function, use default.
Definition: MeshSmoothing.h:48
Weight by cosine of angle made up by normals.
Definition: MeshSmoothing.h:53
bool FromString(const char *str, EnergyMeasure &value)
Convert energy measure string to enumeration value.
void SmoothArray(const char *name, int attr=-1)
WeightFunction
Enumeration of smoothing kernel functions.
Definition: MeshSmoothing.h:46
Uniform node weights / "umbrella operator".
Definition: MeshSmoothing.h:49
virtual void Finalize()
Finalize filter execution.
Gaussian node weights.
Definition: MeshSmoothing.h:51
mirtkOnOffMacro(AdjacentValuesOnly)
Enable/disable averaging of adjacent node values only.
mirtkGetMacro(NumberOfIterations, int)
Get number of smoothing iterations.