12 #ifndef OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED 13 #define OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED 15 #include <tbb/parallel_for.h> 26 #include <type_traits> 37 template<
typename GridT,
38 typename MaskT =
typename GridT::template ValueConverter<float>::Type,
39 typename InterruptT = util::NullInterrupter>
46 using LeafType =
typename TreeType::LeafNodeType;
50 using RangeType =
typename LeafManagerType::LeafRange;
52 static_assert(std::is_floating_point<AlphaType>::value,
53 "openvdb::tools::Filter requires a mask grid with floating-point values");
58 Filter(GridT& grid, InterruptT* interrupt =
nullptr)
61 , mInterrupter(interrupt)
76 , mInterrupter(other.mInterrupter)
78 , mGrainSize(other.mGrainSize)
79 , mMinMask(other.mMinMask)
80 , mMaxMask(other.mMaxMask)
81 , mInvertMask(other.mInvertMask)
121 void mean(
int width = 1,
int iterations = 1,
const MaskType* mask =
nullptr);
130 void gaussian(
int width = 1,
int iterations = 1,
const MaskType* mask =
nullptr);
138 void median(
int width = 1,
int iterations = 1,
const MaskType* mask =
nullptr);
143 void offset(ValueType offset,
const MaskType* mask =
nullptr);
151 if (mTask) mTask(const_cast<Filter*>(
this), range);
156 using LeafT =
typename TreeType::LeafNodeType;
157 using VoxelIterT =
typename LeafT::ValueOnIter;
158 using VoxelCIterT =
typename LeafT::ValueOnCIter;
160 using LeafIterT =
typename RangeType::Iterator;
163 void cook(LeafManagerType& leafs);
165 template<
size_t Axis>
167 Avg(
const GridT* grid,
Int32 w): acc(grid->tree()), width(w), frac(1.f/float(2*w+1)) {}
168 inline ValueType operator()(
Coord xyz);
169 typename GridT::ConstAccessor acc;
175 template <
typename AvgT>
176 void doBox(
const RangeType& r,
Int32 w);
177 void doBoxX(
const RangeType& r,
Int32 w) { this->doBox<Avg<0> >(r,w); }
178 void doBoxZ(
const RangeType& r,
Int32 w) { this->doBox<Avg<1> >(r,w); }
179 void doBoxY(
const RangeType& r,
Int32 w) { this->doBox<Avg<2> >(r,w); }
180 void doMedian(
const RangeType&,
int);
181 void doOffset(
const RangeType&, ValueType);
186 typename std::function<void (Filter*, const RangeType&)> mTask;
187 InterruptT* mInterrupter;
188 const MaskType* mMask;
190 AlphaType mMinMask, mMaxMask;
198 namespace filter_internal {
200 template<
typename T>
static inline void accum(T& sum, T addend) { sum += addend; }
202 inline void accum(
bool& sum,
bool addend) { sum = sum || addend; }
206 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
207 template<
size_t Axis>
208 inline typename GridT::ValueType
209 Filter<GridT, MaskT, InterruptT>::Avg<Axis>::operator()(
Coord xyz)
211 ValueType sum = zeroVal<ValueType>();
215 ValueType value =
static_cast<ValueType
>(sum * frac);
224 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
230 if (mInterrupter) mInterrupter->start(
"Applying mean filter");
237 mTask = std::bind(&Filter::doBoxX, std::placeholders::_1, std::placeholders::_2, w);
240 mTask = std::bind(&Filter::doBoxY, std::placeholders::_1, std::placeholders::_2, w);
243 mTask = std::bind(&Filter::doBoxZ, std::placeholders::_1, std::placeholders::_2, w);
247 if (mInterrupter) mInterrupter->end();
251 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
257 if (mInterrupter) mInterrupter->start(
"Applying Gaussian filter");
263 for (
int i=0; i<iterations; ++i) {
265 mTask = std::bind(&Filter::doBoxX, std::placeholders::_1, std::placeholders::_2, w);
268 mTask = std::bind(&Filter::doBoxY, std::placeholders::_1, std::placeholders::_2, w);
271 mTask = std::bind(&Filter::doBoxZ, std::placeholders::_1, std::placeholders::_2, w);
276 if (mInterrupter) mInterrupter->end();
280 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
286 if (mInterrupter) mInterrupter->start(
"Applying median filter");
290 mTask = std::bind(&Filter::doMedian,
291 std::placeholders::_1, std::placeholders::_2,
std::max(1, width));
292 for (
int i=0; i<iterations && !this->
wasInterrupted(); ++i) this->cook(leafs);
294 if (mInterrupter) mInterrupter->end();
298 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
304 if (mInterrupter) mInterrupter->start(
"Applying offset");
308 mTask = std::bind(&Filter::doOffset, std::placeholders::_1, std::placeholders::_2, value);
311 if (mInterrupter) mInterrupter->end();
320 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
325 tbb::parallel_for(leafs.leafRange(mGrainSize), *
this);
327 (*this)(leafs.leafRange());
329 leafs.swapLeafBuffer(1, mGrainSize==0);
334 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
335 template <
typename AvgT>
337 Filter<GridT, MaskT, InterruptT>::doBox(
const RangeType& range,
Int32 w)
342 typename AlphaMaskT::FloatType a, b;
343 AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
344 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
345 BufferT& buffer = leafIter.buffer(1);
346 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
347 const Coord xyz = iter.getCoord();
348 if (alpha(xyz, a, b)) {
350 const ValueType value(b*(*iter) + a*avg(xyz));
352 buffer.setValue(iter.pos(), value);
357 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
358 BufferT& buffer = leafIter.buffer(1);
359 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
360 buffer.setValue(iter.pos(), avg(iter.getCoord()));
368 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
370 Filter<GridT, MaskT, InterruptT>::doMedian(
const RangeType& range,
int width)
373 typename math::DenseStencil<GridType> stencil(*mGrid, width);
375 typename AlphaMaskT::FloatType a, b;
376 AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
377 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
378 BufferT& buffer = leafIter.buffer(1);
379 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
380 if (alpha(iter.getCoord(), a, b)) {
381 stencil.moveTo(iter);
383 ValueType value(b*(*iter) + a*stencil.median());
385 buffer.setValue(iter.pos(), value);
390 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
391 BufferT& buffer = leafIter.buffer(1);
392 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
393 stencil.moveTo(iter);
394 buffer.setValue(iter.pos(), stencil.median());
402 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
404 Filter<GridT, MaskT, InterruptT>::doOffset(
const RangeType& range, ValueType offset)
408 typename AlphaMaskT::FloatType a, b;
409 AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
410 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
411 for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
412 if (alpha(iter.getCoord(), a, b)) {
414 ValueType value(*iter + a*offset);
416 iter.setValue(value);
421 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
422 for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
423 iter.setValue(*iter + offset);
430 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
435 tbb::task::self().cancel_group_execution();
445 #endif // OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:82
typename CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition: LeafManager.h:93
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
Axis
Definition: Math.h:849
Definition: Exceptions.h:65
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:102
int32_t Int32
Definition: Types.h:33
Definition: Exceptions.h:13
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:82
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:49
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:154
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...