OpenVDB: TopologyToLevelSet.h Source File

OpenVDB 7.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 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
22 #include <openvdb/util/NullInterrupter.h>
23 #include <tbb/task_group.h>
24 #include <algorithm> // for std::min(), std::max()
25 #include <vector>
26
27
28 namespace openvdb {
29 OPENVDB_USE_VERSION_NAMESPACE
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 {
82 dilateActiveValues( *tree, size, tools::NN_FACE, tools::IGNORE_TILES);
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>
100 struct OffsetAndMinComp
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 {
142 LevelSetFilter<GridType, GridType, InterrupterType> filter(grid, interrupt);
143 filter.setSpatialScheme(math::FIRST_BIAS);
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);
162 filter.setSpatialScheme(math::FIRST_BIAS);
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
LevelSetFilter.h
Performs various types of level set deformations with interface tracking. These unrestricted deformat...
openvdb::v7_1::tools::erodeVoxels
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
openvdb::v7_1::tools::LevelSetTracker< GridT, util::NullInterrupter >::normalize
void normalize(const MaskType *mask)
Iterative normalization, i.e. solving the Eikonal equation.
openvdb::v7_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:188
openvdb::v7_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::v7_1::math::FIRST_BIAS
@ FIRST_BIAS
Definition: FiniteDifference.h:167
Types.h
openvdb::v7_1::TopologyCopy
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:1045
openvdb::v7_1::tools::ttls_internal::OffsetAndMinComp::operator()
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: TopologyToLevelSet.h:111
openvdb::v7_1::tools::ttls_internal::DilateOp::DilateOp
DilateOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:80
openvdb::v7_1::tools::ttls_internal::DilateOp::operator()
void operator()() const
Definition: TopologyToLevelSet.h:81
openvdb::v7_1::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:102
openvdb::v7_1::tools::ttls_internal::OffsetAndMinComp
Definition: TopologyToLevelSet.h:101
openvdb::v7_1::tools::dilateActiveValues
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
openvdb::v7_1::tools::ttls_internal::ErodeOp::operator()
void operator()() const
Definition: TopologyToLevelSet.h:93
openvdb::v7_1::tools::IGNORE_TILES
@ IGNORE_TILES
Definition: Morphology.h:75
openvdb::v7_1::tools::ttls_internal::OffsetAndMinComp::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: TopologyToLevelSet.h:102
Grid.h
openvdb::v7_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
openvdb::v7_1::util::NullInterrupter
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:26
openvdb::v7_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::v7_1::Grid
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
openvdb::v7_1::tree::ValueAccessor::probeConstLeaf
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:384
openvdb::v7_1::GRID_LEVEL_SET
@ GRID_LEVEL_SET
Definition: Types.h:818
openvdb::v7_1::tools::ttls_internal::DilateOp::size
const int size
Definition: TopologyToLevelSet.h:85
openvdb::v7_1::tools::ttls_internal::normalizeLevelSet
void normalizeLevelSet(GridType &grid, const int halfWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:140
FiniteDifference.h
openvdb::v7_1::tools::ttls_internal::OffsetAndMinComp::ValueType
typename TreeType::ValueType ValueType
Definition: TopologyToLevelSet.h:103
NullInterrupter.h
openvdb::v7_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
openvdb::v7_1::tools::ttls_internal::smoothLevelSet
void smoothLevelSet(GridType &grid, int iterations, int halfBandWidthInVoxels, InterrupterType *interrupt=nullptr)
Definition: TopologyToLevelSet.h:152
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:146
openvdb::v7_1::tools::ttls_internal::OffsetAndMinComp::OffsetAndMinComp
OffsetAndMinComp(std::vector< LeafNodeType * > &lhsNodes, const TreeType &rhsTree, ValueType offset)
Definition: TopologyToLevelSet.h:105
openvdb::v7_1::tools::ttls_internal::ErodeOp::size
const int size
Definition: TopologyToLevelSet.h:95
SignedFloodFill.h
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
openvdb::v7_1::tools::ttls_internal::DilateOp::tree
TreeT * tree
Definition: TopologyToLevelSet.h:84
openvdb::v7_1::tree::ValueAccessor
Definition: ValueAccessor.h:183
Morphology.h
Implementation of morphological dilation and erosion.
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:94
openvdb::v7_1::tools::LevelSetTracker< GridT, util::NullInterrupter >::setSpatialScheme
void setSpatialScheme(math::BiasedGradientScheme s)
Set the spatial finite difference scheme.
Definition: LevelSetTracker.h:145
openvdb::v7_1::tools::ttls_internal::ErodeOp::ErodeOp
ErodeOp(TreeT &t, int n)
Definition: TopologyToLevelSet.h:92
openvdb::v7_1::tools::ttls_internal::ErodeOp
Definition: TopologyToLevelSet.h:91
openvdb::v7_1::tools::NN_FACE
@ NN_FACE
Definition: Morphology.h:60
openvdb::v7_1::ValueError
Definition: Exceptions.h:65
openvdb
Definition: Exceptions.h:13
openvdb::v7_1::tools::LevelSetFilter
Filtering (e.g. diffusion) of narrow-band level sets. An optional scalar field can be used to produce...
Definition: LevelSetFilter.h:40
openvdb::v7_1::tools::ttls_internal::DilateOp
Definition: TopologyToLevelSet.h:79
openvdb::v7_1::tools::ttls_internal::ErodeOp::tree
TreeT * tree
Definition: TopologyToLevelSet.h:94
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:82
openvdb::v7_1::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:106