OpenVDB  3.1.0
LevelSetFilter.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2015 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 //
41 
42 #ifndef OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED
43 #define OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED
44 
45 #include <assert.h>
46 #include <boost/type_traits/is_floating_point.hpp>
47 #include "LevelSetTracker.h"
48 #include "Interpolation.h"
49 
50 namespace openvdb {
52 namespace OPENVDB_VERSION_NAME {
53 namespace tools {
54 
61 template<typename GridT,
62  typename MaskT = typename GridT::template ValueConverter<float>::Type,
63  typename InterruptT = util::NullInterrupter>
64 class LevelSetFilter : public LevelSetTracker<GridT, InterruptT>
65 {
66 public:
68  typedef GridT GridType;
69  typedef MaskT MaskType;
70  typedef typename GridType::TreeType TreeType;
71  typedef typename TreeType::ValueType ValueType;
72  typedef typename MaskType::ValueType AlphaType;
73  BOOST_STATIC_ASSERT(boost::is_floating_point<AlphaType>::value);
74 
78  LevelSetFilter(GridType& grid, InterruptT* interrupt = NULL)
79  : BaseType(grid, interrupt)
80  , mMinMask(0)
81  , mMaxMask(1)
82  , mInvertMask(false)
83  {
84  }
86  virtual ~LevelSetFilter() {}
87 
90  AlphaType minMask() const { return mMinMask; }
93  AlphaType maxMask() const { return mMaxMask; }
101  void setMaskRange(AlphaType min, AlphaType max)
102  {
103  if (!(min < max)) OPENVDB_THROW(ValueError, "Invalid mask range (expects min < max)");
104  mMinMask = min;
105  mMaxMask = max;
106  }
107 
110  bool isMaskInverted() const { return mInvertMask; }
113  void invertMask(bool invert=true) { mInvertMask = invert; }
114 
117  void meanCurvature(const MaskType* mask = NULL)
118  {
119  Filter f(this, mask); f.meanCurvature();
120  }
121 
124  void laplacian(const MaskType* mask = NULL)
125  {
126  Filter f(this, mask); f.laplacian();
127  }
128 
135  void gaussian(int width = 1, const MaskType* mask = NULL)
136  {
137  Filter f(this, mask); f.gaussian(width);
138  }
139 
143  void offset(ValueType offset, const MaskType* mask = NULL)
144  {
145  Filter f(this, mask); f.offset(offset);
146  }
147 
154  void median(int width = 1, const MaskType* mask = NULL)
155  {
156  Filter f(this, mask); f.median(width);
157  }
158 
164  void mean(int width = 1, const MaskType* mask = NULL)
165  {
166  Filter f(this, mask); f.mean(width);
167  }
168 
169 private:
170  // disallow copy construction and copy by assignment!
171  LevelSetFilter(const LevelSetFilter&);// not implemented
172  LevelSetFilter& operator=(const LevelSetFilter&);// not implemented
173 
174  // Private struct that implements all the filtering.
175  struct Filter
176  {
177  typedef typename TreeType::LeafNodeType LeafT;
178  typedef typename LeafT::ValueOnIter VoxelIterT;
179  typedef typename LeafT::ValueOnCIter VoxelCIterT;
180  typedef typename tree::LeafManager<TreeType>::BufferType BufferT;
181  typedef typename tree::LeafManager<TreeType>::LeafRange LeafRange;
182  typedef typename LeafRange::Iterator LeafIterT;
183  typedef tools::AlphaMask<GridT, MaskT> AlphaMaskT;
184 
185  Filter(LevelSetFilter* parent, const MaskType* mask) : mParent(parent), mMask(mask) {}
186  virtual ~Filter() {}
187 
188  void box(int width);
189  void median(int width);
190  void mean(int width);
191  void gaussian(int width);
192  void laplacian();
193  void meanCurvature();
194  void offset(ValueType value);
195  void operator()(const LeafRange& r) const
196  {
197  if (mTask) mTask(const_cast<Filter*>(this), r);
198  else OPENVDB_THROW(ValueError, "task is undefined - don\'t call this method directly");
199  }
200  void cook(bool swap)
201  {
202  const int n = mParent->getGrainSize();
203  if (n>0) {
204  tbb::parallel_for(mParent->leafs().leafRange(n), *this);
205  } else {
206  (*this)(mParent->leafs().leafRange());
207  }
208  if (swap) mParent->leafs().swapLeafBuffer(1, n==0);
209  }
210 
211  template <size_t Axis>
212  struct Avg {
213  Avg(const GridT& grid, Int32 w) :
214  acc(grid.tree()), width(w), frac(1/ValueType(2*w+1)) {}
215  inline ValueType operator()(Coord xyz)
216  {
217  ValueType sum = zeroVal<ValueType>();
218  Int32& i = xyz[Axis], j = i + width;
219  for (i -= width; i <= j; ++i) sum += acc.getValue(xyz);
220  return sum*frac;
221  }
222  typename GridT::ConstAccessor acc;
223  const Int32 width;
224  const ValueType frac;
225  };
226 
227  template <typename AvgT>
228  void box( const LeafRange& r, Int32 w);
229 
230  void boxX(const LeafRange& r, Int32 w) { this->box<Avg<0> >(r,w); }
231  void boxZ(const LeafRange& r, Int32 w) { this->box<Avg<1> >(r,w); }
232  void boxY(const LeafRange& r, Int32 w) { this->box<Avg<2> >(r,w); }
233 
234  void median(const LeafRange&, int);
235  void meanCurvature(const LeafRange&);
236  void laplacian(const LeafRange&);
237  void offset(const LeafRange&, ValueType);
238 
239  LevelSetFilter* mParent;
240  const MaskType* mMask;
241  typename boost::function<void (Filter*, const LeafRange&)> mTask;
242  }; // end of private Filter struct
243 
244  AlphaType mMinMask, mMaxMask;
245  bool mInvertMask;
246 
247 }; // end of LevelSetFilter class
248 
249 
251 
252 template<typename GridT, typename MaskT, typename InterruptT>
253 inline void
254 LevelSetFilter<GridT, MaskT, InterruptT>::
255 Filter::median(int width)
256 {
257  mParent->startInterrupter("Median-value flow of level set");
258 
259  mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
260 
261  mTask = boost::bind(&Filter::median, _1, _2, std::max(1, width));
262  this->cook(true);
263 
264  mParent->track();
265 
266  mParent->endInterrupter();
267 }
268 
269 template<typename GridT, typename MaskT, typename InterruptT>
270 inline void
271 LevelSetFilter<GridT, MaskT, InterruptT>::
272 Filter::mean(int width)
273 {
274  mParent->startInterrupter("Mean-value flow of level set");
275 
276  this->box(width);
277 
278  mParent->endInterrupter();
279 }
280 
281 template<typename GridT, typename MaskT, typename InterruptT>
282 inline void
283 LevelSetFilter<GridT, MaskT, InterruptT>::
284 Filter::gaussian(int width)
285 {
286  mParent->startInterrupter("Gaussian flow of level set");
287 
288  for (int n=0; n<4; ++n) this->box(width);
289 
290  mParent->endInterrupter();
291 }
292 
293 template<typename GridT, typename MaskT, typename InterruptT>
294 inline void
295 LevelSetFilter<GridT, MaskT, InterruptT>::
296 Filter::box(int width)
297 {
298  mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
299 
300  width = std::max(1, width);
301 
302  mTask = boost::bind(&Filter::boxX, _1, _2, width);
303  this->cook(true);
304 
305  mTask = boost::bind(&Filter::boxY, _1, _2, width);
306  this->cook(true);
307 
308  mTask = boost::bind(&Filter::boxZ, _1, _2, width);
309  this->cook(true);
310 
311  mParent->track();
312 }
313 
314 template<typename GridT, typename MaskT, typename InterruptT>
315 inline void
318 {
319  mParent->startInterrupter("Mean-curvature flow of level set");
320 
321  mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
322 
323  mTask = boost::bind(&Filter::meanCurvature, _1, _2);
324  this->cook(true);
325 
326  mParent->track();
327 
328  mParent->endInterrupter();
329 }
330 
331 template<typename GridT, typename MaskT, typename InterruptT>
332 inline void
335 {
336  mParent->startInterrupter("Laplacian flow of level set");
337 
338  mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
339 
340  mTask = boost::bind(&Filter::laplacian, _1, _2);
341  this->cook(true);
342 
343  mParent->track();
344 
345  mParent->endInterrupter();
346 }
347 
348 template<typename GridT, typename MaskT, typename InterruptT>
349 inline void
350 LevelSetFilter<GridT, MaskT, InterruptT>::
351 Filter::offset(ValueType value)
352 {
353  mParent->startInterrupter("Offsetting level set");
354 
355  mParent->leafs().removeAuxBuffers();// no auxiliary buffers required
356 
357  const ValueType CFL = ValueType(0.5) * mParent->voxelSize(), offset = openvdb::math::Abs(value);
358  ValueType dist = 0.0;
359  while (offset-dist > ValueType(0.001)*CFL && mParent->checkInterrupter()) {
360  const ValueType delta = openvdb::math::Min(offset-dist, CFL);
361  dist += delta;
362 
363  mTask = boost::bind(&Filter::offset, _1, _2, copysign(delta, value));
364  this->cook(false);
365 
366  mParent->track();
367  }
368 
369  mParent->endInterrupter();
370 }
371 
372 
374 
376 template<typename GridT, typename MaskT, typename InterruptT>
377 inline void
379 Filter::meanCurvature(const LeafRange& range)
380 {
381  mParent->checkInterrupter();
382  //const float CFL = 0.9f, dt = CFL * mDx * mDx / 6.0f;
383  const ValueType dx = mParent->voxelSize(), dt = math::Pow2(dx) / ValueType(3.0);
384  math::CurvatureStencil<GridType> stencil(mParent->grid(), dx);
385  if (mMask) {
386  typename AlphaMaskT::FloatType a, b;
387  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
388  mParent->maxMask(), mParent->isMaskInverted());
389  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
390  ValueType* buffer = leafIter.buffer(1).data();
391  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
392  if (alpha(iter.getCoord(), a, b)) {
393  stencil.moveTo(iter);
394  const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.meanCurvatureNormGrad();
395  buffer[iter.pos()] = b * phi0 + a * phi1;
396  }
397  }
398  }
399  } else {
400  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
401  ValueType* buffer = leafIter.buffer(1).data();
402  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
403  stencil.moveTo(iter);
404  buffer[iter.pos()] = *iter + dt*stencil.meanCurvatureNormGrad();
405  }
406  }
407  }
408 }
409 
417 template<typename GridT, typename MaskT, typename InterruptT>
418 inline void
420 Filter::laplacian(const LeafRange& range)
421 {
422  mParent->checkInterrupter();
423  //const float CFL = 0.9f, half_dt = CFL * mDx * mDx / 12.0f;
424  const ValueType dx = mParent->voxelSize(), dt = math::Pow2(dx) / ValueType(6.0);
425  math::GradStencil<GridType> stencil(mParent->grid(), dx);
426  if (mMask) {
427  typename AlphaMaskT::FloatType a, b;
428  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
429  mParent->maxMask(), mParent->isMaskInverted());
430  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
431  ValueType* buffer = leafIter.buffer(1).data();
432  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
433  if (alpha(iter.getCoord(), a, b)) {
434  stencil.moveTo(iter);
435  const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.laplacian();
436  buffer[iter.pos()] = b * phi0 + a * phi1;
437  }
438  }
439  }
440  } else {
441  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
442  ValueType* buffer = leafIter.buffer(1).data();
443  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
444  stencil.moveTo(iter);
445  buffer[iter.pos()] = *iter + dt*stencil.laplacian();
446  }
447  }
448  }
449 }
450 
452 template<typename GridT, typename MaskT, typename InterruptT>
453 inline void
454 LevelSetFilter<GridT, MaskT, InterruptT>::
455 Filter::offset(const LeafRange& range, ValueType offset)
456 {
457  mParent->checkInterrupter();
458  if (mMask) {
459  typename AlphaMaskT::FloatType a, b;
460  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
461  mParent->maxMask(), mParent->isMaskInverted());
462  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
463  for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
464  if (alpha(iter.getCoord(), a, b)) iter.setValue(*iter + a*offset);
465  }
466  }
467  } else {
468  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
469  for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
470  iter.setValue(*iter + offset);
471  }
472  }
473  }
474 }
475 
477 template<typename GridT, typename MaskT, typename InterruptT>
478 inline void
479 LevelSetFilter<GridT, MaskT, InterruptT>::
480 Filter::median(const LeafRange& range, int width)
481 {
482  mParent->checkInterrupter();
483  typename math::DenseStencil<GridType> stencil(mParent->grid(), width);//creates local cache!
484  if (mMask) {
485  typename AlphaMaskT::FloatType a, b;
486  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
487  mParent->maxMask(), mParent->isMaskInverted());
488  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
489  ValueType* buffer = leafIter.buffer(1).data();
490  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
491  if (alpha(iter.getCoord(), a, b)) {
492  stencil.moveTo(iter);
493  buffer[iter.pos()] = b * (*iter) + a * stencil.median();
494  }
495  }
496  }
497  } else {
498  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
499  ValueType* buffer = leafIter.buffer(1).data();
500  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
501  stencil.moveTo(iter);
502  buffer[iter.pos()] = stencil.median();
503  }
504  }
505  }
506 }
507 
509 template<typename GridT, typename MaskT, typename InterruptT>
510 template <typename AvgT>
511 inline void
512 LevelSetFilter<GridT, MaskT, InterruptT>::
513 Filter::box(const LeafRange& range, Int32 w)
514 {
515  mParent->checkInterrupter();
516  AvgT avg(mParent->grid(), w);
517  if (mMask) {
518  typename AlphaMaskT::FloatType a, b;
519  AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
520  mParent->maxMask(), mParent->isMaskInverted());
521  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
522  ValueType* buffer = leafIter.buffer(1).data();
523  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
524  const Coord xyz = iter.getCoord();
525  if (alpha(xyz, a, b)) buffer[iter.pos()] = b * (*iter)+ a * avg(xyz);
526  }
527  }
528  } else {
529  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
530  ValueType* buffer = leafIter.buffer(1).data();
531  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
532  buffer[iter.pos()] = avg(iter.getCoord());
533  }
534  }
535  }
536 }
537 
538 } // namespace tools
539 } // namespace OPENVDB_VERSION_NAME
540 } // namespace openvdb
541 
542 #endif // OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED
543 
544 // Copyright (c) 2012-2015 DreamWorks Animation LLC
545 // All rights reserved. This software is distributed under the
546 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
MaskT MaskType
Definition: LevelSetFilter.h:69
Avg(const GridT &grid, Int32 w)
Definition: LevelSetFilter.h:213
LevelSetFilter(GridType &grid, InterruptT *interrupt=NULL)
Main constructor from a grid.
Definition: LevelSetFilter.h:78
Performs multi-threaded interface tracking of narrow band level sets. This is the building-block for ...
void meanCurvature(const MaskType *mask=NULL)
One iteration of mean-curvature flow of the level set.
Definition: LevelSetFilter.h:117
void offset(ValueType offset, const MaskType *mask=NULL)
Offset the level set by the specified (world) distance.
Definition: LevelSetFilter.h:143
int32_t Abs(int32_t i)
Return the absolute value of the given quantity.
Definition: Math.h:293
Definition: Exceptions.h:88
Performs multi-threaded interface tracking of narrow band level sets.
Definition: LevelSetTracker.h:67
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
GridType::Ptr meanCurvature(const GridType &grid, bool threaded, InterruptT *interrupt)
Compute the mean curvature of the given grid.
Definition: GridOperators.h:1033
Volume filtering (e.g., diffusion) with optional alpha masking.
Definition: Filter.h:66
AlphaType minMask() const
Return the minimum value of the mask to be used for the derivation of a smooth alpha value...
Definition: LevelSetFilter.h:90
GridType::TreeType TreeType
Definition: LevelSetFilter.h:70
TreeType::ValueType ValueType
Definition: LevelSetFilter.h:71
GridType::Ptr laplacian(const GridType &grid, bool threaded, InterruptT *interrupt)
Compute the Laplacian of the given scalar grid.
Definition: GridOperators.h:1016
void mean(int width=1, const MaskType *mask=NULL)
One iteration of mean-value flow of the level set.
Definition: LevelSetFilter.h:164
const ValueType frac
Definition: LevelSetFilter.h:224
const boost::disable_if_c< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:105
AlphaType maxMask() const
Return the maximum value of the mask to be used for the derivation of a smooth alpha value...
Definition: LevelSetFilter.h:93
GridT GridType
Definition: LevelSetFilter.h:68
#define OPENVDB_VERSION_NAME
Definition: version.h:43
MaskType::ValueType AlphaType
Definition: LevelSetFilter.h:72
LevelSetTracker< GridT, InterruptT > BaseType
Definition: LevelSetFilter.h:67
void setMaskRange(AlphaType min, AlphaType max)
Define the range for the (optional) scalar mask.
Definition: LevelSetFilter.h:101
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:110
Definition: Exceptions.h:39
CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition: LeafManager.h:125
ValueType operator()(Coord xyz)
Definition: LevelSetFilter.h:215
Filtering (e.g. diffusion) of narrow-band level sets. An optional scalar field can be used to produce...
Definition: LevelSetFilter.h:64
Axis
Definition: Math.h:838
Type Pow2(Type x)
Return .
Definition: Math.h:514
void laplacian(const MaskType *mask=NULL)
One iteration of Laplacian flow of the level set.
Definition: LevelSetFilter.h:124
virtual ~LevelSetFilter()
Default destructor.
Definition: LevelSetFilter.h:86
GridT::ConstAccessor acc
Definition: LevelSetFilter.h:222
const boost::disable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:109
int32_t Int32
Definition: Types.h:60
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:113
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
Definition: Interpolation.h:570
const Int32 width
Definition: LevelSetFilter.h:223
void median(int width=1, const MaskType *mask=NULL)
One iteration of median-value flow of the level set.
Definition: LevelSetFilter.h:154
const Type & Min(const Type &a, const Type &b)
Return the minimum of two values.
Definition: Math.h:622
void gaussian(int width=1, const MaskType *mask=NULL)
One iteration of a fast separable Gaussian filter.
Definition: LevelSetFilter.h:135