OpenVDB  6.1.0
TopologyToLevelSet.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2019 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 //
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 #include <tbb/task_group.h>
51 #include <algorithm> // for std::min(), std::max()
52 #include <vector>
53 
54 
55 namespace openvdb {
57 namespace OPENVDB_VERSION_NAME {
58 namespace tools {
59 
60 
73 template<typename GridT>
74 inline typename GridT::template ValueConverter<float>::Type::Ptr
75 topologyToLevelSet(const GridT& grid, int halfWidth = 3, int closingSteps = 1, int dilation = 0,
76  int smoothingSteps = 0);
77 
78 
92 template<typename GridT, typename InterrupterT>
93 inline typename GridT::template ValueConverter<float>::Type::Ptr
94 topologyToLevelSet(const GridT& grid, int halfWidth = 3, int closingSteps = 1, int dilation = 0,
95  int smoothingSteps = 0, InterrupterT* interrupt = nullptr);
96 
97 
99 
100 
101 namespace ttls_internal {
102 
103 
104 template<typename TreeT>
105 struct DilateOp
106 {
107  DilateOp(TreeT& t, int n) : tree(&t), size(n) {}
108  void operator()() const {
110  }
111  TreeT* tree;
112  const int size;
113 };
114 
115 
116 template<typename TreeT>
117 struct ErodeOp
118 {
119  ErodeOp(TreeT& t, int n) : tree(&t), size(n) {}
120  void operator()() const { erodeVoxels( *tree, size); }
121  TreeT* tree;
122  const int size;
123 };
124 
125 
126 template<typename TreeType>
128 {
129  using LeafNodeType = typename TreeType::LeafNodeType;
130  using ValueType = typename TreeType::ValueType;
131 
132  OffsetAndMinComp(std::vector<LeafNodeType*>& lhsNodes,
133  const TreeType& rhsTree, ValueType offset)
134  : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes[0]), mRhsTree(&rhsTree), mOffset(offset)
135  {
136  }
137 
138  void operator()(const tbb::blocked_range<size_t>& range) const
139  {
140  using Iterator = typename LeafNodeType::ValueOnIter;
141 
142  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
143  const ValueType offset = mOffset;
144 
145  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
146 
147  LeafNodeType& lhsNode = *mLhsNodes[n];
148  const LeafNodeType * rhsNodePt = rhsAcc.probeConstLeaf(lhsNode.origin());
149  if (!rhsNodePt) continue;
150 
151  for (Iterator it = lhsNode.beginValueOn(); it; ++it) {
152  ValueType& val = const_cast<ValueType&>(it.getValue());
153  val = std::min(val, offset + rhsNodePt->getValue(it.pos()));
154  }
155  }
156  }
157 
158 private:
159  LeafNodeType * * const mLhsNodes;
160  TreeType const * const mRhsTree;
161  ValueType const mOffset;
162 }; // struct OffsetAndMinComp
163 
164 
165 template<typename GridType, typename InterrupterType>
166 inline void
167 normalizeLevelSet(GridType& grid, const int halfWidthInVoxels, InterrupterType* interrupt = nullptr)
168 {
171  filter.setNormCount(halfWidthInVoxels);
172  filter.normalize();
173  filter.prune();
174 }
175 
176 
177 template<typename GridType, typename InterrupterType>
178 inline void
179 smoothLevelSet(GridType& grid, int iterations, int halfBandWidthInVoxels,
180  InterrupterType* interrupt = nullptr)
181 {
182  using ValueType = typename GridType::ValueType;
183  using TreeType = typename GridType::TreeType;
184  using LeafNodeType = typename TreeType::LeafNodeType;
185 
186  GridType filterGrid(grid);
187 
188  LevelSetFilter<GridType, GridType, InterrupterType> filter(filterGrid, interrupt);
190 
191  for (int n = 0; n < iterations; ++n) {
192  if (interrupt && interrupt->wasInterrupted()) break;
193  filter.mean(1);
194  }
195 
196  std::vector<LeafNodeType*> nodes;
197  grid.tree().getNodes(nodes);
198 
199  const ValueType offset = ValueType(double(0.5) * grid.transform().voxelSize()[0]);
200 
201  tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
202  OffsetAndMinComp<TreeType>(nodes, filterGrid.tree(), -offset));
203 
204  // Clean up any damanage that was done by the min operation
205  normalizeLevelSet(grid, halfBandWidthInVoxels, interrupt);
206 }
207 
208 
209 } // namespace ttls_internal
210 
211 
212 
213 template<typename GridT, typename InterrupterT>
214 inline typename GridT::template ValueConverter<float>::Type::Ptr
215 topologyToLevelSet(const GridT& grid, int halfWidth, int closingSteps, int dilation,
216  int smoothingSteps, InterrupterT* interrupt)
217 {
218  using MaskTreeT = typename GridT::TreeType::template ValueConverter<ValueMask>::Type;
219  using FloatTreeT = typename GridT::TreeType::template ValueConverter<float>::Type;
220  using FloatGridT = Grid<FloatTreeT>;
221 
222  // Check inputs
223 
224  halfWidth = std::max(halfWidth, 1);
225  closingSteps = std::max(closingSteps, 0);
226  dilation = std::max(dilation, 0);
227 
228  if (!grid.hasUniformVoxels()) {
229  OPENVDB_THROW(ValueError, "Non-uniform voxels are not supported!");
230  }
231 
232  // Copy the topology into a MaskGrid.
233  MaskTreeT maskTree( grid.tree(), false/*background*/, openvdb::TopologyCopy() );
234 
235  // Morphological closing operation.
236  dilateActiveValues( maskTree, closingSteps + dilation, tools::NN_FACE, tools::IGNORE_TILES );
237  erodeVoxels( maskTree, closingSteps );
238 
239  // Generate a volume with an implicit zero crossing at the boundary
240  // between active and inactive values in the input grid.
241  const float background = float(grid.voxelSize()[0]) * float(halfWidth);
242  typename FloatTreeT::Ptr lsTree(
243  new FloatTreeT( maskTree, /*out=*/background, /*in=*/-background, openvdb::TopologyCopy() ) );
244 
245  tbb::task_group pool;
246  pool.run( ttls_internal::ErodeOp< MaskTreeT >( maskTree, halfWidth ) );
247  pool.run( ttls_internal::DilateOp<FloatTreeT>( *lsTree , halfWidth ) );
248  pool.wait();// wait for both tasks to complete
249 
250  lsTree->topologyDifference( maskTree );
251  tools::pruneLevelSet( *lsTree, /*threading=*/true);
252 
253  // Create a level set grid from the tree
254  typename FloatGridT::Ptr lsGrid = FloatGridT::create( lsTree );
255  lsGrid->setTransform( grid.transform().copy() );
256  lsGrid->setGridClass( openvdb::GRID_LEVEL_SET );
257 
258  // Use a PDE based scheme to propagate distance values from the
259  // implicit zero crossing.
260  ttls_internal::normalizeLevelSet(*lsGrid, 3*halfWidth, interrupt);
261 
262  // Additional filtering
263  if (smoothingSteps > 0) {
264  ttls_internal::smoothLevelSet(*lsGrid, smoothingSteps, halfWidth, interrupt);
265  }
266 
267  return lsGrid;
268 }
269 
270 
271 template<typename GridT>
272 inline typename GridT::template ValueConverter<float>::Type::Ptr
273 topologyToLevelSet(const GridT& grid, int halfWidth, int closingSteps, int dilation, int smoothingSteps)
274 {
275  util::NullInterrupter interrupt;
276  return topologyToLevelSet(grid, halfWidth, closingSteps, dilation, smoothingSteps, &interrupt);
277 }
278 
279 
280 } // namespace tools
281 } // namespace OPENVDB_VERSION_NAME
282 } // namespace openvdb
283 
284 #endif // OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
285 
286 
287 // Copyright (c) 2012-2019 DreamWorks Animation LLC
288 // All rights reserved. This software is distributed under the
289 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
Definition: TopologyToLevelSet.h:117
void setSpatialScheme(math::BiasedGradientScheme s)
Set the spatial finite difference scheme.
Definition: LevelSetTracker.h:172
void setNormCount(int n)
Set the number of normalizations performed per track or normalize call.
Definition: LevelSetTracker.h:186
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...
Definition: ValueAccessor.h:422
const int size
Definition: TopologyToLevelSet.h:112
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
Definition: Morphology.h:87
OffsetAndMinComp(std::vector< LeafNodeType * > &lhsNodes, const TreeType &rhsTree, ValueType offset)
Definition: TopologyToLevelSet.h:132
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
void normalize(const MaskType *mask)
Iterative normalization, i.e. solving the Eikonal equation.
void mean(int width=1, const MaskType *mask=nullptr)
One iteration of mean-value flow of the level set.
Definition: LevelSetFilter.h:167
Definition: TopologyToLevelSet.h:127
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
ErodeOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:119
Performs various types of level set deformations with interface tracking. These unrestricted deformat...
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:125
void operator()() const
Definition: TopologyToLevelSet.h:108
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
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:1080
Implementation of morphological dilation and erosion.
Definition: Exceptions.h:40
void prune()
Set voxels that are outside the narrow band to the background value (if trimming is enabled) and prun...
Definition: LevelSetTracker.h:307
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
Definition: Morphology.h:102
void normalizeLevelSet(GridType &grid, const int halfWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:167
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: TopologyToLevelSet.h:138
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:750
typename TreeType::ValueType ValueType
Definition: TopologyToLevelSet.h:130
TreeT * tree
Definition: TopologyToLevelSet.h:111
Definition: Exceptions.h:92
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:879
DilateOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:107
void smoothLevelSet(GridType &grid, int iterations, int halfBandWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:179
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:177
typename TreeType::LeafNodeType LeafNodeType
Definition: TopologyToLevelSet.h:129
const int size
Definition: TopologyToLevelSet.h:122
Definition: Types.h:504
Definition: TopologyToLevelSet.h:105
TreeT * tree
Definition: TopologyToLevelSet.h:121
Filtering (e.g. diffusion) of narrow-band level sets. An optional scalar field can be used to produce...
Definition: LevelSetFilter.h:66
GridT::template ValueConverter< float >::Type::Ptr topologyToLevelSet(const GridT &grid, int halfWidth=3, int closingSteps=1, int dilation=0, int smoothingSteps=0, InterrupterT *interrupt=nullptr)
Compute the narrow-band signed distance to the interface between active and inactive voxels in the in...
Definition: TopologyToLevelSet.h:215
void operator()() const
Definition: TopologyToLevelSet.h:120
Definition: FiniteDifference.h:194