OpenVDB  1.2.0
Filter.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2013 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 //
37 
38 #ifndef OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
39 #define OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
40 
41 #include <tbb/parallel_reduce.h>
42 #include <tbb/parallel_for.h>
43 #include <boost/bind.hpp>
44 #include <boost/function.hpp>
45 #include <boost/scoped_ptr.hpp>
46 #include <openvdb/Types.h>
47 #include <openvdb/math/Math.h>
48 #include <openvdb/math/Stencils.h>
49 #include <openvdb/math/Transform.h>
50 #include <openvdb/tree/LeafManager.h>
51 #include <openvdb/util/NullInterrupter.h>
52 #include <openvdb/Grid.h>
53 
54 namespace openvdb {
56 namespace OPENVDB_VERSION_NAME {
57 namespace tools {
58 
61 template<typename GridT, typename InterruptT = util::NullInterrupter>
62 class Filter
63 {
64 public:
65  typedef GridT GridType;
66  typedef typename GridType::TreeType TreeType;
67  typedef typename TreeType::LeafNodeType LeafType;
68  typedef typename LeafType::ValueType ValueType;
72 
76  Filter(GridT& grid, InterruptT* interrupt = NULL) :
77  mGrid(grid), mTask(0), mInterrupter(interrupt)
78  {
79  }
80 
85  void mean(int width = 1, int iterations = 1, bool serial = false);
86 
94  void gaussian(int width = 1, int iterations = 1, bool serial = false);
95 
102  void median(int width = 1, int iterations = 1, bool serial = false);
103 
107  void offset(float offset, bool serial = false);
108 
113  void operator()(const RangeType& range) const
114  {
115  if (mTask) mTask(const_cast<Filter*>(this), range);
116  else OPENVDB_THROW(ValueError, "task is undefined - call median(), mean(), etc.");
117  }
118 
119 private:
120  typedef typename boost::function<void (Filter*, const RangeType&)> FuncType;
121 
122  void cook(bool serial, LeafManagerType& leafs);
123 
124  template <size_t Axis>
125  struct Avg {
126  Avg(const GridT& grid, Int32 w) : acc(grid.tree()), width(w), frac(1/ValueType(2*w+1)) {}
127  ValueType operator()(Coord xyz) {
128  ValueType sum = zeroVal<ValueType>();
129  Int32& i = xyz[Axis], j = i + width;
130  for (i -= width; i <= j; ++i) sum += acc.getValue(xyz);
131  return sum*frac;
132  }
133  typename GridT::ConstAccessor acc;
134  const Int32 width;
135  const ValueType frac;
136  };
137 
138  // Private filter methods called by tbb::parallel_for threads
139  template <typename AvgT>
140  void doBox( const RangeType& r, Int32 w);
141  void doBoxX(const RangeType& r, Int32 w) { this->doBox<Avg<0> >(r,w); }
142  void doBoxZ(const RangeType& r, Int32 w) { this->doBox<Avg<1> >(r,w); }
143  void doBoxY(const RangeType& r, Int32 w) { this->doBox<Avg<2> >(r,w); }
144  void doMedian(const RangeType&, int);
145  void doOffset(const RangeType&, float);
147  bool wasInterrupted();
148 
149  GridType& mGrid;
150  FuncType mTask;
151  InterruptT* mInterrupter;
152 }; // end of Filter class
153 
155 
156 template<typename GridT, typename InterruptT>
157 inline void
158 Filter<GridT, InterruptT>::mean(int width, int iterations, bool serial)
159 {
160  if (mInterrupter) mInterrupter->start("Applying mean filter");
161 
162  const int w = std::max(1, width);
163 
164  LeafManagerType leafs(mGrid.tree(), 1, serial);
165 
166  for (int i=0; i<iterations && !this->wasInterrupted(); ++i) {
167  mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
168  this->cook(serial, leafs);
169 
170  mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
171  this->cook(serial, leafs);
172 
173  mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
174  this->cook(serial, leafs);
175  }
176 
177  if (mInterrupter) mInterrupter->end();
178 }
179 
180 template<typename GridT, typename InterruptT>
181 inline void
182 Filter<GridT, InterruptT>::gaussian(int width, int iterations, bool serial)
183 {
184  if (mInterrupter) mInterrupter->start("Applying gaussian filter");
185 
186  const int w = std::max(1, width);
187 
188  LeafManagerType leafs(mGrid.tree(), 1, serial);
189 
190  for (int i=0; i<iterations; ++i) {
191  for (int n=0; n<4 && !this->wasInterrupted(); ++n) {
192  mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
193  this->cook(serial, leafs);
194 
195  mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
196  this->cook(serial, leafs);
197 
198  mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
199  this->cook(serial, leafs);
200  }
201  }
202 
203  if (mInterrupter) mInterrupter->end();
204 }
205 
206 
207 template<typename GridT, typename InterruptT>
208 inline void
209 Filter<GridT, InterruptT>::median(int width, int iterations, bool serial)
210 {
211  if (mInterrupter) mInterrupter->start("Applying median filter");
212 
213  LeafManagerType leafs(mGrid.tree(), 1, serial);
214 
215  mTask = boost::bind(&Filter::doMedian, _1, _2, std::max(1, width));
216  for (int i=0; i<iterations && !this->wasInterrupted(); ++i) this->cook(serial, leafs);
217 
218  if (mInterrupter) mInterrupter->end();
219 }
220 
221 template<typename GridT, typename InterruptT>
222 inline void
223 Filter<GridT, InterruptT>::offset(float value, bool serial)
224 {
225  if (mInterrupter) mInterrupter->start("Applying offset");
226 
227  LeafManagerType leafs(mGrid.tree(), 0, serial);
228 
229  mTask = boost::bind(&Filter::doOffset, _1, _2, value);
230  this->cook(serial, leafs);
231 
232  if (mInterrupter) mInterrupter->end();
233 }
234 
236 
237 
240 template<typename GridT, typename InterruptT>
241 inline void
242 Filter<GridT, InterruptT>::cook(bool serial, LeafManagerType& leafs)
243 {
244  if (serial) {
245  (*this)(leafs.leafRange());
246  } else {
247  tbb::parallel_for(leafs.leafRange(), *this);
248  }
249  leafs.swapLeafBuffer(1, serial);
250 }
251 
253 template<typename GridT, typename InterruptT>
254 template <typename AvgT>
255 inline void
256 Filter<GridT, InterruptT>::doBox(const RangeType& range, Int32 w)
257 {
258  this->wasInterrupted();
259  AvgT avg(mGrid, w);
260  for (typename RangeType::Iterator lIter=range.begin(); lIter; ++lIter) {
261  BufferType& buffer = lIter.buffer(1);
262  for (typename LeafType::ValueOnCIter vIter = lIter->cbeginValueOn(); vIter; ++vIter) {
263  buffer.setValue(vIter.pos(), avg(vIter.getCoord()));
264  }
265  }
266 }
267 
269 template<typename GridT, typename InterruptT>
270 inline void
271 Filter<GridT, InterruptT>::doMedian(const RangeType& range, int width)
272 {
273  this->wasInterrupted();
274  typename math::DenseStencil<GridType> stencil(mGrid, width);//creates local cache!
275  for (typename RangeType::Iterator lIter=range.begin(); lIter; ++lIter) {
276  BufferType& buffer = lIter.buffer(1);
277  for (typename LeafType::ValueOnCIter vIter = lIter->cbeginValueOn(); vIter; ++vIter) {
278  stencil.moveTo(vIter);
279  buffer.setValue(vIter.pos(), stencil.median());
280  }
281  }
282 }
283 
285 template<typename GridT, typename InterruptT>
286 inline void
287 Filter<GridT, InterruptT>::doOffset(const RangeType& range, float floatVal)
288 {
289  const ValueType offset = static_cast<ValueType>(floatVal);
290  for (typename RangeType::Iterator leafIter=range.begin(); leafIter; ++leafIter) {
291  for (typename LeafType::ValueOnIter iter = leafIter->beginValueOn(); iter; ++iter) {
292  iter.setValue(*iter + offset);
293  }
294  }
295 }
296 
297 template<typename GridT, typename InterruptT>
298 inline bool
300 {
301  if (util::wasInterrupted(mInterrupter)) {
302  tbb::task::self().cancel_group_execution();
303  return true;
304  }
305  return false;
306 }
307 
308 } // namespace tools
309 } // namespace OPENVDB_VERSION_NAME
310 } // namespace openvdb
311 
312 #endif // OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
313 
314 // Copyright (c) 2012-2013 DreamWorks Animation LLC
315 // All rights reserved. This software is distributed under the
316 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )