33 #ifndef OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED
34 #define OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED
36 #include <openvdb/Types.h>
37 #include <openvdb/tree/TreeIterator.h>
38 #include <openvdb/tree/ValueAccessor.h>
39 #include <openvdb/tree/LeafManager.h>
56 inline void dilateVoxels(tree::LeafManager<TreeType>& manager,
int count = 1);
66 inline void erodeVoxels(TreeType& tree,
int count=1);
69 inline void erodeVoxels(tree::LeafManager<TreeType>& manager,
int count = 1);
75 template<Index Log2Dim>
struct DimToWord {
typedef uint8_t Type[0]; };
82 template<
typename TreeType>
94 void erodeVoxels(
int count = 1) { mSteps = count; this->doErosion(); }
100 typedef typename TreeType::LeafNodeType LeafType;
101 typedef typename LeafType::NodeMaskType MaskType;
104 const bool mOwnsManager;
105 ManagerType* mManager;
109 static const int LEAF_DIM = LeafType::DIM;
110 static const int LEAF_LOG2DIM = LeafType::LOG2DIM;
117 Neighbor() : leaf(NULL), init(true) {}
118 inline void clear() { init =
true; }
119 template<
int DX,
int DY,
int DZ>
120 void scatter(AccessorType& acc,
const Coord &xyz,
int indx, Word oldWord)
124 Coord orig = xyz.
offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
125 leaf = acc.probeLeaf(orig);
126 if (leaf==NULL && !acc.isValueOn(orig)) leaf = acc.touchLeaf(orig);
128 static const int N = (LEAF_DIM -1 )*(DY + DX*LEAF_DIM);
129 if (leaf) leaf->getValueMask().template getWord<Word>(indx-N) |= oldWord;
131 template<
int DX,
int DY,
int DZ>
132 Word gather(AccessorType& acc,
const Coord &xyz,
int indx)
136 Coord orig = xyz.
offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
137 leaf = acc.probeLeaf(orig);
138 isOn = leaf ?
false : acc.isValueOn(orig);
140 static const int N = (LEAF_DIM -1 )*(DY + DX*LEAF_DIM);
141 return leaf ? leaf->getValueMask().template getWord<Word>(indx-N) : isOn ? ~Word(0) : Word(0);
146 struct ErodeVoxelsOp {
147 ErodeVoxelsOp(std::vector<MaskType>& masks, ManagerType& manager)
148 : mSavedMasks(masks) , mManager(manager) {}
150 void runParallel() { tbb::parallel_for(mManager.getRange(), *
this); }
151 void operator()(
const tbb::blocked_range<size_t>& range)
const;
154 std::vector<MaskType>& mSavedMasks;
155 ManagerType& mManager;
160 MaskManager(std::vector<MaskType>& masks, ManagerType& manager)
161 : mMasks(masks) , mManager(manager), mSaveMasks(true) {}
163 void save() { mSaveMasks =
true; tbb::parallel_for(mManager.getRange(), *
this); }
164 void update() { mSaveMasks =
false; tbb::parallel_for(mManager.getRange(), *
this); }
165 void operator()(
const tbb::blocked_range<size_t>& range)
const
168 for (
size_t i = range.begin(); i < range.end(); ++i) {
169 mMasks[i] = mManager.leaf(i).getValueMask();
172 for (
size_t i = range.begin(); i < range.end(); ++i) {
173 mManager.leaf(i).setValueMask(mMasks[i]);
179 std::vector<MaskType>& mMasks;
180 ManagerType& mManager;
185 template <
typename TreeType>
189 const int leafCount = mManager->leafCount();
192 std::vector<MaskType> savedMasks(leafCount);
193 MaskManager masks(savedMasks, *mManager);
198 for (
int leafIdx = 0; leafIdx < leafCount; ++leafIdx) {
199 const MaskType& oldMask = savedMasks[leafIdx];
200 LeafType& leaf = mManager->leaf(leafIdx);
201 leaf.getOrigin(origin);
202 for (
int x = 0; x < LEAF_DIM; ++x ) {
203 for (
int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
205 const Word oldWord = oldMask.template getWord<Word>(n);
206 if (oldWord == 0)
continue;
210 leaf.getValueMask().template getWord<Word>(n-LEAF_DIM) |= oldWord;
212 NN[0].template scatter<-1, 0, 0>(
mAcc, origin, n, oldWord);
215 if (x < LEAF_DIM - 1) {
216 leaf.getValueMask().template getWord<Word>(n+LEAF_DIM) |= oldWord;
218 NN[1].template scatter< 1, 0, 0>(
mAcc, origin, n, oldWord);
222 leaf.getValueMask().template getWord<Word>(n-1) |= oldWord;
224 NN[2].template scatter< 0,-1, 0>(
mAcc, origin, n, oldWord);
227 if (y < LEAF_DIM - 1) {
228 leaf.getValueMask().template getWord<Word>(n+1) |= oldWord;
230 NN[3].template scatter< 0, 1, 0>(
mAcc, origin, n, oldWord);
234 leaf.getValueMask().template getWord<Word>(n) |= (oldWord >> 1) | (oldWord << 1);
236 if (Word w = oldWord<<(LEAF_DIM-1)) {
237 NN[4].template scatter< 0, 0,-1>(
mAcc, origin, n, w);
240 if (Word w = oldWord>>(LEAF_DIM-1)) {
241 NN[5].template scatter< 0, 0, 1>(
mAcc, origin, n, w);
245 for (
int i=0; i<6; ++i) NN[i].clear();
248 mManager->rebuildLeafArray();
252 template <
typename TreeType>
256 AccessorType acc(mManager.tree());
259 for (
size_t leafIdx = range.begin(); leafIdx < range.end(); ++leafIdx) {
260 LeafType& leaf = mManager.leaf(leafIdx);
261 if (leaf.isEmpty())
continue;
262 MaskType& newMask = mSavedMasks[leafIdx];
263 leaf.getOrigin(origin);
264 for (
int x = 0; x < LEAF_DIM; ++x ) {
265 for (
int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
267 Word& w = newMask.template getWord<Word>(n);
268 if (w == 0)
continue;
271 w &= (w<<1 | (NN[4].template gather<0,0,-1>(acc, origin, n)>>(LEAF_DIM-1))) &
272 (w>>1 | (NN[5].template gather<0,0, 1>(acc, origin, n)<<(LEAF_DIM-1)));
275 w &= (x == 0) ? NN[0].
template gather<-1, 0, 0>(acc, origin, n) :
276 leaf.getValueMask().template getWord<Word>(n-LEAF_DIM);
279 w &= (x == LEAF_DIM-1) ? NN[1].
template gather< 1, 0, 0>(acc, origin, n) :
280 leaf.getValueMask().template getWord<Word>(n+LEAF_DIM);
283 w &= (y == 0) ? NN[2].
template gather< 0,-1, 0>(acc, origin, n) :
284 leaf.getValueMask().template getWord<Word>(n-1);
287 w &= (y == LEAF_DIM-1) ? NN[3].
template gather< 0, 1, 0>(acc, origin, n) :
288 leaf.getValueMask().template getWord<Word>(n+1);
291 for (
int i=0; i<6; ++i) NN[i].clear();
296 template <
typename TreeType>
297 void Morphology<TreeType>::doErosion()
300 const int leafCount = mManager->leafCount();
303 std::vector<MaskType> savedMasks(leafCount);
304 MaskManager masks(savedMasks, *mManager);
307 ErodeVoxelsOp erode(savedMasks, *mManager);
308 for (
int i = 0; i < mSteps; ++i) {
313 mManager->tree().pruneLevelSet();
319 template<
typename TreeType>
327 template<
typename TreeType>
335 template<
typename TreeType>
343 template<
typename TreeType>
355 #endif // OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED