39 #ifndef OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
40 #define OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
42 #include <tbb/parallel_reduce.h>
43 #include <tbb/parallel_for.h>
44 #include <boost/bind.hpp>
45 #include <boost/function.hpp>
46 #include <boost/type_traits/is_floating_point.hpp>
47 #include <openvdb/Types.h>
48 #include <openvdb/math/Math.h>
49 #include <openvdb/math/Stencils.h>
50 #include <openvdb/math/Transform.h>
51 #include <openvdb/tree/LeafManager.h>
52 #include <openvdb/util/NullInterrupter.h>
53 #include <openvdb/Grid.h>
64 template<
typename GridT,
65 typename MaskT =
typename GridT::template ValueConverter<float>::Type,
66 typename InterruptT = util::NullInterrupter>
73 typedef typename TreeType::LeafNodeType
LeafType;
79 BOOST_STATIC_ASSERT(boost::is_floating_point<AlphaType>::value);
84 Filter(GridT& grid, InterruptT* interrupt = NULL)
87 , mInterrupter(interrupt)
102 , mInterrupter(other.mInterrupter)
104 , mGrainSize(other.mGrainSize)
105 , mMinMask(other.mMinMask)
106 , mMaxMask(other.mMaxMask)
107 , mInvertMask(other.mInvertMask)
119 AlphaType
minMask()
const {
return mMinMask; }
122 AlphaType
maxMask()
const {
return mMaxMask; }
147 void mean(
int width = 1,
int iterations = 1,
const MaskType* mask = NULL);
156 void gaussian(
int width = 1,
int iterations = 1,
const MaskType* mask = NULL);
164 void median(
int width = 1,
int iterations = 1,
const MaskType* mask = NULL);
169 void offset(ValueType offset,
const MaskType* mask = NULL);
177 if (mTask) mTask(const_cast<Filter*>(
this), range);
182 typedef typename TreeType::LeafNodeType LeafT;
183 typedef typename LeafT::ValueOnIter VoxelIterT;
184 typedef typename LeafT::ValueOnCIter VoxelCIterT;
186 typedef typename RangeType::Iterator LeafIterT;
189 void cook(LeafManagerType& leafs);
191 template<
size_t Axis>
193 Avg(
const GridT* grid,
Int32 w): acc(grid->tree()), width(w), frac(1.f/float(2*w+1)) {}
194 inline ValueType operator()(Coord xyz);
195 typename GridT::ConstAccessor acc;
201 template <
typename AvgT>
202 void doBox(
const RangeType& r,
Int32 w);
203 void doBoxX(
const RangeType& r,
Int32 w) { this->doBox<Avg<0> >(r,w); }
204 void doBoxZ(
const RangeType& r,
Int32 w) { this->doBox<Avg<1> >(r,w); }
205 void doBoxY(
const RangeType& r,
Int32 w) { this->doBox<Avg<2> >(r,w); }
206 void doMedian(
const RangeType&,
int);
207 void doOffset(
const RangeType&, ValueType);
212 typename boost::function<void (Filter*, const RangeType&)> mTask;
213 InterruptT* mInterrupter;
214 const MaskType* mMask;
216 AlphaType mMinMask, mMaxMask;
224 namespace filter_internal {
226 template<
typename T>
static inline void accum(T& sum, T addend) { sum += addend; }
228 inline void accum(
bool& sum,
bool addend) { sum = sum || addend; }
232 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
233 template<
size_t Axis>
234 inline typename GridT::ValueType
235 Filter<GridT, MaskT, InterruptT>::Avg<Axis>::operator()(Coord xyz)
237 ValueType sum = zeroVal<ValueType>();
240 return static_cast<ValueType
>(sum * frac);
247 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
253 if (mInterrupter) mInterrupter->start(
"Applying mean filter");
260 mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
263 mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
266 mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
270 if (mInterrupter) mInterrupter->end();
274 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
280 if (mInterrupter) mInterrupter->start(
"Applying gaussian filter");
286 for (
int i=0; i<iterations; ++i) {
288 mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
291 mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
294 mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
299 if (mInterrupter) mInterrupter->end();
303 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
309 if (mInterrupter) mInterrupter->start(
"Applying median filter");
313 mTask = boost::bind(&Filter::doMedian, _1, _2,
std::max(1, width));
314 for (
int i=0; i<iterations && !this->
wasInterrupted(); ++i) this->cook(leafs);
316 if (mInterrupter) mInterrupter->end();
320 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
326 if (mInterrupter) mInterrupter->start(
"Applying offset");
330 mTask = boost::bind(&Filter::doOffset, _1, _2, value);
333 if (mInterrupter) mInterrupter->end();
342 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
347 tbb::parallel_for(leafs.leafRange(mGrainSize), *
this);
349 (*this)(leafs.leafRange());
351 leafs.swapLeafBuffer(1, mGrainSize==0);
356 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
357 template <
typename AvgT>
359 Filter<GridT, MaskT, InterruptT>::doBox(
const RangeType& range,
Int32 w)
364 typename AlphaMaskT::FloatType a, b;
365 AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
366 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
367 BufferT& buffer = leafIter.buffer(1);
368 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
369 const Coord xyz = iter.getCoord();
370 if (alpha(xyz, a, b)) {
371 buffer.setValue(iter.pos(), ValueType(b*(*iter) + a*avg(xyz)));
376 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
377 BufferT& buffer = leafIter.buffer(1);
378 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
379 buffer.setValue(iter.pos(), avg(iter.getCoord()));
387 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
389 Filter<GridT, MaskT, InterruptT>::doMedian(
const RangeType& range,
int width)
392 typename math::DenseStencil<GridType> stencil(*mGrid, width);
394 typename AlphaMaskT::FloatType a, b;
395 AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
396 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
397 BufferT& buffer = leafIter.buffer(1);
398 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
399 if (alpha(iter.getCoord(), a, b)) {
400 stencil.moveTo(iter);
401 buffer.setValue(iter.pos(), ValueType(b*(*iter) + a*stencil.median()));
406 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
407 BufferT& buffer = leafIter.buffer(1);
408 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
409 stencil.moveTo(iter);
410 buffer.setValue(iter.pos(), stencil.median());
418 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
420 Filter<GridT, MaskT, InterruptT>::doOffset(
const RangeType& range, ValueType offset)
424 typename AlphaMaskT::FloatType a, b;
425 AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
426 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
427 for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
428 if (alpha(iter.getCoord(), a, b)) iter.setValue(ValueType(*iter + a*offset));
432 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
433 for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
434 iter.setValue(*iter + offset);
441 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
446 tbb::task::self().cancel_group_execution();
456 #endif // OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
Definition: LeafManager.h:126
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:109
int32_t Int32
Definition: Types.h:61
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
#define OPENVDB_VERSION_NAME
Definition: version.h:43
Definition: Exceptions.h:39
OPENVDB_API Hermite min(const Hermite &, const Hermite &)
min and max operations done directly on the compressed data.
Axis
Definition: Math.h:822
Definition: Exceptions.h:88
OPENVDB_API Hermite max(const Hermite &, const Hermite &)
min and max operations done directly on the compressed data.
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition: LeafManager.h:120