35 #ifndef OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
36 #define OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
38 #include <tbb/parallel_reduce.h>
39 #include <tbb/parallel_for.h>
40 #include <boost/bind.hpp>
41 #include <boost/function.hpp>
42 #include <boost/scoped_ptr.hpp>
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>
57 template<
typename Gr
idT,
typename InterruptT = util::NullInterrupter>
63 typedef typename TreeType::LeafNodeType
LeafType;
70 Filter(GridT& grid, InterruptT* interrupt = NULL) :
71 mGrid(grid), mTask(0), mInterrupter(interrupt)
76 void mean(
int width = 1,
int iterations = 1,
bool serial =
false);
82 void gaussian(
int width = 1,
int iterations = 1,
bool serial =
false);
87 void median(
int width = 1,
int iterations = 1,
bool serial =
false);
90 void offset(
float offset,
bool serial =
false);
97 if (mTask) mTask(const_cast<Filter*>(
this), r);
102 typedef typename boost::function<void (Filter*, const RangeType&)> FuncType;
104 void cook(
bool serial, LeafManagerType& leafs);
107 void doBoxX(
const RangeType&,
Int32);
108 void doBoxY(
const RangeType&,
Int32);
109 void doBoxZ(
const RangeType&,
Int32);
110 void doMedian(
const RangeType&,
int);
111 void doOffset(
const RangeType&,
float);
117 InterruptT* mInterrupter;
122 template<
typename Gr
idT,
typename InterruptT>
126 if (mInterrupter) mInterrupter->start(
"Applying mean filter");
133 mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
134 this->cook(serial, leafs);
136 mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
137 this->cook(serial, leafs);
139 mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
140 this->cook(serial, leafs);
143 if (mInterrupter) mInterrupter->end();
146 template<
typename Gr
idT,
typename InterruptT>
150 if (mInterrupter) mInterrupter->start(
"Applying gaussian filter");
156 for (
int i=0; i<iterations; ++i) {
158 mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
159 this->cook(serial, leafs);
161 mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
162 this->cook(serial, leafs);
164 mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
165 this->cook(serial, leafs);
169 if (mInterrupter) mInterrupter->end();
173 template<
typename Gr
idT,
typename InterruptT>
177 if (mInterrupter) mInterrupter->start(
"Applying median filter");
181 mTask = boost::bind(&Filter::doMedian, _1, _2,
std::max(1, width));
182 for (
int i=0; i<iterations && !this->
wasInterrupted(); ++i) this->cook(serial, leafs);
184 if (mInterrupter) mInterrupter->end();
187 template<
typename Gr
idT,
typename InterruptT>
191 if (mInterrupter) mInterrupter->start(
"Applying offset");
195 mTask = boost::bind(&Filter::doOffset, _1, _2, value);
196 this->cook(serial, leafs);
198 if (mInterrupter) mInterrupter->end();
206 template<
typename Gr
idT,
typename InterruptT>
211 (*this)(leafs.leafRange());
213 tbb::parallel_for(leafs.leafRange(), *
this);
215 leafs.swapLeafBuffer(1, serial);
219 template<
typename Gr
idT,
typename InterruptT>
221 Filter<GridT, InterruptT>::doBoxX(
const RangeType& range,
Int32 w)
224 const ValueType frac = ValueType(1)/ValueType(2*w+1);
225 typename GridT::ConstAccessor acc = mGrid.getConstAccessor();
226 for (
typename RangeType::Iterator lIter=range.begin(); lIter; ++lIter) {
227 BufferType& buffer = lIter.buffer(1);
228 for (
typename LeafType::ValueOnCIter vIter = lIter->cbeginValueOn(); vIter; ++vIter) {
229 ValueType sum = zeroVal<ValueType>();
231 for (
Int32 x = xyz.x()-w, xLast = xyz.x()+w; x <= xLast; ++x) {
232 sum += acc.getValue(xyz.setX(x));
234 buffer.setValue(vIter.pos(), sum*frac);
240 template<
typename Gr
idT,
typename InterruptT>
242 Filter<GridT, InterruptT>::doBoxY(
const RangeType& range,
Int32 w)
245 const ValueType frac = ValueType(1)/ValueType(2*w+1);
246 typename GridT::ConstAccessor acc = mGrid.getConstAccessor();
247 for (
typename RangeType::Iterator lIter=range.begin(); lIter; ++lIter) {
248 BufferType& buffer = lIter.buffer(1);
249 for (
typename LeafType::ValueOnCIter vIter = lIter->cbeginValueOn(); vIter; ++vIter) {
250 ValueType sum = zeroVal<ValueType>();
252 for (
Int32 y = xyz.y()-w, yLast = xyz.y()+w; y <= yLast; ++y) {
253 sum += acc.getValue(xyz.setY(y));
255 buffer.setValue(vIter.pos(), sum*frac);
261 template<
typename Gr
idT,
typename InterruptT>
263 Filter<GridT, InterruptT>::doBoxZ(
const RangeType& range,
Int32 w)
266 const ValueType frac = ValueType(1)/ValueType(2*w+1);
267 typename GridT::ConstAccessor acc = mGrid.getConstAccessor();
268 for (
typename RangeType::Iterator lIter=range.begin(); lIter; ++lIter) {
269 BufferType& buffer = lIter.buffer(1);
270 for (
typename LeafType::ValueOnCIter vIter = lIter->cbeginValueOn(); vIter; ++vIter) {
271 ValueType sum = zeroVal<ValueType>();
273 for (
Int32 z = xyz.z()-w, zLast = xyz.z()+w; z <= zLast; ++z) {
274 sum += acc.getValue(xyz.setZ(z));
276 buffer.setValue(vIter.pos(), sum*frac);
282 template<
typename Gr
idT,
typename InterruptT>
284 Filter<GridT, InterruptT>::doMedian(
const RangeType& range,
int width)
287 typename math::DenseStencil<GridType> stencil(mGrid, width);
288 for (
typename RangeType::Iterator lIter=range.begin(); lIter; ++lIter) {
289 BufferType& buffer = lIter.buffer(1);
290 for (
typename LeafType::ValueOnCIter vIter = lIter->cbeginValueOn(); vIter; ++vIter) {
291 stencil.moveTo(vIter);
292 buffer.setValue(vIter.pos(), stencil.median());
298 template<
typename Gr
idT,
typename InterruptT>
300 Filter<GridT, InterruptT>::doOffset(
const RangeType& range,
float floatVal)
302 const ValueType value =
static_cast<ValueType
>(floatVal);
303 for (
typename RangeType::Iterator lIter=range.begin(); lIter; ++lIter) lIter->addValue(value);
306 template<
typename Gr
idT,
typename InterruptT>
311 tbb::task::self().cancel_group_execution();
321 #endif // OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED