OpenVDB  8.1.0
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 erodeActiveValues 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 {
94  tools::erodeActiveValues(*tree, /*iterations=*/size, tools::NN_FACE, tools::IGNORE_TILES);
95  tools::pruneInactive(*tree);
96  }
97  TreeT* tree;
98  const int size;
99 };
100 
101 
102 template<typename TreeType>
104 {
105  using LeafNodeType = typename TreeType::LeafNodeType;
106  using ValueType = typename TreeType::ValueType;
107 
108  OffsetAndMinComp(std::vector<LeafNodeType*>& lhsNodes,
109  const TreeType& rhsTree, ValueType offset)
110  : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes[0]), mRhsTree(&rhsTree), mOffset(offset)
111  {
112  }
113 
114  void operator()(const tbb::blocked_range<size_t>& range) const
115  {
116  using Iterator = typename LeafNodeType::ValueOnIter;
117 
118  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
119  const ValueType offset = mOffset;
120 
121  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
122 
123  LeafNodeType& lhsNode = *mLhsNodes[n];
124  const LeafNodeType * rhsNodePt = rhsAcc.probeConstLeaf(lhsNode.origin());
125  if (!rhsNodePt) continue;
126 
127  for (Iterator it = lhsNode.beginValueOn(); it; ++it) {
128  ValueType& val = const_cast<ValueType&>(it.getValue());
129  val = std::min(val, offset + rhsNodePt->getValue(it.pos()));
130  }
131  }
132  }
133 
134 private:
135  LeafNodeType * * const mLhsNodes;
136  TreeType const * const mRhsTree;
137  ValueType const mOffset;
138 }; // struct OffsetAndMinComp
139 
140 
141 template<typename GridType, typename InterrupterType>
142 inline void
143 normalizeLevelSet(GridType& grid, const int halfWidthInVoxels, InterrupterType* interrupt = nullptr)
144 {
147  filter.setNormCount(halfWidthInVoxels);
148  filter.normalize();
149  filter.prune();
150 }
151 
152 
153 template<typename GridType, typename InterrupterType>
154 inline void
155 smoothLevelSet(GridType& grid, int iterations, int halfBandWidthInVoxels,
156  InterrupterType* interrupt = nullptr)
157 {
158  using ValueType = typename GridType::ValueType;
159  using TreeType = typename GridType::TreeType;
160  using LeafNodeType = typename TreeType::LeafNodeType;
161 
162  GridType filterGrid(grid);
163 
164  LevelSetFilter<GridType, GridType, InterrupterType> filter(filterGrid, interrupt);
166 
167  for (int n = 0; n < iterations; ++n) {
168  if (interrupt && interrupt->wasInterrupted()) break;
169  filter.mean(1);
170  }
171 
172  std::vector<LeafNodeType*> nodes;
173  grid.tree().getNodes(nodes);
174 
175  const ValueType offset = ValueType(double(0.5) * grid.transform().voxelSize()[0]);
176 
177  tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
178  OffsetAndMinComp<TreeType>(nodes, filterGrid.tree(), -offset));
179 
180  // Clean up any damanage that was done by the min operation
181  normalizeLevelSet(grid, halfBandWidthInVoxels, interrupt);
182 }
183 
184 
185 } // namespace ttls_internal
186 
187 
188 
189 template<typename GridT, typename InterrupterT>
190 inline typename GridT::template ValueConverter<float>::Type::Ptr
191 topologyToLevelSet(const GridT& grid, int halfWidth, int closingSteps, int dilation,
192  int smoothingSteps, InterrupterT* interrupt)
193 {
194  using MaskTreeT = typename GridT::TreeType::template ValueConverter<ValueMask>::Type;
195  using FloatTreeT = typename GridT::TreeType::template ValueConverter<float>::Type;
196  using FloatGridT = Grid<FloatTreeT>;
197 
198  // Check inputs
199 
200  halfWidth = std::max(halfWidth, 1);
201  closingSteps = std::max(closingSteps, 0);
202  dilation = std::max(dilation, 0);
203 
204  if (!grid.hasUniformVoxels()) {
205  OPENVDB_THROW(ValueError, "Non-uniform voxels are not supported!");
206  }
207 
208  // Copy the topology into a MaskGrid.
209  MaskTreeT maskTree( grid.tree(), false/*background*/, openvdb::TopologyCopy() );
210 
211  // Morphological closing operation.
212  tools::dilateActiveValues(maskTree, closingSteps + dilation, tools::NN_FACE, tools::IGNORE_TILES);
213  tools::erodeActiveValues(maskTree, /*iterations=*/closingSteps, tools::NN_FACE, tools::IGNORE_TILES);
214  tools::pruneInactive(maskTree);
215 
216  // Generate a volume with an implicit zero crossing at the boundary
217  // between active and inactive values in the input grid.
218  const float background = float(grid.voxelSize()[0]) * float(halfWidth);
219  typename FloatTreeT::Ptr lsTree(
220  new FloatTreeT( maskTree, /*out=*/background, /*in=*/-background, openvdb::TopologyCopy() ) );
221 
222  tbb::task_group pool;
223  pool.run( ttls_internal::ErodeOp< MaskTreeT >( maskTree, halfWidth ) );
224  pool.run( ttls_internal::DilateOp<FloatTreeT>( *lsTree , halfWidth ) );
225  pool.wait();// wait for both tasks to complete
226 
227  lsTree->topologyDifference( maskTree );
228  tools::pruneLevelSet( *lsTree, /*threading=*/true);
229 
230  // Create a level set grid from the tree
231  typename FloatGridT::Ptr lsGrid = FloatGridT::create( lsTree );
232  lsGrid->setTransform( grid.transform().copy() );
233  lsGrid->setGridClass( openvdb::GRID_LEVEL_SET );
234 
235  // Use a PDE based scheme to propagate distance values from the
236  // implicit zero crossing.
237  ttls_internal::normalizeLevelSet(*lsGrid, 3*halfWidth, interrupt);
238 
239  // Additional filtering
240  if (smoothingSteps > 0) {
241  ttls_internal::smoothLevelSet(*lsGrid, smoothingSteps, halfWidth, interrupt);
242  }
243 
244  return lsGrid;
245 }
246 
247 
248 template<typename GridT>
249 inline typename GridT::template ValueConverter<float>::Type::Ptr
250 topologyToLevelSet(const GridT& grid, int halfWidth, int closingSteps, int dilation, int smoothingSteps)
251 {
252  util::NullInterrupter interrupt;
253  return topologyToLevelSet(grid, halfWidth, closingSteps, dilation, smoothingSteps, &interrupt);
254 }
255 
256 
257 } // namespace tools
258 } // namespace OPENVDB_VERSION_NAME
259 } // namespace openvdb
260 
261 #endif // OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
262 
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:560
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 & max(const T &a, const T &b)
Definition: Composite.h:107
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
void smoothLevelSet(GridType &grid, int iterations, int halfBandWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:155
void normalizeLevelSet(GridType &grid, const int halfWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:143
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:191
@ NN_FACE
Definition: Morphology.h:56
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
void erodeActiveValues(TreeOrLeafManagerT &tree, const int iterations=1, const NearestNeighbors nn=NN_FACE, const TilePolicy mode=PRESERVE_TILES, const bool threaded=true)
Topologically erode all active values (i.e. both voxels and tiles) in a tree using one of three neare...
Definition: Morphology.h:1126
void dilateActiveValues(TreeOrLeafManagerT &tree, const int iterations=1, const NearestNeighbors nn=NN_FACE, const TilePolicy mode=PRESERVE_TILES, const bool threaded=true)
Topologically dilate all active values (i.e. both voxels and tiles) in a tree using one of three near...
Definition: Morphology.h:1049
@ IGNORE_TILES
Definition: Morphology.h:78
void pruneInactive(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with background tiles any nodes whose values are a...
Definition: Prune.h:354
@ GRID_LEVEL_SET
Definition: openvdb/Types.h:333
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:97
const int size
Definition: TopologyToLevelSet.h:98
void operator()() const
Definition: TopologyToLevelSet.h:93
Definition: TopologyToLevelSet.h:104
typename TreeType::ValueType ValueType
Definition: TopologyToLevelSet.h:106
OffsetAndMinComp(std::vector< LeafNodeType * > &lhsNodes, const TreeType &rhsTree, ValueType offset)
Definition: TopologyToLevelSet.h:108
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: TopologyToLevelSet.h:114
typename TreeType::LeafNodeType LeafNodeType
Definition: TopologyToLevelSet.h:105
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.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:178