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)
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;
188 void cook(LeafManagerType& leafs);
193 AlphaMask(
const GridType& grid,
const MaskType& mask,
194 AlphaType
min, AlphaType
max,
bool invert)
195 : mAcc(mask.tree()), mSampler(mAcc, mask.transform(), grid.transform()),
196 mMin(min), mInvNorm(1/(max-min)), mInvert(invert)
200 inline bool operator()(
const Coord& xyz, AlphaType& a, AlphaType& b)
const
203 const AlphaType t = (a-mMin)*mInvNorm;
204 a = t > 0 ? t < 1 ? (3-2*t)*t*t : 1 : 0;
206 if (mInvert) std::swap(a,b);
209 typedef typename MaskType::ConstAccessor AccType;
212 const AlphaType mMin, mInvNorm;
216 template <
size_t Axis>
218 Avg(
const GridT* grid,
Int32 w) :
219 acc(grid->tree()), width(w), frac(1/ValueType(2*w+1)) {}
220 ValueType operator()(Coord xyz) {
221 ValueType sum = zeroVal<ValueType>();
223 for (i -= width; i <= j; ++i) sum += acc.getValue(xyz);
226 typename GridT::ConstAccessor acc;
228 const ValueType frac;
232 template <
typename AvgT>
233 void doBox(
const RangeType& r,
Int32 w);
234 void doBoxX(
const RangeType& r,
Int32 w) { this->doBox<Avg<0> >(r,w); }
235 void doBoxZ(
const RangeType& r,
Int32 w) { this->doBox<Avg<1> >(r,w); }
236 void doBoxY(
const RangeType& r,
Int32 w) { this->doBox<Avg<2> >(r,w); }
237 void doMedian(
const RangeType&,
int);
238 void doOffset(
const RangeType&, ValueType);
243 typename boost::function<void (Filter*, const RangeType&)> mTask;
244 InterruptT* mInterrupter;
245 const MaskType* mMask;
247 AlphaType mMinMask, mMaxMask;
253 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
259 if (mInterrupter) mInterrupter->start(
"Applying mean filter");
266 mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
269 mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
272 mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
276 if (mInterrupter) mInterrupter->end();
279 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
285 if (mInterrupter) mInterrupter->start(
"Applying gaussian filter");
291 for (
int i=0; i<iterations; ++i) {
293 mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
296 mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
299 mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
304 if (mInterrupter) mInterrupter->end();
308 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
314 if (mInterrupter) mInterrupter->start(
"Applying median filter");
318 mTask = boost::bind(&Filter::doMedian, _1, _2,
std::max(1, width));
319 for (
int i=0; i<iterations && !this->
wasInterrupted(); ++i) this->cook(leafs);
321 if (mInterrupter) mInterrupter->end();
324 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
330 if (mInterrupter) mInterrupter->start(
"Applying offset");
334 mTask = boost::bind(&Filter::doOffset, _1, _2, value);
337 if (mInterrupter) mInterrupter->end();
345 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
350 tbb::parallel_for(leafs.leafRange(mGrainSize), *
this);
352 (*this)(leafs.leafRange());
354 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)
367 AlphaMask 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()));
388 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
390 Filter<GridT, MaskT, InterruptT>::doMedian(
const RangeType& range,
int width)
393 typename math::DenseStencil<GridType> stencil(*mGrid, width);
396 AlphaMask alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask);
397 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
398 BufferT& buffer = leafIter.buffer(1);
399 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
400 if (alpha(iter.getCoord(), a, b)) {
401 stencil.moveTo(iter);
402 buffer.setValue(iter.pos(), ValueType(b*(*iter) + a*stencil.median()));
407 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
408 BufferT& buffer = leafIter.buffer(1);
409 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
410 stencil.moveTo(iter);
411 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)
425 AlphaMask 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);
440 template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
445 tbb::task::self().cancel_group_execution();
455 #endif // OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
OPENVDB_API Hermite min(const Hermite &, const Hermite &)
min and max operations done directly on the compressed data.
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
Definition: Exceptions.h:88
Definition: LeafManager.h:122
#define OPENVDB_VERSION_NAME
Definition: version.h:45
OPENVDB_API Hermite max(const Hermite &, const Hermite &)
min and max operations done directly on the compressed data.
int32_t Int32
Definition: Types.h:59
Axis
Definition: Math.h:767
CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition: LeafManager.h:117
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:67
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:109