OpenVDB  8.0.1
TopologyToLevelSet.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
11 
12 #ifndef OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
13 #define OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
14 
15 #include "LevelSetFilter.h"
16 #include "Morphology.h" // for erodeVoxels and dilateActiveValues
17 #include "SignedFloodFill.h"
18 
19 #include <openvdb/Grid.h>
20 #include <openvdb/Types.h>
21 #include <openvdb/math/FiniteDifference.h> // for math::BiasedGradientScheme
23 #include <tbb/task_group.h>
24 #include <algorithm> // for std::min(), std::max()
25 #include <vector>
26 
27 
28 namespace openvdb {
30 namespace OPENVDB_VERSION_NAME {
31 namespace tools {
32 
33 
46 template<typename GridT>
47 inline typename GridT::template ValueConverter<float>::Type::Ptr
48 topologyToLevelSet(const GridT& grid, int halfWidth = 3, int closingSteps = 1, int dilation = 0,
49  int smoothingSteps = 0);
50 
51 
65 template<typename GridT, typename InterrupterT>
66 inline typename GridT::template ValueConverter<float>::Type::Ptr
67 topologyToLevelSet(const GridT& grid, int halfWidth = 3, int closingSteps = 1, int dilation = 0,
68  int smoothingSteps = 0, InterrupterT* interrupt = nullptr);
69 
70 
72 
73 
74 namespace ttls_internal {
75 
76 
77 template<typename TreeT>
78 struct DilateOp
79 {
80  DilateOp(TreeT& t, int n) : tree(&t), size(n) {}
81  void operator()() const {
83  }
84  TreeT* tree;
85  const int size;
86 };
87 
88 
89 template<typename TreeT>
90 struct ErodeOp
91 {
92  ErodeOp(TreeT& t, int n) : tree(&t), size(n) {}
93  void operator()() const { erodeVoxels( *tree, size); }
94  TreeT* tree;
95  const int size;
96 };
97 
98 
99 template<typename TreeType>
101 {
102  using LeafNodeType = typename TreeType::LeafNodeType;
103  using ValueType = typename TreeType::ValueType;
104 
105  OffsetAndMinComp(std::vector<LeafNodeType*>& lhsNodes,
106  const TreeType& rhsTree, ValueType offset)
107  : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes[0]), mRhsTree(&rhsTree), mOffset(offset)
108  {
109  }
110 
111  void operator()(const tbb::blocked_range<size_t>& range) const
112  {
113  using Iterator = typename LeafNodeType::ValueOnIter;
114 
115  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
116  const ValueType offset = mOffset;
117 
118  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
119 
120  LeafNodeType& lhsNode = *mLhsNodes[n];
121  const LeafNodeType * rhsNodePt = rhsAcc.probeConstLeaf(lhsNode.origin());
122  if (!rhsNodePt) continue;
123 
124  for (Iterator it = lhsNode.beginValueOn(); it; ++it) {
125  ValueType& val = const_cast<ValueType&>(it.getValue());
126  val = std::min(val, offset + rhsNodePt->getValue(it.pos()));
127  }
128  }
129  }
130 
131 private:
132  LeafNodeType * * const mLhsNodes;
133  TreeType const * const mRhsTree;
134  ValueType const mOffset;
135 }; // struct OffsetAndMinComp
136 
137 
138 template<typename GridType, typename InterrupterType>
139 inline void
140 normalizeLevelSet(GridType& grid, const int halfWidthInVoxels, InterrupterType* interrupt = nullptr)
141 {
144  filter.setNormCount(halfWidthInVoxels);
145  filter.normalize();
146  filter.prune();
147 }
148 
149 
150 template<typename GridType, typename InterrupterType>
151 inline void
152 smoothLevelSet(GridType& grid, int iterations, int halfBandWidthInVoxels,
153  InterrupterType* interrupt = nullptr)
154 {
155  using ValueType = typename GridType::ValueType;
156  using TreeType = typename GridType::TreeType;
157  using LeafNodeType = typename TreeType::LeafNodeType;
158 
159  GridType filterGrid(grid);
160 
161  LevelSetFilter<GridType, GridType, InterrupterType> filter(filterGrid, interrupt);
163 
164  for (int n = 0; n < iterations; ++n) {
165  if (interrupt && interrupt->wasInterrupted()) break;
166  filter.mean(1);
167  }
168 
169  std::vector<LeafNodeType*> nodes;
170  grid.tree().getNodes(nodes);
171 
172  const ValueType offset = ValueType(double(0.5) * grid.transform().voxelSize()[0]);
173 
174  tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
175  OffsetAndMinComp<TreeType>(nodes, filterGrid.tree(), -offset));
176 
177  // Clean up any damanage that was done by the min operation
178  normalizeLevelSet(grid, halfBandWidthInVoxels, interrupt);
179 }
180 
181 
182 } // namespace ttls_internal
183 
184 
185 
186 template<typename GridT, typename InterrupterT>
187 inline typename GridT::template ValueConverter<float>::Type::Ptr
188 topologyToLevelSet(const GridT& grid, int halfWidth, int closingSteps, int dilation,
189  int smoothingSteps, InterrupterT* interrupt)
190 {
191  using MaskTreeT = typename GridT::TreeType::template ValueConverter<ValueMask>::Type;
192  using FloatTreeT = typename GridT::TreeType::template ValueConverter<float>::Type;
193  using FloatGridT = Grid<FloatTreeT>;
194 
195  // Check inputs
196 
197  halfWidth = std::max(halfWidth, 1);
198  closingSteps = std::max(closingSteps, 0);
199  dilation = std::max(dilation, 0);
200 
201  if (!grid.hasUniformVoxels()) {
202  OPENVDB_THROW(ValueError, "Non-uniform voxels are not supported!");
203  }
204 
205  // Copy the topology into a MaskGrid.
206  MaskTreeT maskTree( grid.tree(), false/*background*/, openvdb::TopologyCopy() );
207 
208  // Morphological closing operation.
209  dilateActiveValues( maskTree, closingSteps + dilation, tools::NN_FACE, tools::IGNORE_TILES );
210  erodeVoxels( maskTree, closingSteps );
211 
212  // Generate a volume with an implicit zero crossing at the boundary
213  // between active and inactive values in the input grid.
214  const float background = float(grid.voxelSize()[0]) * float(halfWidth);
215  typename FloatTreeT::Ptr lsTree(
216  new FloatTreeT( maskTree, /*out=*/background, /*in=*/-background, openvdb::TopologyCopy() ) );
217 
218  tbb::task_group pool;
219  pool.run( ttls_internal::ErodeOp< MaskTreeT >( maskTree, halfWidth ) );
220  pool.run( ttls_internal::DilateOp<FloatTreeT>( *lsTree , halfWidth ) );
221  pool.wait();// wait for both tasks to complete
222 
223  lsTree->topologyDifference( maskTree );
224  tools::pruneLevelSet( *lsTree, /*threading=*/true);
225 
226  // Create a level set grid from the tree
227  typename FloatGridT::Ptr lsGrid = FloatGridT::create( lsTree );
228  lsGrid->setTransform( grid.transform().copy() );
229  lsGrid->setGridClass( openvdb::GRID_LEVEL_SET );
230 
231  // Use a PDE based scheme to propagate distance values from the
232  // implicit zero crossing.
233  ttls_internal::normalizeLevelSet(*lsGrid, 3*halfWidth, interrupt);
234 
235  // Additional filtering
236  if (smoothingSteps > 0) {
237  ttls_internal::smoothLevelSet(*lsGrid, smoothingSteps, halfWidth, interrupt);
238  }
239 
240  return lsGrid;
241 }
242 
243 
244 template<typename GridT>
245 inline typename GridT::template ValueConverter<float>::Type::Ptr
246 topologyToLevelSet(const GridT& grid, int halfWidth, int closingSteps, int dilation, int smoothingSteps)
247 {
248  util::NullInterrupter interrupt;
249  return topologyToLevelSet(grid, halfWidth, closingSteps, dilation, smoothingSteps, &interrupt);
250 }
251 
252 
253 } // namespace tools
254 } // namespace OPENVDB_VERSION_NAME
255 } // namespace openvdb
256 
257 #endif // OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
258 
Performs various types of level set deformations with interface tracking. These unrestricted deformat...
Implementation of morphological dilation and erosion.
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:577
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: openvdb/Types.h:542
Definition: openvdb/Exceptions.h:65
Filtering (e.g. diffusion) of narrow-band level sets. An optional scalar field can be used to produce...
Definition: LevelSetFilter.h:40
void mean(int width=1, const MaskType *mask=nullptr)
One iteration of mean-value flow of the level set.
Definition: LevelSetFilter.h:140
void prune()
Set voxels that are outside the narrow band to the background value (if trimming is enabled) and prun...
Definition: LevelSetTracker.h:280
void normalize(const MaskType *mask)
Iterative normalization, i.e. solving the Eikonal equation.
void setSpatialScheme(math::BiasedGradientScheme s)
Set the spatial finite difference scheme.
Definition: LevelSetTracker.h:145
void setNormCount(int n)
Set the number of normalizations performed per track or normalize call.
Definition: LevelSetTracker.h:159
Definition: ValueAccessor.h:183
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:384
@ FIRST_BIAS
Definition: FiniteDifference.h:167
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
void normalizeLevelSet(GridType &grid, const int halfWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:140
void smoothLevelSet(GridType &grid, int iterations, int halfBandWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:152
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:188
@ NN_FACE
Definition: Morphology.h:60
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:1047
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:389
@ IGNORE_TILES
Definition: Morphology.h:75
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:846
@ GRID_LEVEL_SET
Definition: openvdb/Types.h:315
Definition: openvdb/Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: openvdb/Exceptions.h:74
Definition: TopologyToLevelSet.h:79
DilateOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:80
TreeT * tree
Definition: TopologyToLevelSet.h:84
const int size
Definition: TopologyToLevelSet.h:85
void operator()() const
Definition: TopologyToLevelSet.h:81
Definition: TopologyToLevelSet.h:91
ErodeOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:92
TreeT * tree
Definition: TopologyToLevelSet.h:94
const int size
Definition: TopologyToLevelSet.h:95
void operator()() const
Definition: TopologyToLevelSet.h:93
Definition: TopologyToLevelSet.h:101
typename TreeType::ValueType ValueType
Definition: TopologyToLevelSet.h:103
OffsetAndMinComp(std::vector< LeafNodeType * > &lhsNodes, const TreeType &rhsTree, ValueType offset)
Definition: TopologyToLevelSet.h:105
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: TopologyToLevelSet.h:111
typename TreeType::LeafNodeType LeafNodeType
Definition: TopologyToLevelSet.h:102
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:26
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:101
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:153