OpenVDB  12.0.0
LevelSetFilter.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 /// @author Ken Museth
5 ///
6 /// @file tools/LevelSetFilter.h
7 ///
8 /// @brief Performs various types of level set deformations with
9 /// interface tracking. These unrestricted deformations include
10 /// surface smoothing (e.g., Laplacian flow), filtering (e.g., mean
11 /// value) and morphological operations (e.g., morphological opening).
12 /// All these operations can optionally be masked with another grid that
13 /// acts as an alpha-mask.
14 
15 #ifndef OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED
16 #define OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED
17 
18 #include "LevelSetTracker.h"
19 #include "Interpolation.h"
20 #include <algorithm> // for std::max()
21 #include <functional>
22 #include <type_traits>
23 
24 
25 namespace openvdb {
27 namespace OPENVDB_VERSION_NAME {
28 namespace tools {
29 
30 /// @brief Filtering (e.g. diffusion) of narrow-band level sets. An
31 /// optional scalar field can be used to produce a (smooth) alpha mask
32 /// for the filtering.
33 ///
34 /// @note This class performs proper interface tracking which allows
35 /// for unrestricted surface deformations
36 template<typename GridT,
37  typename MaskT = typename GridT::template ValueConverter<float>::Type,
38  typename InterruptT = util::NullInterrupter>
39 class LevelSetFilter : public LevelSetTracker<GridT, InterruptT>
40 {
41 public:
43  using GridType = GridT;
44  using MaskType = MaskT;
45  using TreeType = typename GridType::TreeType;
46  using ValueType = typename TreeType::ValueType;
47  using AlphaType = typename MaskType::ValueType;
48  static_assert(std::is_floating_point<AlphaType>::value,
49  "LevelSetFilter requires a mask grid with floating-point values");
50 
51  /// @brief Main constructor from a grid
52  /// @param grid The level set to be filtered.
53  /// @param interrupt Optional interrupter.
54  LevelSetFilter(GridType& grid, InterruptT* interrupt = nullptr)
55  : BaseType(grid, interrupt)
56  , mMinMask(0)
57  , mMaxMask(1)
58  , mInvertMask(false)
59  {
60  }
61  /// @brief Default destructor
62  ~LevelSetFilter() override {}
63 
64  /// @brief Return the minimum value of the mask to be used for the
65  /// derivation of a smooth alpha value.
66  AlphaType minMask() const { return mMinMask; }
67  /// @brief Return the maximum value of the mask to be used for the
68  /// derivation of a smooth alpha value.
69  AlphaType maxMask() const { return mMaxMask; }
70  /// @brief Define the range for the (optional) scalar mask.
71  /// @param min Minimum value of the range.
72  /// @param max Maximum value of the range.
73  /// @details Mask values outside the range maps to alpha values of
74  /// respectfully zero and one, and values inside the range maps
75  /// smoothly to 0->1 (unless of course the mask is inverted).
76  /// @throw ValueError if @a min is not smaller than @a max.
78  {
79  if (!(min < max)) OPENVDB_THROW(ValueError, "Invalid mask range (expects min < max)");
80  mMinMask = min;
81  mMaxMask = max;
82  }
83 
84  /// @brief Return true if the mask is inverted, i.e. min->max in the
85  /// original mask maps to 1->0 in the inverted alpha mask.
86  bool isMaskInverted() const { return mInvertMask; }
87  /// @brief Invert the optional mask, i.e. min->max in the original
88  /// mask maps to 1->0 in the inverted alpha mask.
89  void invertMask(bool invert=true) { mInvertMask = invert; }
90 
91  /// @brief One iteration of mean-curvature flow of the level set.
92  /// @param mask Optional alpha mask.
93  void meanCurvature(const MaskType* mask = nullptr)
94  {
95  Filter f(this, mask); f.meanCurvature();
96  }
97 
98  /// @brief One iteration of filleting on the level set.
99  /// @param mask Optional alpha mask.
100  ///
101  /// @note This filter rounds off concave edges to create a smoother
102  /// transition between surfaces. Fillets a level set by offsetting
103  /// at locations with a negative principal curvature, proportional
104  /// to its magnitude leaves locations with non-negative principal
105  /// curvatures untouched. This filter converges to the convex hull
106  /// if iterated enough times.
107  ///
108  /// @details See also Level Set Methods and Fast Marching Methods
109  /// by James Sethian, pp. 204.
110  void fillet(const MaskType* mask = nullptr)
111  {
112  Filter f(this, mask); f.fillet();
113  }
114 
115  /// @brief One iteration of Laplacian flow of the level set.
116  /// @param mask Optional alpha mask.
117  void laplacian(const MaskType* mask = nullptr)
118  {
119  Filter f(this, mask); f.laplacian();
120  }
121 
122  /// @brief One iteration of a fast separable Gaussian filter.
123  /// @param width Width of the Gaussian kernel in voxel units.
124  /// @param mask Optional alpha mask.
125  ///
126  /// @note This is approximated as 4 iterations of a separable mean filter
127  /// which typically leads an approximation that's better than 95%!
128  void gaussian(int width = 1, const MaskType* mask = nullptr)
129  {
130  Filter f(this, mask); f.gaussian(width);
131  }
132 
133  /// @brief Offset the level set by the specified (world) distance.
134  /// @param offset Value of the offset.
135  /// @param mask Optional alpha mask.
136  void offset(ValueType offset, const MaskType* mask = nullptr)
137  {
138  Filter f(this, mask); f.offset(offset);
139  }
140 
141  /// @brief One iteration of median-value flow of the level set.
142  /// @param width Width of the median-value kernel in voxel units.
143  /// @param mask Optional alpha mask.
144  ///
145  /// @warning This filter is not separable and is hence relatively
146  /// slow!
147  void median(int width = 1, const MaskType* mask = nullptr)
148  {
149  Filter f(this, mask); f.median(width);
150  }
151 
152  /// @brief One iteration of mean-value flow of the level set.
153  /// @param width Width of the mean-value kernel in voxel units.
154  /// @param mask Optional alpha mask.
155  ///
156  /// @note This filter is separable so it's fast!
157  void mean(int width = 1, const MaskType* mask = nullptr)
158  {
159  Filter f(this, mask); f.mean(width);
160  }
161 
162 private:
163  // disallow copy construction and copy by assignment!
164  LevelSetFilter(const LevelSetFilter&);// not implemented
165  LevelSetFilter& operator=(const LevelSetFilter&);// not implemented
166 
167  // Private struct that implements all the filtering.
168  struct Filter
169  {
170  using LeafT = typename TreeType::LeafNodeType;
171  using VoxelIterT = typename LeafT::ValueOnIter;
172  using VoxelCIterT = typename LeafT::ValueOnCIter;
173  using BufferT = typename tree::LeafManager<TreeType>::BufferType;
175  using LeafIterT = typename LeafRange::Iterator;
176  using AlphaMaskT = tools::AlphaMask<GridT, MaskT>;
177 
178  Filter(LevelSetFilter* parent, const MaskType* mask) : mParent(parent), mMask(mask) {}
179  Filter(const Filter&) = default;
180  ~Filter() {}
181 
182  void box(int width);
183  void median(int width);
184  void mean(int width);
185  void gaussian(int width);
186  void laplacian();
187  void meanCurvature();
188  void fillet();
189  void offset(ValueType value);
190  void operator()(const LeafRange& r) const
191  {
192  if (mTask) mTask(const_cast<Filter*>(this), r);
193  else OPENVDB_THROW(ValueError, "task is undefined - don\'t call this method directly");
194  }
195  void cook(bool swap)
196  {
197  const int n = mParent->getGrainSize();
198  if (n>0) {
199  tbb::parallel_for(mParent->leafs().leafRange(n), *this);
200  } else {
201  (*this)(mParent->leafs().leafRange());
202  }
203  if (swap) mParent->leafs().swapLeafBuffer(1, n==0);
204  }
205 
206  template <size_t Axis>
207  struct Avg {
208  Avg(const GridT& grid, Int32 w) :
209  acc(grid.tree()), width(w), frac(1/ValueType(2*w+1)) {}
210  inline ValueType operator()(Coord xyz)
211  {
212  ValueType sum = zeroVal<ValueType>();
213  Int32& i = xyz[Axis], j = i + width;
214  for (i -= width; i <= j; ++i) sum += acc.getValue(xyz);
215  return sum*frac;
216  }
217  typename GridT::ConstAccessor acc;
218  const Int32 width;
220  };
221 
222  template<typename AvgT>
223  void boxImpl(const LeafRange& r, Int32 w);
224 
225  void boxXImpl(const LeafRange& r, Int32 w) { this->boxImpl<Avg<0> >(r,w); }
226  void boxZImpl(const LeafRange& r, Int32 w) { this->boxImpl<Avg<1> >(r,w); }
227  void boxYImpl(const LeafRange& r, Int32 w) { this->boxImpl<Avg<2> >(r,w); }
228 
229  void medianImpl(const LeafRange&, int);
230  void meanCurvatureImpl(const LeafRange&);
231  void filletImpl(const LeafRange&);
232  void laplacianImpl(const LeafRange&);
233  void offsetImpl(const LeafRange&, ValueType);
234 
235  LevelSetFilter* mParent;
236  const MaskType* mMask;
237  typename std::function<void (Filter*, const LeafRange&)> mTask;
238  }; // end of private Filter struct
239 
240  AlphaType mMinMask, mMaxMask;
241  bool mInvertMask;
242 
243 }; // end of LevelSetFilter class
244 
245 
246 ////////////////////////////////////////
247 
248 template<typename GridT, typename MaskT, typename InterruptT>
249 inline void
251 {
252  mParent->startInterrupter("Median-value flow of level set");
253 
254  mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
255 
256  mTask = std::bind(&Filter::medianImpl,
257  std::placeholders::_1, std::placeholders::_2, std::max(1, width));
258  this->cook(true);
259 
260  mParent->track();
261 
262  mParent->endInterrupter();
263 }
264 
265 template<typename GridT, typename MaskT, typename InterruptT>
266 inline void
268 {
269  mParent->startInterrupter("Mean-value flow of level set");
270 
271  this->box(width);
272 
273  mParent->endInterrupter();
274 }
275 
276 template<typename GridT, typename MaskT, typename InterruptT>
277 inline void
279 {
280  mParent->startInterrupter("Gaussian flow of level set");
281 
282  for (int n=0; n<4; ++n) this->box(width);
283 
284  mParent->endInterrupter();
285 }
286 
287 template<typename GridT, typename MaskT, typename InterruptT>
288 inline void
290 {
291  mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
292 
293  width = std::max(1, width);
294 
295  mTask = std::bind(&Filter::boxXImpl, std::placeholders::_1, std::placeholders::_2, width);
296  this->cook(true);
297 
298  mTask = std::bind(&Filter::boxYImpl, std::placeholders::_1, std::placeholders::_2, width);
299  this->cook(true);
300 
301  mTask = std::bind(&Filter::boxZImpl, std::placeholders::_1, std::placeholders::_2, width);
302  this->cook(true);
303 
304  mParent->track();
305 }
306 
307 template<typename GridT, typename MaskT, typename InterruptT>
308 inline void
310 {
311  mParent->startInterrupter("Mean-curvature flow of level set");
312 
313  mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
314 
315  mTask = std::bind(&Filter::meanCurvatureImpl, std::placeholders::_1, std::placeholders::_2);
316  this->cook(true);
317 
318  mParent->track();
319 
320  mParent->endInterrupter();
321 }
322 
323 template<typename GridT, typename MaskT, typename InterruptT>
324 inline void
326 {
327  mParent->startInterrupter("Filleting level set");
328 
329  mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
330 
331  mTask = std::bind(&Filter::filletImpl, std::placeholders::_1, std::placeholders::_2);
332  this->cook(true);
333 
334  mParent->track();
335 
336  mParent->endInterrupter();
337 }
338 
339 template<typename GridT, typename MaskT, typename InterruptT>
340 inline void
342 {
343  mParent->startInterrupter("Laplacian flow of level set");
344 
345  mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
346 
347  mTask = std::bind(&Filter::laplacianImpl, std::placeholders::_1, std::placeholders::_2);
348  this->cook(true);
349 
350  mParent->track();
351 
352  mParent->endInterrupter();
353 }
354 
355 template<typename GridT, typename MaskT, typename InterruptT>
356 inline void
358 {
359  mParent->startInterrupter("Offsetting level set");
360 
361  mParent->leafs().removeAuxBuffers();// no auxiliary buffers required
362 
363  const ValueType CFL = ValueType(0.5) * mParent->voxelSize(), offset = openvdb::math::Abs(value);
364  ValueType dist = 0.0;
365  while (offset-dist > ValueType(0.001)*CFL && mParent->checkInterrupter()) {
366  const ValueType delta = openvdb::math::Min(offset-dist, CFL);
367  dist += delta;
368 
369  mTask = std::bind(&Filter::offsetImpl,
370  std::placeholders::_1, std::placeholders::_2, copysign(delta, value));
371  this->cook(false);
372 
373  mParent->track();
374  }
375 
376  mParent->endInterrupter();
377 }
378 
379 
380 ///////////////////////// PRIVATE METHODS //////////////////////
381 
382 /// Performs parabolic mean-curvature diffusion
383 template<typename GridT, typename MaskT, typename InterruptT>
384 inline void
386 {
387  mParent->checkInterrupter();
388  //const float CFL = 0.9f, dt = CFL * mDx * mDx / 6.0f;
389  const ValueType dx = mParent->voxelSize(), dt = math::Pow2(dx) / ValueType(3.0);
390  math::CurvatureStencil<GridType> stencil(mParent->grid(), dx);
391  if (mMask) {
392  typename AlphaMaskT::FloatType a, b;
393  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
394  mParent->maxMask(), mParent->isMaskInverted());
395  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
396  ValueType* buffer = leafIter.buffer(1).data();
397  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
398  if (alpha(iter.getCoord(), a, b)) {
399  stencil.moveTo(iter);
400  const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.meanCurvatureNormGrad();
401  buffer[iter.pos()] = b * phi0 + a * phi1;
402  }
403  }
404  }
405  } else {
406  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
407  ValueType* buffer = leafIter.buffer(1).data();
408  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
409  stencil.moveTo(iter);
410  buffer[iter.pos()] = *iter + dt*stencil.meanCurvatureNormGrad();
411  }
412  }
413  }
414 }
415 
416 /// Fillets a level set by offsetting at locations with a negative principal
417 /// curvature, proportional to its magnitude. Leaves locations with non-negative
418 /// principal curvatures untouched. This filter converges to the convex hull if
419 /// iterated enough times.
420 template<typename GridT, typename MaskT, typename InterruptT>
421 inline void
423 {
424  mParent->checkInterrupter();
425 
426  const ValueType dx = mParent->voxelSize(), dt = math::Pow2(dx) / ValueType(3);
427  math::CurvatureStencil<GridType> stencil(mParent->grid(), dx);
428 
429  if (mMask) {
430  typename AlphaMaskT::FloatType a, b;
431  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
432  mParent->maxMask(), mParent->isMaskInverted());
433  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
434  ValueType* buffer = leafIter.buffer(1).data();
435  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
436  if (alpha(iter.getCoord(), a, b)) {
437  stencil.moveTo(iter);
438 
439  const ValueType kappa = stencil.principalCurvatures().first;
440 
441  const ValueType phi0 = *iter,
442  phi1 = phi0 + math::Min(ValueType(0), dt*kappa);
443  buffer[iter.pos()] = b * phi0 + a * phi1;
444  }
445  }
446  }
447  } else {
448  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
449  ValueType* buffer = leafIter.buffer(1).data();
450  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
451  stencil.moveTo(iter);
452 
453  const ValueType kappa = stencil.principalCurvatures().first;
454 
455  if (math::isNegative(kappa))
456  buffer[iter.pos()] = *iter + dt*kappa;
457  }
458  }
459  }
460 }
461 
462 /// Performs Laplacian diffusion. Note if the grids contains a true
463 /// signed distance field (e.g. a solution to the Eikonal equation)
464 /// Laplacian diffusions (e.g. geometric heat equation) is actually
465 /// identical to mean curvature diffusion, yet less computationally
466 /// expensive! In other words if you're performing renormalization
467 /// anyway (e.g. rebuilding the narrow-band) you should consider
468 /// performing Laplacian diffusion over mean curvature flow!
469 template<typename GridT, typename MaskT, typename InterruptT>
470 inline void
472 {
473  mParent->checkInterrupter();
474  //const float CFL = 0.9f, half_dt = CFL * mDx * mDx / 12.0f;
475  const ValueType dx = mParent->voxelSize(), dt = math::Pow2(dx) / ValueType(6.0);
476  math::GradStencil<GridType> stencil(mParent->grid(), dx);
477  if (mMask) {
478  typename AlphaMaskT::FloatType a, b;
479  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
480  mParent->maxMask(), mParent->isMaskInverted());
481  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
482  ValueType* buffer = leafIter.buffer(1).data();
483  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
484  if (alpha(iter.getCoord(), a, b)) {
485  stencil.moveTo(iter);
486  const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.laplacian();
487  buffer[iter.pos()] = b * phi0 + a * phi1;
488  }
489  }
490  }
491  } else {
492  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
493  ValueType* buffer = leafIter.buffer(1).data();
494  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
495  stencil.moveTo(iter);
496  buffer[iter.pos()] = *iter + dt*stencil.laplacian();
497  }
498  }
499  }
500 }
501 
502 /// Offsets the values by a constant
503 template<typename GridT, typename MaskT, typename InterruptT>
504 inline void
506  const LeafRange& range, ValueType offset)
507 {
508  mParent->checkInterrupter();
509  if (mMask) {
510  typename AlphaMaskT::FloatType a, b;
511  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
512  mParent->maxMask(), mParent->isMaskInverted());
513  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
514  for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
515  if (alpha(iter.getCoord(), a, b)) iter.setValue(*iter + a*offset);
516  }
517  }
518  } else {
519  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
520  for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
521  iter.setValue(*iter + offset);
522  }
523  }
524  }
525 }
526 
527 /// Performs simple but slow median-value diffusion
528 template<typename GridT, typename MaskT, typename InterruptT>
529 inline void
530 LevelSetFilter<GridT, MaskT, InterruptT>::Filter::medianImpl(const LeafRange& range, int width)
531 {
532  mParent->checkInterrupter();
533  typename math::DenseStencil<GridType> stencil(mParent->grid(), width);//creates local cache!
534  if (mMask) {
535  typename AlphaMaskT::FloatType a, b;
536  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
537  mParent->maxMask(), mParent->isMaskInverted());
538  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
539  ValueType* buffer = leafIter.buffer(1).data();
540  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
541  if (alpha(iter.getCoord(), a, b)) {
542  stencil.moveTo(iter);
543  buffer[iter.pos()] = b * (*iter) + a * stencil.median();
544  }
545  }
546  }
547  } else {
548  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
549  ValueType* buffer = leafIter.buffer(1).data();
550  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
551  stencil.moveTo(iter);
552  buffer[iter.pos()] = stencil.median();
553  }
554  }
555  }
556 }
557 
558 /// One dimensional convolution of a separable box filter
559 template<typename GridT, typename MaskT, typename InterruptT>
560 template <typename AvgT>
561 inline void
563 {
564  mParent->checkInterrupter();
565  AvgT avg(mParent->grid(), w);
566  if (mMask) {
567  typename AlphaMaskT::FloatType a, b;
568  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
569  mParent->maxMask(), mParent->isMaskInverted());
570  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
571  ValueType* buffer = leafIter.buffer(1).data();
572  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
573  const Coord xyz = iter.getCoord();
574  if (alpha(xyz, a, b)) buffer[iter.pos()] = b * (*iter)+ a * avg(xyz);
575  }
576  }
577  } else {
578  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
579  ValueType* buffer = leafIter.buffer(1).data();
580  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
581  buffer[iter.pos()] = avg(iter.getCoord());
582  }
583  }
584  }
585 }
586 
587 
588 ////////////////////////////////////////
589 
590 
591 // Explicit Template Instantiation
592 
593 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
594 
595 #ifdef OPENVDB_INSTANTIATE_LEVELSETFILTER
597 #endif
598 
601 
602 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
603 
604 
605 } // namespace tools
606 } // namespace OPENVDB_VERSION_NAME
607 } // namespace openvdb
608 
609 #endif // OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED
Type Pow2(Type x)
Return x2.
Definition: Math.h:548
bool isNegative(const Type &x)
Return true if x is less than zero.
Definition: Math.h:367
LevelSetFilter(GridType &grid, InterruptT *interrupt=nullptr)
Main constructor from a grid.
Definition: LevelSetFilter.h:54
~LevelSetFilter() override
Default destructor.
Definition: LevelSetFilter.h:62
Performs multi-threaded interface tracking of narrow band level sets. This is the building-block for ...
LeafManagerType & leafs()
Definition: LevelSetTracker.h:189
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Coord Abs(const Coord &xyz)
Definition: Coord.h:518
Definition: Stencils.h:1231
Performs multi-threaded interface tracking of narrow band level sets.
Definition: LevelSetTracker.h:57
typename GridType::TreeType TreeType
Definition: LevelSetFilter.h:45
void setMaskRange(AlphaType min, AlphaType max)
Define the range for the (optional) scalar mask.
Definition: LevelSetFilter.h:77
Definition: Stencils.h:1515
bool isMaskInverted() const
Return true if the mask is inverted, i.e. min->max in the original mask maps to 1->0 in the inverted ...
Definition: LevelSetFilter.h:86
Filtering (e.g. diffusion) of narrow-band level sets. An optional scalar field can be used to produce...
Definition: LevelSetFilter.h:39
void invertMask(bool invert=true)
Invert the optional mask, i.e. min->max in the original mask maps to 1->0 in the inverted alpha mask...
Definition: LevelSetFilter.h:89
void startInterrupter(const char *msg)
Definition: LevelSetTracker.h:369
typename TreeType::ValueType ValueType
Definition: LevelSetFilter.h:46
int32_t Int32
Definition: Types.h:56
const Type & Min(const Type &a, const Type &b)
Return the minimum of two values.
Definition: Math.h:656
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
Definition: Exceptions.h:65
const ValueType frac
Definition: LevelSetFilter.h:219
GridType::Ptr laplacian(const GridType &grid, bool threaded, InterruptT *interrupt)
Compute the Laplacian of the given scalar grid.
Definition: GridOperators.h:1018
void median(int width=1, const MaskType *mask=nullptr)
One iteration of median-value flow of the level set.
Definition: LevelSetFilter.h:147
void meanCurvature(const MaskType *mask=nullptr)
One iteration of mean-curvature flow of the level set.
Definition: LevelSetFilter.h:93
Axis
Definition: Math.h:901
GridType::Ptr meanCurvature(const GridType &grid, bool threaded, InterruptT *interrupt)
Compute the mean curvature of the given grid.
Definition: GridOperators.h:1035
GridT::ConstAccessor acc
Definition: LevelSetFilter.h:217
Definition: Exceptions.h:13
bool checkInterrupter()
Definition: LevelSetTracker.h:385
void fillet(const MaskType *mask=nullptr)
One iteration of filleting on the level set.
Definition: LevelSetFilter.h:110
void mean(int width=1, const MaskType *mask=nullptr)
One iteration of mean-value flow of the level set.
Definition: LevelSetFilter.h:157
ValueType operator()(Coord xyz)
Definition: LevelSetFilter.h:210
typename LeafManagerType::LeafRange LeafRange
Definition: LevelSetTracker.h:67
Dense stencil of a given width.
Definition: Stencils.h:1764
typename MaskType::ValueType AlphaType
Definition: LevelSetFilter.h:47
void offset(ValueType offset, const MaskType *mask=nullptr)
Offset the level set by the specified (world) distance.
Definition: LevelSetFilter.h:136
typename CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition: LeafManager.h:96
Avg(const GridT &grid, Int32 w)
Definition: LevelSetFilter.h:208
#define OPENVDB_INSTANTIATE_CLASS
Definition: version.h.in:158
void gaussian(int width=1, const MaskType *mask=nullptr)
One iteration of a fast separable Gaussian filter.
Definition: LevelSetFilter.h:128
MaskT MaskType
Definition: LevelSetFilter.h:44
Definition: Interpolation.h:544
FloatT FloatType
Definition: Interpolation.h:552
GridT GridType
Definition: LevelSetFilter.h:43
AlphaType minMask() const
Return the minimum value of the mask to be used for the derivation of a smooth alpha value...
Definition: LevelSetFilter.h:66
AlphaType maxMask() const
Return the maximum value of the mask to be used for the derivation of a smooth alpha value...
Definition: LevelSetFilter.h:69
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:106
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
const Int32 width
Definition: LevelSetFilter.h:218
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
void laplacian(const MaskType *mask=nullptr)
One iteration of Laplacian flow of the level set.
Definition: LevelSetFilter.h:117