OpenVDB: Filter.h Source File

OpenVDB 3.1.0

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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>
50 #include <openvdb/tree/LeafManager.h>
51 #include <openvdb/util/NullInterrupter.h>
52 #include <openvdb/Grid.h>
53 #include "Interpolation.h"
54
55 namespace openvdb {
56 OPENVDB_USE_VERSION_NAMESPACE
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;
75 typedef typename tree::LeafManager<TreeType> LeafManagerType;
76 typedef typename LeafManagerType::LeafRange RangeType;
77 typedef typename LeafManagerType::BufferType BufferType;
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
321 Filter<GridT, MaskT, InterruptT>::offset(ValueType value, const MaskType* mask)
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
442 Filter<GridT, MaskT, InterruptT>::wasInterrupted()
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/ )
openvdb::v3_1_0::util::wasInterrupted
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
openvdb::v3_1_0::tools::Filter::minMask
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
openvdb::v3_1_0::tools::Filter::Filter
Filter(const Filter &other)
Shallow copy constructor called by tbb::parallel_for() threads during filtering.
Definition: Filter.h:98
Types.h
openvdb::v3_1_0::tools::Filter::isMaskInverted
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
NullInterrupter.h
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
openvdb::v3_1_0::tools::Filter::Filter
Filter(GridT &grid, InterruptT *interrupt=NULL)
Definition: Filter.h:83
openvdb::v3_1_0::ValueError
Definition: Exceptions.h:88
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
openvdb::v3_1_0::tree::LeafManager::leafRange
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:350
openvdb::v3_1_0::tools::Filter::operator()
void operator()(const RangeType &range) const
Used internally by tbb::parallel_for()
Definition: Filter.h:174
openvdb::v3_1_0::tools::Filter::LeafType
TreeType::LeafNodeType LeafType
Definition: Filter.h:72
openvdb::v3_1_0::tree::LeafManager
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:114
openvdb::v3_1_0::tools::Filter::getGrainSize
int getGrainSize() const
Definition: Filter.h:111
openvdb::v3_1_0::tools::Filter
Volume filtering (e.g., diffusion) with optional alpha masking.
Definition: Filter.h:66
openvdb::v3_1_0::tools::filter_internal::accum
void accum(bool &sum, bool addend)
Definition: Filter.h:227
Transform.h
openvdb::v3_1_0::math::DenseStencil::moveTo
void moveTo(const Coord &ijk)
Initialize the stencil buffer with the values of voxel (x, y, z) and its neighbors.
Definition: Stencils.h:1636
openvdb::v3_1_0::tools::Filter::RangeType
LeafManagerType::LeafRange RangeType
Definition: Filter.h:76
openvdb::v3_1_0::tools::composite::min
const boost::disable_if_c< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:105
openvdb::v3_1_0::tree::LeafManager::swapLeafBuffer
bool swapLeafBuffer(size_t bufferIdx, bool serial=false)
Swap each leaf node&#39;s buffer with the nth corresponding auxiliary buffer, where n = bufferIdx...
Definition: LeafManager.h:364
openvdb::v3_1_0::tools::Filter::setGrainSize
void setGrainSize(int grainsize)
Set the grain-size used for multi-threading.
Definition: Filter.h:114
openvdb::v3_1_0::tree::LeafManager::LeafRange::begin
Iterator begin() const
Definition: LeafManager.h:181
openvdb::v3_1_0::tools::Filter::LeafManagerType
tree::LeafManager< TreeType > LeafManagerType
Definition: Filter.h:75
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
Definition: version.h:43
openvdb::v3_1_0::tools::Filter::BufferType
LeafManagerType::BufferType BufferType
Definition: Filter.h:77
openvdb::v3_1_0::tools::Filter::GridType
GridT GridType
Definition: Filter.h:69
openvdb::v3_1_0::tools::Filter::ValueType
GridType::ValueType ValueType
Definition: Filter.h:73
openvdb
Definition: Exceptions.h:39
openvdb::v3_1_0::tree::LeafManager::BufferType
CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition: LeafManager.h:125
openvdb::v3_1_0::tools::Filter::AlphaType
MaskType::ValueType AlphaType
Definition: Filter.h:74
openvdb::v3_1_0::math::Axis
Axis
Definition: Math.h:838
openvdb::v3_1_0::tools::Filter::setMaskRange
void setMaskRange(AlphaType min, AlphaType max)
Define the range for the (optional) scalar mask.
Definition: Filter.h:128
openvdb::v3_1_0::tools::Filter::TreeType
GridType::TreeType TreeType
Definition: Filter.h:71
Interpolation.h
openvdb::v3_1_0::tools::composite::max
const boost::disable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:109
openvdb::v3_1_0::tools::Filter::MaskType
MaskT MaskType
Definition: Filter.h:70
openvdb::v3_1_0::tools::Filter::invertMask
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
openvdb::v3_1_0::tools::AlphaMask::FloatType
FloatT FloatType
Definition: Interpolation.h:577
openvdb::v3_1_0::Int32
int32_t Int32
Definition: Types.h:60
Grid.h
openvdb::v3_1_0::math::BaseStencil< DenseStencil< GridT, IsSafe >, GridT, IsSafe >::median
ValueType median() const
Return the median value of the current stencil.
Definition: Stencils.h:146
openvdb::v3_1_0::tree::LeafManager::LeafRange::Iterator
Definition: LeafManager.h:134
Stencils.h
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
openvdb::v3_1_0::tools::Filter::maxMask
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
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
openvdb::v3_1_0::tools::AlphaMask
Definition: Interpolation.h:570
LeafManager.h
A LeafManager manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional au...
openvdb::v3_1_0::math::DenseStencil
Dense stencil of a given width.
Definition: Stencils.h:1616
openvdb::v3_1_0::tree::LeafManager::LeafRange
Definition: LeafManager.h:131