OpenVDB  1.1.0
Filter.h
Go to the documentation of this file.
1 
2 //
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 //
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/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>
50 
51 namespace openvdb {
53 namespace OPENVDB_VERSION_NAME {
54 namespace tools {
55 
57 template<typename GridT, typename InterruptT = util::NullInterrupter>
58 class Filter
59 {
60 public:
61  typedef GridT GridType;
62  typedef typename GridType::TreeType TreeType;
63  typedef typename TreeType::LeafNodeType LeafType;
64  typedef typename LeafType::ValueType ValueType;
68 
70  Filter(GridT& grid, InterruptT* interrupt = NULL) :
71  mGrid(grid), mTask(0), mInterrupter(interrupt)
72  {
73  }
74 
76  void mean(int width = 1, int iterations = 1, bool serial = false);
77 
82  void gaussian(int width = 1, int iterations = 1, bool serial = false);
83 
87  void median(int width = 1, int iterations = 1, bool serial = false);
88 
90  void offset(float offset, bool serial = false);
91 
95  void operator()(const RangeType& r) const
96  {
97  if (mTask) mTask(const_cast<Filter*>(this), r);
98  else OPENVDB_THROW(ValueError, "task is undefined - call median(), mean(), etc.");
99  }
100 
101 private:
102  typedef typename boost::function<void (Filter*, const RangeType&)> FuncType;
103 
104  void cook(bool serial, LeafManagerType& leafs);
105 
106  // Private filter methods called by tbb::parallel_for threads
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);
113  bool wasInterrupted();
114 
115  GridType& mGrid;
116  FuncType mTask;
117  InterruptT* mInterrupter;
118 }; // end of Filter class
119 
121 
122 template<typename GridT, typename InterruptT>
123 inline void
124 Filter<GridT, InterruptT>::mean(int width, int iterations, bool serial)
125 {
126  if (mInterrupter) mInterrupter->start("Applying mean filter");
127 
128  const int w = std::max(1, width);
129 
130  LeafManagerType leafs(mGrid.tree(), 1, serial);
131 
132  for (int i=0; i<iterations && !this->wasInterrupted(); ++i) {
133  mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
134  this->cook(serial, leafs);
135 
136  mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
137  this->cook(serial, leafs);
138 
139  mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
140  this->cook(serial, leafs);
141  }
142 
143  if (mInterrupter) mInterrupter->end();
144 }
145 
146 template<typename GridT, typename InterruptT>
147 inline void
148 Filter<GridT, InterruptT>::gaussian(int width, int iterations, bool serial)
149 {
150  if (mInterrupter) mInterrupter->start("Applying gaussian filter");
151 
152  const int w = std::max(1, width);
153 
154  LeafManagerType leafs(mGrid.tree(), 1, serial);
155 
156  for (int i=0; i<iterations; ++i) {
157  for (int n=0; n<4 && !this->wasInterrupted(); ++n) {
158  mTask = boost::bind(&Filter::doBoxX, _1, _2, w);
159  this->cook(serial, leafs);
160 
161  mTask = boost::bind(&Filter::doBoxY, _1, _2, w);
162  this->cook(serial, leafs);
163 
164  mTask = boost::bind(&Filter::doBoxZ, _1, _2, w);
165  this->cook(serial, leafs);
166  }
167  }
168 
169  if (mInterrupter) mInterrupter->end();
170 }
171 
172 
173 template<typename GridT, typename InterruptT>
174 inline void
175 Filter<GridT, InterruptT>::median(int width, int iterations, bool serial)
176 {
177  if (mInterrupter) mInterrupter->start("Applying median filter");
178 
179  LeafManagerType leafs(mGrid.tree(), 1, serial);
180 
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);
183 
184  if (mInterrupter) mInterrupter->end();
185 }
186 
187 template<typename GridT, typename InterruptT>
188 inline void
189 Filter<GridT, InterruptT>::offset(float value, bool serial)
190 {
191  if (mInterrupter) mInterrupter->start("Applying offset");
192 
193  LeafManagerType leafs(mGrid.tree(), 0, serial);
194 
195  mTask = boost::bind(&Filter::doOffset, _1, _2, value);
196  this->cook(serial, leafs);
197 
198  if (mInterrupter) mInterrupter->end();
199 }
200 
202 
203 
206 template<typename GridT, typename InterruptT>
207 inline void
208 Filter<GridT, InterruptT>::cook(bool serial, LeafManagerType& leafs)
209 {
210  if (serial) {
211  (*this)(leafs.leafRange());
212  } else {
213  tbb::parallel_for(leafs.leafRange(), *this);
214  }
215  leafs.swapLeafBuffer(1, serial);
216 }
217 
219 template<typename GridT, typename InterruptT>
220 inline void
221 Filter<GridT, InterruptT>::doBoxX(const RangeType& range, Int32 w)
222 {
223  this->wasInterrupted();
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>();
230  math::Coord xyz = vIter.getCoord();
231  for (Int32 x = xyz.x()-w, xLast = xyz.x()+w; x <= xLast; ++x) {
232  sum += acc.getValue(xyz.setX(x));
233  }
234  buffer.setValue(vIter.pos(), sum*frac);
235  }
236  }
237 }
238 
240 template<typename GridT, typename InterruptT>
241 inline void
242 Filter<GridT, InterruptT>::doBoxY(const RangeType& range, Int32 w)
243 {
244  this->wasInterrupted();
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>();
251  math::Coord xyz = vIter.getCoord();
252  for (Int32 y = xyz.y()-w, yLast = xyz.y()+w; y <= yLast; ++y) {
253  sum += acc.getValue(xyz.setY(y));
254  }
255  buffer.setValue(vIter.pos(), sum*frac);
256  }
257  }
258 }
259 
261 template<typename GridT, typename InterruptT>
262 inline void
263 Filter<GridT, InterruptT>::doBoxZ(const RangeType& range, Int32 w)
264 {
265  this->wasInterrupted();
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>();
272  math::Coord xyz = vIter.getCoord();
273  for (Int32 z = xyz.z()-w, zLast = xyz.z()+w; z <= zLast; ++z) {
274  sum += acc.getValue(xyz.setZ(z));
275  }
276  buffer.setValue(vIter.pos(), sum*frac);
277  }
278  }
279 }
280 
282 template<typename GridT, typename InterruptT>
283 inline void
284 Filter<GridT, InterruptT>::doMedian(const RangeType& range, int width)
285 {
286  this->wasInterrupted();
287  typename math::DenseStencil<GridType> stencil(mGrid, width);//creates local cache!
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());
293  }
294  }
295 }
296 
298 template<typename GridT, typename InterruptT>
299 inline void
300 Filter<GridT, InterruptT>::doOffset(const RangeType& range, float floatVal)
301 {
302  const ValueType value = static_cast<ValueType>(floatVal);
303  for (typename RangeType::Iterator lIter=range.begin(); lIter; ++lIter) lIter->addValue(value);
304 }
305 
306 template<typename GridT, typename InterruptT>
307 inline bool
309 {
310  if (util::wasInterrupted(mInterrupter)) {
311  tbb::task::self().cancel_group_execution();
312  return true;
313  }
314  return false;
315 }
316 
317 } // namespace tools
318 } // namespace OPENVDB_VERSION_NAME
319 } // namespace openvdb
320 
321 #endif // OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED
322 
323 // Copyright (c) 2012-2013 DreamWorks Animation LLC
324 // All rights reserved. This software is distributed under the
325 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )