OpenVDB 5.1.0

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