| 432 | } |
| 433 | |
| 434 | Expected<std::vector<Mesh>> convertToInstances( const VdbVolume& mask, const std::vector<VdbVolume>& voxelSeeds, size_t minSize, ProgressCallback cb = {} ) |
| 435 | { |
| 436 | MR_TIMER; |
| 437 | std::vector<VoxelBitSet> seeds; |
| 438 | VoxelBitSet allSeeds; |
| 439 | for ( auto& seedObj : voxelSeeds ) |
| 440 | { |
| 441 | auto s = mask2set( seedObj ); |
| 442 | allSeeds |= s; |
| 443 | if ( s.count() > minSize ) |
| 444 | seeds.push_back( s ); |
| 445 | } |
| 446 | |
| 447 | auto dilatedMask = mask2set( dilateMask( mask ) ); |
| 448 | allSeeds = allSeeds | dilatedMask.flip(); |
| 449 | |
| 450 | auto maybeSimpleMask = vdbVolumeToSimpleVolume( mask ); |
| 451 | if ( !maybeSimpleMask ) |
| 452 | return unexpected( maybeSimpleMask.error() ); |
| 453 | auto& simpleMask = *maybeSimpleMask; |
| 454 | |
| 455 | std::vector<Mesh> res; |
| 456 | auto t = simpleMask; // temporary volume for segmentation |
| 457 | std::fill( begin( t.data ), end( t.data ), 0.f ); |
| 458 | for ( size_t i = 0; i < seeds.size(); ++i ) |
| 459 | { |
| 460 | reportProgress( cb, (float)i / seeds.size() ); |
| 461 | const auto& s = seeds[i]; |
| 462 | if ( s.count() < minSize ) |
| 463 | continue; |
| 464 | |
| 465 | auto maybeSegm = segmentVolumeByGraphCut( simpleMask, 3000.f, s, allSeeds - s ); |
| 466 | if ( !maybeSegm ) |
| 467 | return unexpected( maybeSegm.error() ); |
| 468 | |
| 469 | std::fill( begin( t.data ), end( t.data ), 0.f ); |
| 470 | for ( auto j : *maybeSegm ) |
| 471 | t.data[j] = 1.f; |
| 472 | |
| 473 | auto grid = simpleVolumeToDenseGrid( t ); |
| 474 | auto mesh = gridToMesh( std::move( grid ), GridToMeshSettings{ |
| 475 | .voxelSize = t.voxelSize, |
| 476 | .isoValue = 0.5f, |
| 477 | } ).value(); |
| 478 | |
| 479 | res.push_back( std::move( mesh ) ); |
| 480 | } |
| 481 | |
| 482 | return res; |
| 483 | } |
| 484 | |
| 485 | } |
| 486 |
no test coverage detected