HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Statistics.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2012-2017 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 //
29 ///////////////////////////////////////////////////////////////////////////
30 //
31 /// @file Statistics.h
32 ///
33 /// @brief Functions to efficiently compute histograms, extremas
34 /// (min/max) and statistics (mean, variance, etc.) of grid values
35 
36 #ifndef OPENVDB_TOOLS_STATISTICS_HAS_BEEN_INCLUDED
37 #define OPENVDB_TOOLS_STATISTICS_HAS_BEEN_INCLUDED
38 
39 #include <openvdb/Types.h>
40 #include <openvdb/Exceptions.h>
41 #include <openvdb/math/Stats.h>
42 #include "ValueTransformer.h"
43 
44 
45 namespace openvdb {
47 namespace OPENVDB_VERSION_NAME {
48 namespace tools {
49 
50 /// @brief Iterate over a scalar grid and compute a histogram of the values
51 /// of the voxels that are visited, or iterate over a vector-valued grid
52 /// and compute a histogram of the magnitudes of the vectors.
53 /// @param iter an iterator over the values of a grid or its tree
54 /// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.)
55 /// @param minVal the smallest value that can be added to the histogram
56 /// @param maxVal the largest value that can be added to the histogram
57 /// @param numBins the number of histogram bins
58 /// @param threaded if true, iterate over the grid in parallel
59 template<typename IterT>
60 inline math::Histogram
61 histogram(const IterT& iter, double minVal, double maxVal,
62  size_t numBins = 10, bool threaded = true);
63 
64 /// @brief Iterate over a scalar grid and compute extrema (min/max) of the
65 /// values of the voxels that are visited, or iterate over a vector-valued grid
66 /// and compute extrema of the magnitudes of the vectors.
67 /// @param iter an iterator over the values of a grid or its tree
68 /// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.)
69 /// @param threaded if true, iterate over the grid in parallel
70 template<typename IterT>
71 inline math::Extrema
72 extrema(const IterT& iter, bool threaded = true);
73 
74 /// @brief Iterate over a scalar grid and compute statistics (mean, variance, etc.)
75 /// of the values of the voxels that are visited, or iterate over a vector-valued grid
76 /// and compute statistics of the magnitudes of the vectors.
77 /// @param iter an iterator over the values of a grid or its tree
78 /// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.)
79 /// @param threaded if true, iterate over the grid in parallel
80 template<typename IterT>
81 inline math::Stats
82 statistics(const IterT& iter, bool threaded = true);
83 
84 /// @brief Iterate over a grid and compute extrema (min/max) of
85 /// the values produced by applying the given functor at each voxel that is visited.
86 /// @param iter an iterator over the values of a grid or its tree
87 /// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.)
88 /// @param op a functor of the form <tt>void op(const IterT&, math::Stats&)</tt>,
89 /// where @c IterT is the type of @a iter, that inserts zero or more
90 /// floating-point values into the provided @c math::Stats object
91 /// @param threaded if true, iterate over the grid in parallel
92 /// @note When @a threaded is true, each thread gets its own copy of the functor.
93 ///
94 /// @par Example:
95 /// Compute statistics of just the active and positive-valued voxels of a scalar,
96 /// floating-point grid.
97 /// @code
98 /// struct Local {
99 /// static inline
100 /// void addIfPositive(const FloatGrid::ValueOnCIter& iter, math::Extrema& ex)
101 /// {
102 /// const float f = *iter;
103 /// if (f > 0.0) {
104 /// if (iter.isVoxelValue()) ex.add(f);
105 /// else ex.add(f, iter.getVoxelCount());
106 /// }
107 /// }
108 /// };
109 /// FloatGrid grid = ...;
110 /// math::Extrema stats =
111 /// tools::extrema(grid.cbeginValueOn(), Local::addIfPositive, /*threaded=*/true);
112 /// @endcode
113 template<typename IterT, typename ValueOp>
114 inline math::Extrema
115 extrema(const IterT& iter, const ValueOp& op, bool threaded);
116 
117 /// @brief Iterate over a grid and compute statistics (mean, variance, etc.) of
118 /// the values produced by applying the given functor at each voxel that is visited.
119 /// @param iter an iterator over the values of a grid or its tree
120 /// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.)
121 /// @param op a functor of the form <tt>void op(const IterT&, math::Stats&)</tt>,
122 /// where @c IterT is the type of @a iter, that inserts zero or more
123 /// floating-point values into the provided @c math::Stats object
124 /// @param threaded if true, iterate over the grid in parallel
125 /// @note When @a threaded is true, each thread gets its own copy of the functor.
126 ///
127 /// @par Example:
128 /// Compute statistics of just the active and positive-valued voxels of a scalar,
129 /// floating-point grid.
130 /// @code
131 /// struct Local {
132 /// static inline
133 /// void addIfPositive(const FloatGrid::ValueOnCIter& iter, math::Stats& stats)
134 /// {
135 /// const float f = *iter;
136 /// if (f > 0.0) {
137 /// if (iter.isVoxelValue()) stats.add(f);
138 /// else stats.add(f, iter.getVoxelCount());
139 /// }
140 /// }
141 /// };
142 /// FloatGrid grid = ...;
143 /// math::Stats stats =
144 /// tools::statistics(grid.cbeginValueOn(), Local::addIfPositive, /*threaded=*/true);
145 /// @endcode
146 template<typename IterT, typename ValueOp>
147 inline math::Stats
148 statistics(const IterT& iter, const ValueOp& op, bool threaded);
149 
150 
151 /// @brief Iterate over a grid and compute statistics (mean, variance, etc.)
152 /// of the values produced by applying a given operator (see math/Operators.h)
153 /// at each voxel that is visited.
154 /// @param iter an iterator over the values of a grid or its tree
155 /// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.)
156 /// @param op an operator object with a method of the form
157 /// <tt>double result(Accessor&, const Coord&)</tt>
158 /// @param threaded if true, iterate over the grid in parallel
159 /// @note World-space operators, whose @c result() methods are of the form
160 /// <tt>double result(const Map&, Accessor&, const Coord&)</tt>, must be wrapped
161 /// in a math::MapAdapter.
162 /// @note Vector-valued operators like math::Gradient must be wrapped in an adapter
163 /// such as math::OpMagnitude.
164 ///
165 /// @par Example:
166 /// Compute statistics of the magnitude of the gradient at the active voxels of
167 /// a scalar, floating-point grid. (Note the use of the math::MapAdapter and
168 /// math::OpMagnitude adapters.)
169 /// @code
170 /// FloatGrid grid = ...;
171 ///
172 /// // Assume that we know that the grid has a uniform scale map.
173 /// typedef math::UniformScaleMap MapType;
174 /// // Specify a world-space gradient operator that uses first-order differencing.
175 /// typedef math::Gradient<MapType, math::FD_1ST> GradientOp;
176 /// // Wrap the operator with an adapter that computes the magnitude of the gradient.
177 /// typedef math::OpMagnitude<GradientOp, MapType> MagnitudeOp;
178 /// // Wrap the operator with an adapter that associates a map with it.
179 /// typedef math::MapAdapter<MapType, GradientOp, double> CompoundOp;
180 ///
181 /// if (MapType::Ptr map = grid.constTransform().constMap<MapType>()) {
182 /// math::Stats stats = tools::opStatistics(grid.cbeginValueOn(), CompoundOp(*map));
183 /// }
184 /// @endcode
185 ///
186 /// @par Example:
187 /// Compute statistics of the divergence at the active voxels of a vector-valued grid.
188 /// @code
189 /// Vec3SGrid grid = ...;
190 ///
191 /// // Assume that we know that the grid has a uniform scale map.
192 /// typedef math::UniformScaleMap MapType;
193 /// // Specify a world-space divergence operator that uses first-order differencing.
194 /// typedef math::Divergence<MapType, math::FD_1ST> DivergenceOp;
195 /// // Wrap the operator with an adapter that associates a map with it.
196 /// typedef math::MapAdapter<MapType, DivergenceOp, double> CompoundOp;
197 ///
198 /// if (MapType::Ptr map = grid.constTransform().constMap<MapType>()) {
199 /// math::Stats stats = tools::opStatistics(grid.cbeginValueOn(), CompoundOp(*map));
200 /// }
201 /// @endcode
202 ///
203 /// @par Example:
204 /// As above, but computing the divergence in index space.
205 /// @code
206 /// Vec3SGrid grid = ...;
207 ///
208 /// // Specify an index-space divergence operator that uses first-order differencing.
209 /// typedef math::ISDivergence<math::FD_1ST> DivergenceOp;
210 ///
211 /// math::Stats stats = tools::opStatistics(grid.cbeginValueOn(), DivergenceOp());
212 /// @endcode
213 template<typename OperatorT, typename IterT>
214 inline math::Stats
215 opStatistics(const IterT& iter, const OperatorT& op = OperatorT(), bool threaded = true);
216 
217 /// @brief Same as opStatistics except it returns a math::Extrema vs a math::Stats
218 template<typename OperatorT, typename IterT>
219 inline math::Extrema
220 opExtrema(const IterT& iter, const OperatorT& op = OperatorT(), bool threaded = true);
221 
222 ////////////////////////////////////////
223 
224 
225 namespace stats_internal {
226 
227 /// @todo This traits class is needed because tree::TreeValueIteratorBase uses
228 /// the name ValueT for the type of the value to which the iterator points,
229 /// whereas node-level iterators use the name ValueType.
230 template<typename IterT, typename AuxT = void>
231 struct IterTraits {
232  typedef typename IterT::ValueType ValueType;
233 };
234 
235 template<typename TreeT, typename ValueIterT>
236 struct IterTraits<tree::TreeValueIteratorBase<TreeT, ValueIterT> > {
238 };
239 
240 
241 // Helper class to compute a scalar value from either a scalar or a vector value
242 // (the latter by computing the vector's magnitude)
243 template<typename T, bool IsVector> struct GetValImpl;
244 
245 template<typename T>
246 struct GetValImpl<T, /*IsVector=*/false> {
247  static inline double get(const T& val) { return double(val); }
248 };
249 
250 template<typename T>
251 struct GetValImpl<T, /*IsVector=*/true> {
252  static inline double get(const T& val) { return val.length(); }
253 };
254 
255 
256 // Helper class to compute a scalar value from a tree or node iterator
257 // that points to a value in either a scalar or a vector grid, and to
258 // add that value to a math::Stats object.
259 template<typename IterT, typename StatsT>
260 struct GetVal
261 {
264 
265  inline void operator()(const IterT& iter, StatsT& stats) const {
266  if (iter.isVoxelValue()) stats.add(ImplT::get(*iter));
267  else stats.add(ImplT::get(*iter), iter.getVoxelCount());
268  }
269 };
270 
271 // Helper class to accumulate scalar voxel values or vector voxel magnitudes
272 // into a math::Stats object
273 template<typename IterT, typename ValueOp, typename StatsT>
274 struct StatsOp
275 {
276  StatsOp(const ValueOp& op): getValue(op) {}
277 
278  // Accumulate voxel and tile values into this functor's Stats object.
279  inline void operator()(const IterT& iter) { getValue(iter, stats); }
280 
281  // Accumulate another functor's Stats object into this functor's.
282  inline void join(StatsOp& other) { stats.add(other.stats); }
283 
284  StatsT stats;
285  ValueOp getValue;
286 };
287 
288 
289 // Helper class to accumulate scalar voxel values or vector voxel magnitudes
290 // into a math::Histogram object
291 template<typename IterT, typename ValueOp>
292 struct HistOp
293 {
294  HistOp(const ValueOp& op, double vmin, double vmax, size_t bins):
295  hist(vmin, vmax, bins), getValue(op)
296  {}
297 
298  // Accumulate voxel and tile values into this functor's Histogram object.
299  inline void operator()(const IterT& iter) { getValue(iter, hist); }
300 
301  // Accumulate another functor's Histogram object into this functor's.
302  inline void join(HistOp& other) { hist.add(other.hist); }
303 
305  ValueOp getValue;
306 };
307 
308 
309 // Helper class to apply an operator such as math::Gradient or math::Laplacian
310 // to voxels and accumulate the scalar results or the magnitudes of vector results
311 // into a math::Stats object
312 template<typename IterT, typename OpT, typename StatsT>
313 struct MathOp
314 {
315  typedef typename IterT::TreeT TreeT;
316  typedef typename TreeT::ValueType ValueT;
318 
319  // Each thread gets its own accessor and its own copy of the operator.
321  OpT mOp;
322  StatsT mStats;
323 
324  template<typename TreeT>
325  static inline TreeT* THROW_IF_NULL(TreeT* ptr) {
326  if (ptr == NULL) OPENVDB_THROW(ValueError, "iterator references a null tree");
327  return ptr;
328  }
329 
330  MathOp(const IterT& iter, const OpT& op):
331  mAcc(*THROW_IF_NULL(iter.getTree())), mOp(op)
332  {}
333 
334  // Accumulate voxel and tile values into this functor's Stats object.
335  void operator()(const IterT& it)
336  {
337  if (it.isVoxelValue()) {
338  // Add the magnitude of the gradient at a single voxel.
339  mStats.add(mOp.result(mAcc, it.getCoord()));
340  } else {
341  // Iterate over the voxels enclosed by a tile and add the results
342  // of applying the operator at each voxel.
343  /// @todo This could be specialized to be done more efficiently for some operators.
344  /// For example, all voxels in the interior of a tile (i.e., not on the borders)
345  /// have gradient zero, so there's no need to apply the operator to every voxel.
346  CoordBBox bbox = it.getBoundingBox();
347  Coord xyz;
348  int &x = xyz.x(), &y = xyz.y(), &z = xyz.z();
349  for (x = bbox.min().x(); x <= bbox.max().x(); ++x) {
350  for (y = bbox.min().y(); y <= bbox.max().y(); ++y) {
351  for (z = bbox.min().z(); z <= bbox.max().z(); ++z) {
352  mStats.add(mOp.result(mAcc, it.getCoord()));
353  }
354  }
355  }
356  }
357  }
358 
359  // Accumulate another functor's Stats object into this functor's.
360  inline void join(MathOp& other) { mStats.add(other.mStats); }
361 }; // struct MathOp
362 
363 } // namespace stats_internal
364 
365 
366 template<typename IterT>
367 inline math::Histogram
368 histogram(const IterT& iter, double vmin, double vmax, size_t numBins, bool threaded)
369 {
371  ValueOp valOp;
372  stats_internal::HistOp<IterT, ValueOp> op(valOp, vmin, vmax, numBins);
373  tools::accumulate(iter, op, threaded);
374  return op.hist;
375 }
376 
377 template<typename IterT>
378 inline math::Extrema
379 extrema(const IterT& iter, bool threaded)
380 {
382  return extrema(iter, valOp, threaded);
383 }
384 
385 template<typename IterT>
386 inline math::Stats
387 statistics(const IterT& iter, bool threaded)
388 {
390  return statistics(iter, valOp, threaded);
391 }
392 
393 template<typename IterT, typename ValueOp>
394 inline math::Extrema
395 extrema(const IterT& iter, const ValueOp& valOp, bool threaded)
396 {
398  tools::accumulate(iter, op, threaded);
399  return op.stats;
400 }
401 
402 template<typename IterT, typename ValueOp>
403 inline math::Stats
404 statistics(const IterT& iter, const ValueOp& valOp, bool threaded)
405 {
407  tools::accumulate(iter, op, threaded);
408  return op.stats;
409 }
410 
411 
412 template<typename OperatorT, typename IterT>
413 inline math::Extrema
414 opExtrema(const IterT& iter, const OperatorT& op, bool threaded)
415 {
417  tools::accumulate(iter, func, threaded);
418  return func.mStats;
419 }
420 
421 template<typename OperatorT, typename IterT>
422 inline math::Stats
423 opStatistics(const IterT& iter, const OperatorT& op, bool threaded)
424 {
426  tools::accumulate(iter, func, threaded);
427  return func.mStats;
428 }
429 
430 } // namespace tools
431 } // namespace OPENVDB_VERSION_NAME
432 } // namespace openvdb
433 
434 #endif // OPENVDB_TOOLS_STATISTICS_HAS_BEEN_INCLUDED
435 
436 // Copyright (c) 2012-2017 DreamWorks Animation LLC
437 // All rights reserved. This software is distributed under the
438 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
math::Stats opStatistics(const IterT &iter, const OperatorT &op=OperatorT(), bool threaded=true)
Iterate over a grid and compute statistics (mean, variance, etc.) of the values produced by applying ...
Definition: Statistics.h:423
math::Stats statistics(const IterT &iter, bool threaded=true)
Iterate over a scalar grid and compute statistics (mean, variance, etc.) of the values of the voxels ...
Definition: Statistics.h:387
png_voidp ptr
Definition: png.h:2145
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:847
GetValImpl< ValueT, VecTraits< ValueT >::IsVec > ImplT
Definition: Statistics.h:263
GLint y
Definition: glcorearb.h:102
HistOp(const ValueOp &op, double vmin, double vmax, size_t bins)
Definition: Statistics.h:294
Classes to compute statistics and histograms.
#define OPENVDB_VERSION_NAME
Definition: version.h:43
This class computes statistics (minimum value, maximum value, mean, variance and standard deviation) ...
Definition: Stats.h:195
void operator()(const IterT &iter, StatsT &stats) const
Definition: Statistics.h:265
This class computes a histogram, with a fixed interval width, of a population of floating-point value...
Definition: Stats.h:292
void accumulate(const IterT &iter, XformOp &op, bool threaded=true)
GLenum func
Definition: glcorearb.h:782
GLint GLenum GLint x
Definition: glcorearb.h:408
GLuint GLfloat * val
Definition: glcorearb.h:1607
math::Extrema opExtrema(const IterT &iter, const OperatorT &op=OperatorT(), bool threaded=true)
Same as opStatistics except it returns a math::Extrema vs a math::Stats.
Definition: Statistics.h:414
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
math::Histogram histogram(const IterT &iter, double minVal, double maxVal, size_t numBins=10, bool threaded=true)
Iterate over a scalar grid and compute a histogram of the values of the voxels that are visited...
Definition: Statistics.h:368
bool add(double val, uint64_t n=1)
Add n samples with constant value val, provided that the val falls within this histogram's value rang...
Definition: Stats.h:325
math::Extrema extrema(const IterT &iter, bool threaded=true)
Iterate over a scalar grid and compute extrema (min/max) of the values of the voxels that are visited...
Definition: Statistics.h:379
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:101
This class computes the minimum and maximum values of a population of floating-point values...
Definition: Stats.h:105