OpenVDB  0.104.0
Filter.h
Go to the documentation of this file.
1 
2 //
3 // Copyright (c) 2012 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 //
34 
35 #ifndef OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
36 #define OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
37 
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/openvdb.h>
44 #include <openvdb/Types.h>
45 #include <openvdb/math/Math.h>
46 #include <openvdb/math/Stencils.h>
47 #include <openvdb/math/Transform.h>
48 #include <openvdb/tree/LeafManager.h>
49 #include <openvdb/util/NullInterrupter.h>
50 #include <openvdb/Grid.h>
51 
52 
53 namespace openvdb {
55 namespace OPENVDB_VERSION_NAME {
56 namespace tools {
57 
59 template<typename GridT, typename InterruptT = util::NullInterrupter>
60 class Filter
61 {
62 public:
63  typedef GridT GridType;
64  typedef typename GridType::TreeType TreeType;
65  typedef typename TreeType::LeafNodeType LeafType;
66  typedef typename LeafType::ValueType ValueType;
70 
72  explicit Filter(GridT& grid, InterruptT* interrupt = NULL) :
73  mIsMaster(true), mGrid(grid), mTask(0),
74  mLeafs(new LeafManagerType(grid.tree())), mInterrupter(interrupt)
75  {
76  }
78  Filter(const Filter& other) :
79  mIsMaster(false), mGrid(other.mGrid), mTask(other.mTask),
80  mLeafs(other.mLeafs), mInterrupter(other.mInterrupter)
81  {
82  }
83  virtual ~Filter()
84  {
85  if ( mIsMaster ) delete mLeafs;
86  }
87 
89  void mean(int width = 1, bool serial = false);
90 
95  void gaussian(int width = 1, bool serial = false);
96 
100  void median(int width = 1, bool serial = false);
101 
103  void offset(float offset, bool serial = false);
104 
108  void operator()(const RangeType& r) const
109  {
110  if (mTask) mTask(const_cast<Filter*>(this), r);
111  else OPENVDB_THROW(ValueError, "task is undefined - call median(), mean(), etc.");
112  }
113 
114 private:
115  typedef typename boost::function<void (Filter*, const RangeType&)> FuncType;
116 
117  void cook(bool serial, bool swapBuffers);
118 
119  // Private filter methods called by tbb::parallel_for threads
120  void doBoxX(const RangeType&, Int32);
121  void doBoxY(const RangeType&, Int32);
122  void doBoxZ(const RangeType&, Int32);
123  void doMedian(const RangeType&, int);
124  void doOffset(const RangeType&, float);
125  void startInterrupter(const char* msg);
126  void endInterrupter();
127  void checkInterrupter();
128 
129  const bool mIsMaster;
130  GridType& mGrid;
131  FuncType mTask;
132  LeafManagerType* mLeafs;
133  InterruptT* mInterrupter;
134 
135 }; // end of Filter class
136 
138 
139 template<typename GridT, typename InterruptT>
140 inline void
141 Filter<GridT, InterruptT>::mean(int width, bool serial)
142 {
143  this->startInterrupter("Applying mean filter");
144  width = std::max(1, width);
145 
146  mLeafs->rebuildAuxBuffers(1, serial);
147 
148  mTask = boost::bind(&Filter::doBoxX, _1, _2, width);
149  this->cook(serial, true);
150 
151  mTask = boost::bind(&Filter::doBoxY, _1, _2, width);
152  this->cook(serial, true);
153 
154  mTask = boost::bind(&Filter::doBoxZ, _1, _2, width);
155  this->cook(serial, true);
156  this->endInterrupter();
157 }
158 
159 template<typename GridT, typename InterruptT>
160 inline void
161 Filter<GridT, InterruptT>::gaussian(int width, bool serial)
162 {
163  this->startInterrupter("Applying gaussian filter");
164  width = std::max(1, width);
165 
166  mLeafs->rebuildAuxBuffers(1, serial);
167 
168  for (int n=0; n<4; ++n) {
169  mTask = boost::bind(&Filter::doBoxX, _1, _2, width);
170  this->cook(serial, true);
171 
172  mTask = boost::bind(&Filter::doBoxY, _1, _2, width);
173  this->cook(serial, true);
174 
175  mTask = boost::bind(&Filter::doBoxZ, _1, _2, width);
176  this->cook(serial, true);
177  }
178  this->endInterrupter();
179 }
180 
181 
182 template<typename GridT, typename InterruptT>
183 inline void
184 Filter<GridT, InterruptT>::median(int width, bool serial)
185 {
186  this->startInterrupter("Applying median filter");
187  mLeafs->rebuildAuxBuffers(1, serial);
188  mTask = boost::bind(&Filter::doMedian, _1, _2, std::max(1, width));
189  this->cook(serial, true);
190  this->endInterrupter();
191 }
192 
193 template<typename GridT, typename InterruptT>
194 inline void
195 Filter<GridT, InterruptT>::offset(float value, bool serial)
196 {
197  this->startInterrupter("Applying offset");
198  mLeafs->removeAuxBuffers();
199  mTask = boost::bind(&Filter::doOffset, _1, _2, value);
200  this->cook(serial, false);
201  this->endInterrupter();
202 }
203 
205 
206 
209 template<typename GridT, typename InterruptT>
210 inline void
211 Filter<GridT, InterruptT>::cook(bool serial, bool swapBuffers)
212 {
213  if (serial) {
214  (*this)(mLeafs->getRange());
215  } else {
216  tbb::parallel_for(mLeafs->getRange(), *this);
217  }
218  if (swapBuffers) mLeafs->swapLeafBuffer(1, serial);
219 }
220 
222 template<typename GridT, typename InterruptT>
223 inline void
224 Filter<GridT, InterruptT>::doBoxX(const RangeType& range, Int32 w)
225 {
226  this->checkInterrupter();
227  const ValueType frac = ValueType(1)/ValueType(2*w+1);
228  typename GridT::ConstAccessor acc = mGrid.getConstAccessor();
229  for (size_t n=range.begin(), nLast = range.end(); n != nLast; ++n) {
230  const LeafType& leaf = mLeafs->leaf(n);
231  BufferType& buffer = mLeafs->getBuffer(n, 1);
232  for (typename LeafType::ValueOnCIter iter = leaf.cbeginValueOn(); iter; ++iter) {
233  ValueType sum = zeroVal<ValueType>();
234  math::Coord xyz = iter.getCoord();
235  for (Int32 x = xyz.x()-w, xLast = xyz.x()+w; x <= xLast; ++x) {
236  sum += acc.getValue(xyz.setX(x));
237  }
238  buffer.setValue(iter.pos(), sum*frac);
239  }
240  }
241 }
242 
244 template<typename GridT, typename InterruptT>
245 inline void
246 Filter<GridT, InterruptT>::doBoxY(const RangeType& range, Int32 w)
247 {
248  this->checkInterrupter();
249  const ValueType frac = ValueType(1)/ValueType(2*w+1);
250  typename GridT::ConstAccessor acc = mGrid.getConstAccessor();
251  for (size_t n=range.begin(), nLast = range.end(); n != nLast; ++n) {
252  const LeafType& leaf = mLeafs->leaf(n);
253  BufferType& buffer = mLeafs->getBuffer(n, 1);
254  for (typename LeafType::ValueOnCIter iter = leaf.cbeginValueOn(); iter; ++iter) {
255  ValueType sum = zeroVal<ValueType>();
256  math::Coord xyz = iter.getCoord();
257  for (Int32 y = xyz.y()-w, yLast = xyz.y()+w; y <= yLast; ++y) {
258  sum += acc.getValue(xyz.setY(y));
259  }
260  buffer.setValue(iter.pos(), sum*frac);
261  }
262  }
263 }
264 
266 template<typename GridT, typename InterruptT>
267 inline void
268 Filter<GridT, InterruptT>::doBoxZ(const RangeType& range, Int32 w)
269 {
270  this->checkInterrupter();
271  const ValueType frac = ValueType(1)/ValueType(2*w+1);
272  typename GridT::ConstAccessor acc = mGrid.getConstAccessor();
273  for (size_t n=range.begin(), nLast = range.end(); n != nLast; ++n) {
274  const LeafType& leaf = mLeafs->leaf(n);
275  BufferType& buffer = mLeafs->getBuffer(n, 1);
276  for (typename LeafType::ValueOnCIter iter = leaf.cbeginValueOn(); iter; ++iter) {
277  ValueType sum = zeroVal<ValueType>();
278  math::Coord xyz = iter.getCoord();
279  for (Int32 z = xyz.z()-w, zLast = xyz.z()+w; z <= zLast; ++z) {
280  sum += acc.getValue(xyz.setZ(z));
281  }
282  buffer.setValue(iter.pos(), sum*frac);
283  }
284  }
285 }
286 
288 template<typename GridT, typename InterruptT>
289 inline void
290 Filter<GridT, InterruptT>::doMedian(const RangeType& range, int width)
291 {
292  this->checkInterrupter();
293  typename math::DenseStencil<GridType> stencil(mGrid, width);//creates local cache!
294  for (size_t n=range.begin(), e=range.end(); n != e; ++n) {
295  const LeafType& leaf = mLeafs->leaf(n);
296  BufferType& buffer = mLeafs->getBuffer(n, 1);
297  for (typename LeafType::ValueOnCIter iter = leaf.cbeginValueOn(); iter; ++iter) {
298  stencil.moveTo(iter);
299  buffer.setValue(iter.pos(), stencil.median());
300  }
301  }
302 }
303 
305 template<typename GridT, typename InterruptT>
306 inline void
307 Filter<GridT, InterruptT>::doOffset(const RangeType& range, float floatVal)
308 {
309  const ValueType value = static_cast<ValueType>(floatVal);
310  for (size_t n=range.begin(), e=range.end(); n != e; ++n) mLeafs->leaf(n).addValue(value);
311 }
312 
313 template<typename GridT, typename InterruptT>
314 inline void
315 Filter<GridT, InterruptT>::startInterrupter(const char* msg)
316 {
317  if (mInterrupter) mInterrupter->start(msg);
318 }
319 
320 template<typename GridT, typename InterruptT>
321 inline void
322 Filter<GridT, InterruptT>::endInterrupter()
323 {
324  if (mInterrupter) mInterrupter->end();
325 }
326 
327 template<typename GridT, typename InterruptT>
328 inline void
329 Filter<GridT, InterruptT>::checkInterrupter()
330 {
331  if (util::wasInterrupted(mInterrupter)) tbb::task::self().cancel_group_execution();
332 }
333 
334 } // namespace tools
335 } // namespace OPENVDB_VERSION_NAME
336 } // namespace openvdb
337 
338 #endif // OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
339 
340 // Copyright (c) 2012 DreamWorks Animation LLC
341 // All rights reserved. This software is distributed under the
342 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )