OpenVDB  7.0.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 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 
void setNormCount(int n)
Set the number of normalizations performed per track or normalize call.
Definition: LevelSetTracker.h:159
OffsetAndMinComp(std::vector< LeafNodeType * > &lhsNodes, const TreeType &rhsTree, ValueType offset)
Definition: TopologyToLevelSet.h:105
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
const int size
Definition: TopologyToLevelSet.h:95
TreeT * tree
Definition: TopologyToLevelSet.h:84
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:82
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
Definition: TopologyToLevelSet.h:100
Definition: TopologyToLevelSet.h:90
DilateOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:80
Performs various types of level set deformations with interface tracking. These unrestricted deformat...
Definition: Exceptions.h:65
void prune()
Set voxels that are outside the narrow band to the background value (if trimming is enabled) and prun...
Definition: LevelSetTracker.h:280
TreeT * tree
Definition: TopologyToLevelSet.h:94
void setSpatialScheme(math::BiasedGradientScheme s)
Set the spatial finite difference scheme.
Definition: LevelSetTracker.h:145
void normalizeLevelSet(GridType &grid, const int halfWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:140
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
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:102
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
Implementation of morphological dilation and erosion.
Definition: Exceptions.h:13
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: TopologyToLevelSet.h:111
void mean(int width=1, const MaskType *mask=nullptr)
One iteration of mean-value flow of the level set.
Definition: LevelSetFilter.h:140
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:25
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:395
void smoothLevelSet(GridType &grid, int iterations, int halfBandWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:152
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:681
void operator()() const
Definition: TopologyToLevelSet.h:81
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:102
Definition: Morphology.h:75
Definition: FiniteDifference.h:167
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 normalize(const MaskType *mask)
Iterative normalization, i.e. solving the Eikonal equation.
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:154
void operator()() const
Definition: TopologyToLevelSet.h:93
Filtering (e.g. diffusion) of narrow-band level sets. An optional scalar field can be used to produce...
Definition: LevelSetFilter.h:39
Definition: Morphology.h:60
Definition: TopologyToLevelSet.h:78
typename TreeType::ValueType ValueType
Definition: TopologyToLevelSet.h:103
Definition: Types.h:454
const int size
Definition: TopologyToLevelSet.h:85
typename TreeType::LeafNodeType LeafNodeType
Definition: TopologyToLevelSet.h:102
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:106
ErodeOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:92