39 #ifndef OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED 40 #define OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED 42 #include <tbb/parallel_for.h> 53 #include <type_traits> 64 template<
typename GridT,
65 typename MaskT =
typename GridT::template ValueConverter<float>::Type,
66 typename InterruptT = util::NullInterrupter>
73 using LeafType =
typename TreeType::LeafNodeType;
77 using RangeType =
typename LeafManagerType::LeafRange;
79 static_assert(std::is_floating_point<AlphaType>::value,
80 "openvdb::tools::Filter requires a mask grid with floating-point values");
85 Filter(GridT& grid, InterruptT* interrupt =
nullptr)
88 , mInterrupter(interrupt)
103 , mInterrupter(other.mInterrupter)
105 , mGrainSize(other.mGrainSize)
106 , mMinMask(other.mMinMask)
107 , mMaxMask(other.mMaxMask)
108 , mInvertMask(other.mInvertMask)
148 void mean(
int width = 1,
int iterations = 1,
const MaskType* mask =
nullptr);
157 void gaussian(
int width = 1,
int iterations = 1,
const MaskType* mask =
nullptr);
165 void median(
int width = 1,
int iterations = 1,
const MaskType* mask =
nullptr);
170 void offset(ValueType offset,
const MaskType* mask =
nullptr);
178 if (mTask) mTask(const_cast<Filter*>(
this), range);
183 using LeafT =
typename TreeType::LeafNodeType;
184 using VoxelIterT =
typename LeafT::ValueOnIter;
185 using VoxelCIterT =
typename LeafT::ValueOnCIter;
187 using LeafIterT =
typename RangeType::Iterator;
190 void cook(LeafManagerType& leafs);
192 template<
size_t Axis>
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;
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);
213 typename std::function<void (Filter*,
const RangeType&)> mTask;
214 InterruptT* mInterrupter;
215 const MaskType* mMask;
217 AlphaType mMinMask, mMaxMask;
225 namespace filter_internal {
227 template<
typename T>
static inline void accum(T& sum, T addend) { sum += addend; }
229 inline void accum(
bool& sum,
bool addend) { sum = sum || addend; }
233 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
234 template<
size_t Axis>
235 inline typename GridT::ValueType
236 Filter<GridT, MaskT, InterruptT>::Avg<Axis>::operator()(
Coord xyz)
238 ValueType sum = zeroVal<ValueType>();
241 return static_cast<ValueType>(sum * frac);
248 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
254 if (mInterrupter) mInterrupter->start(
"Applying mean filter");
261 mTask = std::bind(&Filter::doBoxX, std::placeholders::_1, std::placeholders::_2, w);
264 mTask = std::bind(&Filter::doBoxY, std::placeholders::_1, std::placeholders::_2, w);
267 mTask = std::bind(&Filter::doBoxZ, std::placeholders::_1, std::placeholders::_2, w);
271 if (mInterrupter) mInterrupter->end();
275 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
281 if (mInterrupter) mInterrupter->start(
"Applying Gaussian filter");
287 for (
int i=0; i<iterations; ++i) {
289 mTask = std::bind(&Filter::doBoxX, std::placeholders::_1, std::placeholders::_2, w);
292 mTask = std::bind(&Filter::doBoxY, std::placeholders::_1, std::placeholders::_2, w);
295 mTask = std::bind(&Filter::doBoxZ, std::placeholders::_1, std::placeholders::_2, w);
300 if (mInterrupter) mInterrupter->end();
304 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
310 if (mInterrupter) mInterrupter->start(
"Applying median filter");
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);
318 if (mInterrupter) mInterrupter->end();
322 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
328 if (mInterrupter) mInterrupter->start(
"Applying offset");
332 mTask = std::bind(&Filter::doOffset, std::placeholders::_1, std::placeholders::_2, value);
335 if (mInterrupter) mInterrupter->end();
344 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
349 tbb::parallel_for(leafs.leafRange(mGrainSize), *
this);
351 (*this)(leafs.leafRange());
353 leafs.swapLeafBuffer(1, mGrainSize==0);
358 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
359 template <
typename AvgT>
361 Filter<GridT, MaskT, InterruptT>::doBox(
const RangeType& range,
Int32 w)
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)));
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()));
389 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
391 Filter<GridT, MaskT, InterruptT>::doMedian(
const RangeType& range,
int width)
394 typename math::DenseStencil<GridType> stencil(*mGrid, width);
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()));
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());
420 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
422 Filter<GridT, MaskT, InterruptT>::doOffset(
const RangeType& range, ValueType offset)
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));
434 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
435 for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
436 iter.setValue(*iter + offset);
443 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
448 tbb::task::self().cancel_group_execution();
458 #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:109
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:51
int32_t Int32
Definition: Types.h:63
Axis
Definition: Math.h:856
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
Definition: Exceptions.h:40
typename CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition: LeafManager.h:121
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:110
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
Definition: Exceptions.h:92
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...