OpenVDB 12.0.0
 
Loading...
Searching...
No Matches
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
25namespace openvdb {
27namespace OPENVDB_VERSION_NAME {
28namespace 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
36template<typename GridT,
37 typename MaskT = typename GridT::template ValueConverter<float>::Type,
38 typename InterruptT = util::NullInterrupter>
39class LevelSetFilter : public LevelSetTracker<GridT, InterruptT>
40{
41public:
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
162private:
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;
174 using LeafRange = typename tree::LeafManager<TreeType>::LeafRange;
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)) {}
211 {
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;
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
248template<typename GridT, typename MaskT, typename InterruptT>
249inline void
250LevelSetFilter<GridT, MaskT, InterruptT>::Filter::median(int width)
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
265template<typename GridT, typename MaskT, typename InterruptT>
266inline void
267LevelSetFilter<GridT, MaskT, InterruptT>::Filter::mean(int width)
268{
269 mParent->startInterrupter("Mean-value flow of level set");
270
271 this->box(width);
272
273 mParent->endInterrupter();
274}
275
276template<typename GridT, typename MaskT, typename InterruptT>
277inline void
278LevelSetFilter<GridT, MaskT, InterruptT>::Filter::gaussian(int width)
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
287template<typename GridT, typename MaskT, typename InterruptT>
288inline void
289LevelSetFilter<GridT, MaskT, InterruptT>::Filter::box(int width)
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
307template<typename GridT, typename MaskT, typename InterruptT>
308inline void
309LevelSetFilter<GridT, MaskT, InterruptT>::Filter::meanCurvature()
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
323template<typename GridT, typename MaskT, typename InterruptT>
324inline void
325LevelSetFilter<GridT, MaskT, InterruptT>::Filter::fillet()
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
339template<typename GridT, typename MaskT, typename InterruptT>
340inline void
341LevelSetFilter<GridT, MaskT, InterruptT>::Filter::laplacian()
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
355template<typename GridT, typename MaskT, typename InterruptT>
356inline void
357LevelSetFilter<GridT, MaskT, InterruptT>::Filter::offset(ValueType value)
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
383template<typename GridT, typename MaskT, typename InterruptT>
384inline void
385LevelSetFilter<GridT, MaskT, InterruptT>::Filter::meanCurvatureImpl(const LeafRange& range)
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.
420template<typename GridT, typename MaskT, typename InterruptT>
421inline void
422LevelSetFilter<GridT, MaskT, InterruptT>::Filter::filletImpl(const LeafRange& range)
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!
469template<typename GridT, typename MaskT, typename InterruptT>
470inline void
471LevelSetFilter<GridT, MaskT, InterruptT>::Filter::laplacianImpl(const LeafRange& range)
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
503template<typename GridT, typename MaskT, typename InterruptT>
504inline void
505LevelSetFilter<GridT, MaskT, InterruptT>::Filter::offsetImpl(
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
528template<typename GridT, typename MaskT, typename InterruptT>
529inline void
530LevelSetFilter<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
559template<typename GridT, typename MaskT, typename InterruptT>
560template <typename AvgT>
561inline void
562LevelSetFilter<GridT, MaskT, InterruptT>::Filter::boxImpl(const LeafRange& range, Int32 w)
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
599OPENVDB_INSTANTIATE_CLASS LevelSetFilter<FloatGrid, FloatGrid, util::NullInterrupter>;
600OPENVDB_INSTANTIATE_CLASS LevelSetFilter<DoubleGrid, FloatGrid, util::NullInterrupter>;
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
Performs multi-threaded interface tracking of narrow band level sets. This is the building-block for ...
Definition Exceptions.h:65
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Definition Interpolation.h:545
Volume filtering (e.g., diffusion) with optional alpha masking.
Definition Filter.h:47
Filtering (e.g. diffusion) of narrow-band level sets. An optional scalar field can be used to produce...
Definition LevelSetFilter.h:40
void laplacian(const MaskType *mask=nullptr)
One iteration of Laplacian flow of the level set.
Definition LevelSetFilter.h:117
typename TreeType::ValueType ValueType
Definition LevelSetFilter.h:46
void fillet(const MaskType *mask=nullptr)
One iteration of filleting on the level set.
Definition LevelSetFilter.h:110
void gaussian(int width=1, const MaskType *mask=nullptr)
One iteration of a fast separable Gaussian filter.
Definition LevelSetFilter.h:128
typename MaskType::ValueType AlphaType
Definition LevelSetFilter.h:47
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
void meanCurvature(const MaskType *mask=nullptr)
One iteration of mean-curvature flow of the level set.
Definition LevelSetFilter.h:93
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 median(int width=1, const MaskType *mask=nullptr)
One iteration of median-value flow of the level set.
Definition LevelSetFilter.h:147
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
void mean(int width=1, const MaskType *mask=nullptr)
One iteration of mean-value flow of the level set.
Definition LevelSetFilter.h:157
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
void offset(ValueType offset, const MaskType *mask=nullptr)
Offset the level set by the specified (world) distance.
Definition LevelSetFilter.h:136
MaskT MaskType
Definition LevelSetFilter.h:44
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
LevelSetFilter(GridType &grid, InterruptT *interrupt=nullptr)
Main constructor from a grid.
Definition LevelSetFilter.h:54
~LevelSetFilter() override
Default destructor.
Definition LevelSetFilter.h:62
LevelSetTracker< GridT, InterruptT > BaseType
Definition LevelSetFilter.h:42
GridT GridType
Definition LevelSetFilter.h:43
LevelSetTracker(GridT &grid, util::NullInterrupter *interrupt=nullptr)
Definition LevelSetTracker.h:260
typename LeafManagerType::LeafRange LeafRange
Definition LevelSetTracker.h:67
const GridType & grid() const
Definition LevelSetTracker.h:187
typename CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition LeafManager.h:96
Definition PointDataGrid.h:170
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:70
int32_t Int32
Definition Types.h:56
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
GridT::ConstAccessor acc
Definition LevelSetFilter.h:217
ValueType operator()(Coord xyz)
Definition LevelSetFilter.h:210
const ValueType frac
Definition LevelSetFilter.h:219
Avg(const GridT &grid, Int32 w)
Definition LevelSetFilter.h:208
const Int32 width
Definition LevelSetFilter.h:218
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218
#define OPENVDB_INSTANTIATE_CLASS
Definition version.h.in:158