HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TopologyToLevelSet.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 TopologyToLevelSet.h
32 ///
33 /// @brief This tool generates a narrow-band signed distance field / level set
34 /// from the interface between active and inactive voxels in a vdb grid.
35 ///
36 /// @par Example:
37 /// Combine with @c tools::PointsToVolume for fast point cloud to level set conversion.
38 
39 #ifndef OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
40 #define OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
41 
42 #include "LevelSetFilter.h"
43 #include "Morphology.h" // for erodeVoxels and dilateActiveValues
44 #include "SignedFloodFill.h"
45 
46 #include <openvdb/Grid.h>
47 #include <openvdb/Types.h>
48 #include <openvdb/math/FiniteDifference.h> // for math::BiasedGradientScheme
50 
51 #include <tbb/task_group.h>
52 
53 
54 namespace openvdb {
56 namespace OPENVDB_VERSION_NAME {
57 namespace tools {
58 
59 
60 /// @brief Compute the narrow-band signed distance to the interface between
61 /// active and inactive voxels in the input grid.
62 ///
63 /// @return A shared pointer to a new sdf / level set grid of type @c float
64 ///
65 /// @param grid Input grid of arbitrary type whose active voxels are used
66 /// in constructing the level set.
67 /// @param halfWidth Half the width of the narrow band in voxel units.
68 /// @param closingSteps Number of morphological closing steps used to fill gaps
69 /// in the active voxel region.
70 /// @param dilation Number of voxels to expand the active voxel region.
71 /// @param smoothingSteps Number of smoothing interations.
72 template<typename GridT>
73 inline typename GridT::template ValueConverter<float>::Type::Ptr
74 topologyToLevelSet(const GridT& grid, int halfWidth = 3, int closingSteps = 1, int dilation = 0,
75  int smoothingSteps = 0);
76 
77 
78 /// @brief Compute the narrow-band signed distance to the interface between
79 /// active and inactive voxels in the input grid.
80 ///
81 /// @return A shared pointer to a new sdf / level set grid of type @c float
82 ///
83 /// @param grid Input grid of arbitrary type whose active voxels are used
84 /// in constructing the level set.
85 /// @param halfWidth Half the width of the narrow band in voxel units.
86 /// @param closingSteps Number of morphological closing steps used to fill gaps
87 /// in the active voxel region.
88 /// @param dilation Number of voxels to expand the active voxel region.
89 /// @param smoothingSteps Number of smoothing interations.
90 /// @param interrupt Optional object adhering to the util::NullInterrupter interface.
91 template<typename GridT, typename InterrupterT>
92 inline typename GridT::template ValueConverter<float>::Type::Ptr
93 topologyToLevelSet(const GridT& grid, int halfWidth = 3, int closingSteps = 1, int dilation = 0,
94  int smoothingSteps = 0, InterrupterT* interrupt = NULL);
95 
96 
97 ////////////////////////////////////////
98 
99 
100 namespace ttls_internal {
101 
102 
103 template<typename TreeT>
104 struct DilateOp
105 {
106  DilateOp(TreeT& t, int n) : tree(&t), size(n) {}
107  void operator()() const {
109  }
110  TreeT* tree;
111  const int size;
112 };
113 
114 
115 template<typename TreeT>
116 struct ErodeOp
117 {
118  ErodeOp(TreeT& t, int n) : tree(&t), size(n) {}
119  void operator()() const { erodeVoxels( *tree, size); }
120  TreeT* tree;
121  const int size;
122 };
123 
124 
125 template<typename TreeType>
127 {
128  typedef typename TreeType::LeafNodeType LeafNodeType;
129  typedef typename TreeType::ValueType ValueType;
130 
131  OffsetAndMinComp(std::vector<LeafNodeType*>& lhsNodes, const TreeType& rhsTree, ValueType offset)
132  : mLhsNodes(lhsNodes.empty() ? NULL : &lhsNodes[0]), mRhsTree(&rhsTree), mOffset(offset)
133  {
134  }
135 
136  void operator()(const tbb::blocked_range<size_t>& range) const
137  {
138  typedef typename LeafNodeType::ValueOnIter Iterator;
139 
140  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
141  const ValueType offset = mOffset;
142 
143  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
144 
145  LeafNodeType& lhsNode = *mLhsNodes[n];
146  const LeafNodeType * rhsNodePt = rhsAcc.probeConstLeaf(lhsNode.origin());
147  if (!rhsNodePt) continue;
148 
149  for (Iterator it = lhsNode.beginValueOn(); it; ++it) {
150  ValueType& val = const_cast<ValueType&>(it.getValue());
151  val = std::min(val, offset + rhsNodePt->getValue(it.pos()));
152  }
153  }
154  }
155 
156 private:
157  LeafNodeType * * const mLhsNodes;
158  TreeType const * const mRhsTree;
159  ValueType const mOffset;
160 }; // struct OffsetAndMinComp
161 
162 
163 template<typename GridType, typename InterrupterType>
164 inline void
165 normalizeLevelSet(GridType& grid, const int halfWidthInVoxels, InterrupterType* interrupt = NULL)
166 {
169  filter.setNormCount(halfWidthInVoxels);
170  filter.normalize();
171  filter.prune();
172 }
173 
174 
175 template<typename GridType, typename InterrupterType>
176 inline void
177 smoothLevelSet(GridType& grid, int iterations, int halfBandWidthInVoxels, InterrupterType* interrupt = NULL)
178 {
179  typedef typename GridType::ValueType ValueType;
180  typedef typename GridType::TreeType TreeType;
181  typedef typename TreeType::LeafNodeType LeafNodeType;
182 
183  GridType filterGrid(grid);
184 
187 
188  for (int n = 0; n < iterations; ++n) {
189  if (interrupt && interrupt->wasInterrupted()) break;
190  filter.mean(1);
191  }
192 
193  std::vector<LeafNodeType*> nodes;
194  grid.tree().getNodes(nodes);
195 
196  const ValueType offset = ValueType(double(0.5) * grid.transform().voxelSize()[0]);
197 
198  tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
199  OffsetAndMinComp<TreeType>(nodes, filterGrid.tree(), -offset));
200 
201  // Clean up any damanage that was done by the min operation
202  normalizeLevelSet(grid, halfBandWidthInVoxels, interrupt);
203 }
204 
205 
206 } // namespace ttls_internal
207 
208 
209 
210 template<typename GridT, typename InterrupterT>
211 inline typename GridT::template ValueConverter<float>::Type::Ptr
212 topologyToLevelSet(const GridT& grid, int halfWidth, int closingSteps, int dilation,
213  int smoothingSteps, InterrupterT* interrupt)
214 {
215  typedef typename GridT::TreeType::template ValueConverter<ValueMask>::Type MaskTreeT;
216  typedef typename GridT::TreeType::template ValueConverter<float>::Type FloatTreeT;
217  typedef Grid<FloatTreeT> FloatGridT;
218 
219  // Check inputs
220 
221  halfWidth = std::max(halfWidth, 1);
222  closingSteps = std::max(closingSteps, 0);
223  dilation = std::max(dilation, 0);
224 
225  if ( !grid.hasUniformVoxels() ) {
226  OPENVDB_THROW(ValueError, "Non-uniform voxels are not supported!");
227  }
228 
229  // Copy the topology into a MaskGrid.
230  MaskTreeT maskTree( grid.tree(), false/*background*/, openvdb::TopologyCopy() );
231 
232  // Morphological closing operation.
233  dilateActiveValues( maskTree, closingSteps + dilation, tools::NN_FACE, tools::IGNORE_TILES );
234  erodeVoxels( maskTree, closingSteps );
235 
236  // Generate a volume with an implicit zero crossing at the boundary
237  // between active and inactive values in the input grid.
238  const float background = float(grid.voxelSize()[0]) * float(halfWidth);
239  typename FloatTreeT::Ptr lsTree(
240  new FloatTreeT( maskTree, /*out=*/background, /*in=*/-background, openvdb::TopologyCopy() ) );
241 
242  tbb::task_group pool;
243  pool.run( ttls_internal::ErodeOp< MaskTreeT >( maskTree, halfWidth ) );
244  pool.run( ttls_internal::DilateOp<FloatTreeT>( *lsTree , halfWidth ) );
245  pool.wait();// wait for both tasks to complete
246 
247  lsTree->topologyDifference( maskTree );
248  tools::pruneLevelSet( *lsTree, /*threading=*/true);
249 
250  // Create a level set grid from the tree
251  typename FloatGridT::Ptr lsGrid = FloatGridT::create( lsTree );
252  lsGrid->setTransform( grid.transform().copy() );
253  lsGrid->setGridClass( openvdb::GRID_LEVEL_SET );
254 
255  // Use a PDE based scheme to propagate distance values from the
256  // implicit zero crossing.
257  ttls_internal::normalizeLevelSet(*lsGrid, 3*halfWidth, interrupt);
258 
259  // Additional filtering
260  if (smoothingSteps > 0) {
261  ttls_internal::smoothLevelSet(*lsGrid, smoothingSteps, halfWidth, interrupt);
262  }
263 
264  return lsGrid;
265 }
266 
267 
268 template<typename GridT>
269 inline typename GridT::template ValueConverter<float>::Type::Ptr
270 topologyToLevelSet(const GridT& grid, int halfWidth, int closingSteps, int dilation, int smoothingSteps)
271 {
272  util::NullInterrupter interrupt;
273  return topologyToLevelSet(grid, halfWidth, closingSteps, dilation, smoothingSteps, &interrupt);
274 }
275 
276 
277 } // namespace tools
278 } // namespace OPENVDB_VERSION_NAME
279 } // namespace openvdb
280 
281 #endif // OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
282 
283 
284 // Copyright (c) 2012-2017 DreamWorks Animation LLC
285 // All rights reserved. This software is distributed under the
286 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
GLenum GLint * range
Definition: glcorearb.h:1924
Filtering (e.g. diffusion) of narrow-band level sets. An optional scalar field can be used to produce...
void prune()
Remove voxels that are outside the narrow band. (substep of track)
const hboost::disable_if_c< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:128
void mean(int width=1, const MaskType *mask=nullptr)
One iteration of mean-value flow of the level set.
png_infop png_color_16p * background
Definition: png.h:2326
Dummy NOOP interrupter class defining interface.
GLsizeiptr size
Definition: glcorearb.h:663
const hboost::disable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:132
void setNormCount(int n)
Set the number of normalizations performed per track or normalize call.
SYS_FORCE_INLINE const_iterator end() const
GLdouble n
Definition: glcorearb.h:2007
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
OffsetAndMinComp(std::vector< LeafNodeType * > &lhsNodes, const TreeType &rhsTree, ValueType offset)
void setSpatialScheme(math::BiasedGradientScheme scheme)
Set the spatial finite difference scheme.
#define OPENVDB_VERSION_NAME
Definition: version.h:43
GLintptr offset
Definition: glcorearb.h:664
void smoothLevelSet(GridType &grid, int iterations, int halfBandWidthInVoxels, InterrupterType *interrupt=NULL)
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:54
Propagates the sign of distance values from the active voxels in the narrow band to the inactive valu...
OPENVDB_STATIC_SPECIALIZATION void erodeVoxels(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE)
Topologically erode all leaf-level active voxels in the given tree.
Definition: Morphology.h:875
void normalizeLevelSet(GridType &grid, const int halfWidthInVoxels, InterrupterType *interrupt=NULL)
GridT::template ValueConverter< float >::Type::Ptr topologyToLevelSet(const GridT &grid, int halfWidth=3, int closingSteps=1, int dilation=0, int smoothingSteps=0)
Compute the narrow-band signed distance to the interface between active and inactive voxels in the in...
GLuint GLfloat * val
Definition: glcorearb.h:1607
GA_API const UT_StringHolder N
Implementation of morphological dilation and erosion.
Performs various types of level set deformations with interface tracking. These unrestricted deformat...
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
void pruneLevelSet(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing nodes whose values are all inactive with inactive ...
Definition: Prune.h:429
void normalize(const MaskType *mask)
Iterative normalization, i.e. solving the Eikonal equation.
OPENVDB_STATIC_SPECIALIZATION void dilateActiveValues(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE, TilePolicy mode=PRESERVE_TILES)
Topologically dilate all active values (i.e. both voxels and tiles) in a tree using one of three near...
Definition: Morphology.h:1074
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:101
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1296
void operator()(const tbb::blocked_range< size_t > &range) const