OpenVDB  3.1.0
Filter.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 //
38 
39 #ifndef OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
40 #define OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
41 
42 #include <tbb/parallel_for.h>
43 #include <boost/bind.hpp>
44 #include <boost/function.hpp>
45 #include <boost/type_traits/is_floating_point.hpp>
46 #include <openvdb/Types.h>
47 #include <openvdb/math/Math.h>
48 #include <openvdb/math/Stencils.h>
49 #include <openvdb/math/Transform.h>
52 #include <openvdb/Grid.h>
53 #include "Interpolation.h"
54 
55 namespace openvdb {
57 namespace OPENVDB_VERSION_NAME {
58 namespace tools {
59 
63 template<typename GridT,
64  typename MaskT = typename GridT::template ValueConverter<float>::Type,
65  typename InterruptT = util::NullInterrupter>
66 class Filter
67 {
68 public:
69  typedef GridT GridType;
70  typedef MaskT MaskType;
71  typedef typename GridType::TreeType TreeType;
72  typedef typename TreeType::LeafNodeType LeafType;
73  typedef typename GridType::ValueType ValueType;
74  typedef typename MaskType::ValueType AlphaType;
78  BOOST_STATIC_ASSERT(boost::is_floating_point<AlphaType>::value);
79 
83  Filter(GridT& grid, InterruptT* interrupt = NULL)
84  : mGrid(&grid)
85  , mTask(0)
86  , mInterrupter(interrupt)
87  , mMask(NULL)
88  , mGrainSize(1)
89  , mMinMask(0)
90  , mMaxMask(1)
91  , mInvertMask(false)
92  {
93  }
94 
98  Filter(const Filter& other)
99  : mGrid(other.mGrid)
100  , mTask(other.mTask)
101  , mInterrupter(other.mInterrupter)
102  , mMask(other.mMask)
103  , mGrainSize(other.mGrainSize)
104  , mMinMask(other.mMinMask)
105  , mMaxMask(other.mMaxMask)
106  , mInvertMask(other.mInvertMask)
107  {
108  }
109 
111  int getGrainSize() const { return mGrainSize; }
114  void setGrainSize(int grainsize) { mGrainSize = grainsize; }
115 
118  AlphaType minMask() const { return mMinMask; }
121  AlphaType maxMask() const { return mMaxMask; }
128  void setMaskRange(AlphaType min, AlphaType max)
129  {
130  if (!(min < max)) OPENVDB_THROW(ValueError, "Invalid mask range (expects min < max)");
131  mMinMask = min;
132  mMaxMask = max;
133  }
134 
137  bool isMaskInverted() const { return mInvertMask; }
140  void invertMask(bool invert=true) { mInvertMask = invert; }
141 
146  void mean(int width = 1, int iterations = 1, const MaskType* mask = NULL);
147 
155  void gaussian(int width = 1, int iterations = 1, const MaskType* mask = NULL);
156 
163  void median(int width = 1, int iterations = 1, const MaskType* mask = NULL);
164 
168  void offset(ValueType offset, const MaskType* mask = NULL);
169 
174  void operator()(const RangeType& range) const
175  {
176  if (mTask) mTask(const_cast<Filter*>(this), range);
177  else OPENVDB_THROW(ValueError, "task is undefined - call median(), mean(), etc.");
178  }
179 
180 private:
181  typedef typename TreeType::LeafNodeType LeafT;
182  typedef typename LeafT::ValueOnIter VoxelIterT;
183  typedef typename LeafT::ValueOnCIter VoxelCIterT;
184  typedef typename tree::LeafManager<TreeType>::BufferType BufferT;
185  typedef typename RangeType::Iterator LeafIterT;
186  typedef tools::AlphaMask<GridT, MaskT> AlphaMaskT;
187 
188  void cook(LeafManagerType& leafs);
189 
190  template<size_t Axis>
191  struct Avg {
192  Avg(const GridT* grid, Int32 w): acc(grid->tree()), width(w), frac(1.f/float(2*w+1)) {}
193  inline ValueType operator()(Coord xyz);
194  typename GridT::ConstAccessor acc;
195  const Int32 width;
196  const float frac;
197  };
198 
199  // Private filter methods called by tbb::parallel_for threads
200  template <typename AvgT>
201  void doBox( const RangeType& r, Int32 w);
202  void doBoxX(const RangeType& r, Int32 w) { this->doBox<Avg<0> >(r,w); }
203  void doBoxZ(const RangeType& r, Int32 w) { this->doBox<Avg<1> >(r,w); }
204  void doBoxY(const RangeType& r, Int32 w) { this->doBox<Avg<2> >(r,w); }
205  void doMedian(const RangeType&, int);
206  void doOffset(const RangeType&, ValueType);
208  bool wasInterrupted();
209 
210  GridType* mGrid;
211  typename boost::function<void (Filter*, const RangeType&)> mTask;
212  InterruptT* mInterrupter;
213  const MaskType* mMask;
214  int mGrainSize;
215  AlphaType mMinMask, mMaxMask;
216  bool mInvertMask;
217 }; // end of Filter class
218 
219 
221 
222 
223 namespace filter_internal {
224 // Helper function for Filter::Avg::operator()
225 template<typename T> static inline void accum(T& sum, T addend) { sum += addend; }
226 // Overload for bool ValueType
227 inline void accum(bool& sum, bool addend) { sum = sum || addend; }
228 }
229 
230 
231 template<typename GridT, typename MaskT, typename InterruptT>
232 template<size_t Axis>
233 inline typename GridT::ValueType
234 Filter<GridT, MaskT, InterruptT>::Avg<Axis>::operator()(Coord xyz)
235 {
236  ValueType sum = zeroVal<ValueType>();
237  Int32 &i = xyz[Axis], j = i + width;
238  for (i -= width; i <= j; ++i) filter_internal::accum(sum, acc.getValue(xyz));
239  return static_cast<ValueType>(sum * frac);
240 }
241 
242 
244 
245 
246 template<typename GridT, typename MaskT, typename InterruptT>
247 inline void
248 Filter<GridT, MaskT, InterruptT>::mean(int width, int iterations, const MaskType* mask)
249 {
250  mMask = mask;
251 
252  if (mInterrupter) mInterrupter->start("Applying mean filter");
253 
254  const int w = std::max(1, width);
255 
256  LeafManagerType leafs(mGrid->tree(), 1, mGrainSize==0);
257 
258  for (int i=0; i<iterations && !this->wasInterrupted(); ++i) {
259  mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
260  this->cook(leafs);
261 
262  mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
263  this->cook(leafs);
264 
265  mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
266  this->cook(leafs);
267  }
268 
269  if (mInterrupter) mInterrupter->end();
270 }
271 
272 
273 template<typename GridT, typename MaskT, typename InterruptT>
274 inline void
275 Filter<GridT, MaskT, InterruptT>::gaussian(int width, int iterations, const MaskType* mask)
276 {
277  mMask = mask;
278 
279  if (mInterrupter) mInterrupter->start("Applying Gaussian filter");
280 
281  const int w = std::max(1, width);
282 
283  LeafManagerType leafs(mGrid->tree(), 1, mGrainSize==0);
284 
285  for (int i=0; i<iterations; ++i) {
286  for (int n=0; n<4 && !this->wasInterrupted(); ++n) {
287  mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
288  this->cook(leafs);
289 
290  mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
291  this->cook(leafs);
292 
293  mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
294  this->cook(leafs);
295  }
296  }
297 
298  if (mInterrupter) mInterrupter->end();
299 }
300 
301 
302 template<typename GridT, typename MaskT, typename InterruptT>
303 inline void
304 Filter<GridT, MaskT, InterruptT>::median(int width, int iterations, const MaskType* mask)
305 {
306  mMask = mask;
307 
308  if (mInterrupter) mInterrupter->start("Applying median filter");
309 
310  LeafManagerType leafs(mGrid->tree(), 1, mGrainSize==0);
311 
312  mTask = boost::bind(&Filter::doMedian, _1, _2, std::max(1, width));
313  for (int i=0; i<iterations && !this->wasInterrupted(); ++i) this->cook(leafs);
314 
315  if (mInterrupter) mInterrupter->end();
316 }
317 
318 
319 template<typename GridT, typename MaskT, typename InterruptT>
320 inline void
322 {
323  mMask = mask;
324 
325  if (mInterrupter) mInterrupter->start("Applying offset");
326 
327  LeafManagerType leafs(mGrid->tree(), 0, mGrainSize==0);
328 
329  mTask = boost::bind(&Filter::doOffset, _1, _2, value);
330  this->cook(leafs);
331 
332  if (mInterrupter) mInterrupter->end();
333 }
334 
335 
337 
338 
341 template<typename GridT, typename MaskT, typename InterruptT>
342 inline void
343 Filter<GridT, MaskT, InterruptT>::cook(LeafManagerType& leafs)
344 {
345  if (mGrainSize>0) {
346  tbb::parallel_for(leafs.leafRange(mGrainSize), *this);
347  } else {
348  (*this)(leafs.leafRange());
349  }
350  leafs.swapLeafBuffer(1, mGrainSize==0);
351 }
352 
353 
355 template<typename GridT, typename MaskT, typename InterruptT>
356 template <typename AvgT>
357 inline void
358 Filter<GridT, MaskT, InterruptT>::doBox(const RangeType& range, Int32 w)
359 {
360  this->wasInterrupted();
361  AvgT avg(mGrid, w);
362  if (mMask) {
363  typename AlphaMaskT::FloatType a, b;
364  AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
365  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
366  BufferT& buffer = leafIter.buffer(1);
367  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
368  const Coord xyz = iter.getCoord();
369  if (alpha(xyz, a, b)) {
370  buffer.setValue(iter.pos(), ValueType(b*(*iter) + a*avg(xyz)));
371  }
372  }
373  }
374  } else {
375  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
376  BufferT& buffer = leafIter.buffer(1);
377  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
378  buffer.setValue(iter.pos(), avg(iter.getCoord()));
379  }
380  }
381  }
382 }
383 
384 
386 template<typename GridT, typename MaskT, typename InterruptT>
387 inline void
388 Filter<GridT, MaskT, InterruptT>::doMedian(const RangeType& range, int width)
389 {
390  this->wasInterrupted();
391  typename math::DenseStencil<GridType> stencil(*mGrid, width);//creates local cache!
392  if (mMask) {
393  typename AlphaMaskT::FloatType a, b;
394  AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
395  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
396  BufferT& buffer = leafIter.buffer(1);
397  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
398  if (alpha(iter.getCoord(), a, b)) {
399  stencil.moveTo(iter);
400  buffer.setValue(iter.pos(), ValueType(b*(*iter) + a*stencil.median()));
401  }
402  }
403  }
404  } else {
405  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
406  BufferT& buffer = leafIter.buffer(1);
407  for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
408  stencil.moveTo(iter);
409  buffer.setValue(iter.pos(), stencil.median());
410  }
411  }
412  }
413 }
414 
415 
417 template<typename GridT, typename MaskT, typename InterruptT>
418 inline void
419 Filter<GridT, MaskT, InterruptT>::doOffset(const RangeType& range, ValueType offset)
420 {
421  this->wasInterrupted();
422  if (mMask) {
423  typename AlphaMaskT::FloatType a, b;
424  AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
425  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
426  for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
427  if (alpha(iter.getCoord(), a, b)) iter.setValue(ValueType(*iter + a*offset));
428  }
429  }
430  } else {
431  for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
432  for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
433  iter.setValue(*iter + offset);
434  }
435  }
436  }
437 }
438 
439 
440 template<typename GridT, typename MaskT, typename InterruptT>
441 inline bool
443 {
444  if (util::wasInterrupted(mInterrupter)) {
445  tbb::task::self().cancel_group_execution();
446  return true;
447  }
448  return false;
449 }
450 
451 } // namespace tools
452 } // namespace OPENVDB_VERSION_NAME
453 } // namespace openvdb
454 
455 #endif // OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
456 
457 // Copyright (c) 2012-2015 DreamWorks Animation LLC
458 // All rights reserved. This software is distributed under the
459 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
AlphaType minMask() const
Return the minimum value of the mask to be used for the derivation of a smooth alpha value...
Definition: Filter.h:118
Filter(const Filter &other)
Shallow copy constructor called by tbb::parallel_for() threads during filtering.
Definition: Filter.h:98
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: Filter.h:137
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Filter(GridT &grid, InterruptT *interrupt=NULL)
Definition: Filter.h:83
Definition: Exceptions.h:88
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
void operator()(const RangeType &range) const
Used internally by tbb::parallel_for()
Definition: Filter.h:174
TreeType::LeafNodeType LeafType
Definition: Filter.h:72
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:114
int getGrainSize() const
Definition: Filter.h:111
Volume filtering (e.g., diffusion) with optional alpha masking.
Definition: Filter.h:66
void accum(bool &sum, bool addend)
Definition: Filter.h:227
LeafManagerType::LeafRange RangeType
Definition: Filter.h:76
const boost::disable_if_c< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:105
void setGrainSize(int grainsize)
Set the grain-size used for multi-threading.
Definition: Filter.h:114
tree::LeafManager< TreeType > LeafManagerType
Definition: Filter.h:75
#define OPENVDB_VERSION_NAME
Definition: version.h:43
LeafManagerType::BufferType BufferType
Definition: Filter.h:77
GridT GridType
Definition: Filter.h:69
GridType::ValueType ValueType
Definition: Filter.h:73
Definition: Exceptions.h:39
CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition: LeafManager.h:125
MaskType::ValueType AlphaType
Definition: Filter.h:74
Axis
Definition: Math.h:838
void setMaskRange(AlphaType min, AlphaType max)
Define the range for the (optional) scalar mask.
Definition: Filter.h:128
GridType::TreeType TreeType
Definition: Filter.h:71
const boost::disable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:109
MaskT MaskType
Definition: Filter.h:70
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: Filter.h:140
int32_t Int32
Definition: Types.h:60
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
AlphaType maxMask() const
Return the maximum value of the mask to be used for the derivation of a smooth alpha value...
Definition: Filter.h:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
Definition: Interpolation.h:570
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...