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 
Types.h
LevelSetFilter.h
Performs various types of level set deformations with interface tracking. These unrestricted deformat...
openvdb::v8_1::tools::topologyToLevelSet
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
openvdb::v8_1::tools::IGNORE_TILES
@ IGNORE_TILES
Definition: Morphology.h:78
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:178
openvdb::v8_1::tools::NN_FACE
@ NN_FACE
Definition: Morphology.h:56
openvdb::v8_1::tools::ttls_internal::OffsetAndMinComp
Definition: TopologyToLevelSet.h:103
openvdb::v8_1::tools::dilateActiveValues
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
openvdb::v8_1::util::NullInterrupter
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:25
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: openvdb/Exceptions.h:74
openvdb::v8_1::tools::pruneInactive
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.h
openvdb::v8_1::tools::ttls_internal::normalizeLevelSet
void normalizeLevelSet(GridType &grid, const int halfWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:143
openvdb::v8_1::tools::ttls_internal::DilateOp::tree
TreeT * tree
Definition: TopologyToLevelSet.h:84
openvdb::v8_1::tree::ValueAccessor
Definition: ValueAccessor.h:182
openvdb::v8_1::tree::ValueAccessor::probeConstLeaf
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:384
openvdb::v8_1::tools::pruneLevelSet
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
FiniteDifference.h
openvdb::v8_1::tools::ttls_internal::ErodeOp::operator()
void operator()() const
Definition: TopologyToLevelSet.h:93
openvdb::v8_1::ValueError
Definition: openvdb/Exceptions.h:65
openvdb::v8_1::tools::LevelSetTracker< GridT, util::NullInterrupter >::normalize
void normalize(const MaskType *mask)
Iterative normalization, i.e. solving the Eikonal equation.
openvdb::v8_1::tools::LevelSetFilter
Filtering (e.g. diffusion) of narrow-band level sets. An optional scalar field can be used to produce...
Definition: LevelSetFilter.h:39
NullInterrupter.h
openvdb::v8_1::tools::ttls_internal::DilateOp::DilateOp
DilateOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:80
openvdb::v8_1::math::FIRST_BIAS
@ FIRST_BIAS
Definition: FiniteDifference.h:167
openvdb::v8_1::GRID_LEVEL_SET
@ GRID_LEVEL_SET
Definition: openvdb/Types.h:333
openvdb::v8_1::tools::ttls_internal::OffsetAndMinComp::ValueType
typename TreeType::ValueType ValueType
Definition: TopologyToLevelSet.h:106
openvdb::v8_1::tools::LevelSetTracker< GridT, util::NullInterrupter >::setNormCount
void setNormCount(int n)
Set the number of normalizations performed per track or normalize call.
Definition: LevelSetTracker.h:159
openvdb::v8_1::tools::ttls_internal::ErodeOp
Definition: TopologyToLevelSet.h:90
openvdb::v8_1::tools::erodeActiveValues
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
openvdb::v8_1::tools::ttls_internal::smoothLevelSet
void smoothLevelSet(GridType &grid, int iterations, int halfBandWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:155
openvdb::v8_1::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
openvdb::v8_1::tools::ttls_internal::DilateOp
Definition: TopologyToLevelSet.h:78
openvdb::v8_1::tools::ttls_internal::OffsetAndMinComp::OffsetAndMinComp
OffsetAndMinComp(std::vector< LeafNodeType * > &lhsNodes, const TreeType &rhsTree, ValueType offset)
Definition: TopologyToLevelSet.h:108
SignedFloodFill.h
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
openvdb::v8_1::tools::ttls_internal::ErodeOp::tree
TreeT * tree
Definition: TopologyToLevelSet.h:97
openvdb::v8_1::tools::ttls_internal::DilateOp::operator()
void operator()() const
Definition: TopologyToLevelSet.h:81
openvdb::v8_1::tools::LevelSetFilter::mean
void mean(int width=1, const MaskType *mask=nullptr)
One iteration of mean-value flow of the level set.
Definition: LevelSetFilter.h:140
Morphology.h
Implementation of morphological dilation and erosion.
openvdb::v8_1::tools::ttls_internal::ErodeOp::size
const int size
Definition: TopologyToLevelSet.h:98
openvdb::v8_1::tools::LevelSetTracker< GridT, util::NullInterrupter >::prune
void prune()
Set voxels that are outside the narrow band to the background value (if trimming is enabled) and prun...
Definition: LevelSetTracker.h:280
openvdb::v8_1::tools::ttls_internal::OffsetAndMinComp::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: TopologyToLevelSet.h:114
openvdb::v8_1::tools::ttls_internal::DilateOp::size
const int size
Definition: TopologyToLevelSet.h:85
openvdb::v8_1::tools::LevelSetTracker< GridT, util::NullInterrupter >::setSpatialScheme
void setSpatialScheme(math::BiasedGradientScheme s)
Set the spatial finite difference scheme.
Definition: LevelSetTracker.h:145
openvdb::v8_1::tools::ttls_internal::ErodeOp::ErodeOp
ErodeOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:92
openvdb
Definition: openvdb/Exceptions.h:13
openvdb::v8_1::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
openvdb::v8_1::Grid
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
openvdb::v8_1::tools::ttls_internal::OffsetAndMinComp::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: TopologyToLevelSet.h:105