HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TopologyToLevelSet.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2012-2018 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-2018 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()
Set voxels that are outside the narrow band to the background value (if trimming is enabled) and prun...
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
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:189
Dummy NOOP interrupter class defining interface.
GLsizeiptr size
Definition: glcorearb.h:663
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)
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
GLintptr offset
Definition: glcorearb.h:664
void setSpatialScheme(math::BiasedGradientScheme s)
Set the spatial finite difference scheme.
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:55
Propagate the signs 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:878
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...
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:416
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:135
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:1079
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1296
void operator()(const tbb::blocked_range< size_t > &range) const