Skip to content

Commit 67d3f2d

Browse files
authored
Merge pull request #2442 from SCIInstitute/mesh-isolate
Add Mesh/Grooming isolate / extract largest component functionality
2 parents 7357643 + d6fe627 commit 67d3f2d

File tree

16 files changed

+155
-0
lines changed

16 files changed

+155
-0
lines changed

Applications/shapeworks/Commands.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ COMMAND_DECLARE(FieldMean, MeshCommand);
8282
COMMAND_DECLARE(FieldStd, MeshCommand);
8383
COMMAND_DECLARE(FieldNames, MeshCommand);
8484
COMMAND_DECLARE(FixElement, MeshCommand);
85+
COMMAND_DECLARE(MeshLargestComponent, MeshCommand);
8586
COMMAND_DECLARE(ClipClosedSurface, MeshCommand);
8687
COMMAND_DECLARE(ClosestPoint, MeshCommand);
8788
COMMAND_DECLARE(GeodesicDistance, MeshCommand);

Applications/shapeworks/MeshCommands.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,27 @@ bool FixElement::execute(const optparse::Values &options, SharedCommandData &sha
765765
return sharedData.validMesh();
766766
}
767767

768+
///////////////////////////////////////////////////////////////////////////////
769+
// MeshLargestComponent
770+
///////////////////////////////////////////////////////////////////////////////
771+
void MeshLargestComponent::buildParser() {
772+
const std::string prog = "mesh-largest-component";
773+
const std::string desc = "extract the largest connected component from the mesh";
774+
parser.prog(prog).description(desc);
775+
776+
Command::buildParser();
777+
}
778+
779+
bool MeshLargestComponent::execute(const optparse::Values &options, SharedCommandData &sharedData) {
780+
if (!sharedData.validMesh()) {
781+
std::cerr << "No mesh to operate on\n";
782+
return false;
783+
}
784+
785+
sharedData.mesh->extractLargestComponent();
786+
return sharedData.validMesh();
787+
}
788+
768789
///////////////////////////////////////////////////////////////////////////////
769790
// ClipClosedSurface
770791
///////////////////////////////////////////////////////////////////////////////

Applications/shapeworks/shapeworks.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ int main(int argc, char *argv[])
8282
shapeworks.addCommand(MeshBounds::getCommand());
8383
shapeworks.addCommand(Distance::getCommand());
8484
shapeworks.addCommand(FixElement::getCommand());
85+
shapeworks.addCommand(MeshLargestComponent::getCommand());
8586
shapeworks.addCommand(ClipClosedSurface::getCommand());
8687
shapeworks.addCommand(ComputeNormals::getCommand());
8788
shapeworks.addCommand(ClosestPoint::getCommand());

Libs/Groom/Groom.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,12 @@ bool Groom::mesh_pipeline(std::shared_ptr<Subject> subject, size_t domain) {
368368

369369
//---------------------------------------------------------------------------
370370
bool Groom::run_mesh_pipeline(Mesh& mesh, GroomParameters params) {
371+
// Extract largest component (should be first)
372+
if (params.get_mesh_largest_component()) {
373+
mesh.extractLargestComponent();
374+
increment_progress();
375+
}
376+
371377
if (params.get_fill_mesh_holes_tool()) {
372378
mesh.fillHoles();
373379
increment_progress();
@@ -505,6 +511,7 @@ int Groom::get_total_ops() {
505511
(project_->get_original_domain_types()[i] == DomainType::Image && params.get_convert_to_mesh());
506512

507513
if (run_mesh) {
514+
num_tools += params.get_mesh_largest_component() ? 1 : 0;
508515
num_tools += params.get_fill_mesh_holes_tool() ? 1 : 0;
509516
num_tools += params.get_mesh_smooth() ? 1 : 0;
510517
num_tools += params.get_remesh() ? 1 : 0;

Libs/Groom/GroomParameters.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const std::string ISO_SPACING = "iso_spacing";
2323
const std::string SPACING = "spacing";
2424
const std::string CONVERT_MESH = "convert_to_mesh";
2525
const std::string FILL_MESH_HOLES = "fill_mesh_holes";
26+
const std::string MESH_LARGEST_COMPONENT = "mesh_largest_component";
2627
const std::string FILL_HOLES = "fill_holes";
2728
const std::string ISOLATE = "isolate";
2829
const std::string PAD = "pad";
@@ -77,6 +78,7 @@ const std::vector<double> spacing{0, 0, 0};
7778
const bool convert_mesh = false;
7879
const bool fill_holes = true;
7980
const bool fill_holes_mesh = false;
81+
const bool mesh_largest_component = true;
8082
const bool isolate = true;
8183
const bool pad = true;
8284
const int pad_value = 10;
@@ -156,6 +158,7 @@ GroomParameters::GroomParameters(ProjectHandle project, std::string domain_name)
156158
Keys::SPACING,
157159
Keys::CONVERT_MESH,
158160
Keys::FILL_MESH_HOLES,
161+
Keys::MESH_LARGEST_COMPONENT,
159162
Keys::FILL_HOLES,
160163
Keys::ISOLATE,
161164
Keys::PAD,
@@ -233,6 +236,14 @@ bool GroomParameters::get_fill_mesh_holes_tool() {
233236
//---------------------------------------------------------------------------
234237
void GroomParameters::set_fill_mesh_holes_tool(bool value) { params_.set(Keys::FILL_MESH_HOLES, value); }
235238

239+
//---------------------------------------------------------------------------
240+
bool GroomParameters::get_mesh_largest_component() {
241+
return params_.get(Keys::MESH_LARGEST_COMPONENT, Defaults::mesh_largest_component);
242+
}
243+
244+
//---------------------------------------------------------------------------
245+
void GroomParameters::set_mesh_largest_component(bool value) { params_.set(Keys::MESH_LARGEST_COMPONENT, value); }
246+
236247
//---------------------------------------------------------------------------
237248
bool GroomParameters::get_auto_pad_tool() { return params_.get(Keys::PAD, Defaults::pad); }
238249

Libs/Groom/GroomParameters.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ class GroomParameters {
6161
bool get_fill_mesh_holes_tool();
6262
void set_fill_mesh_holes_tool(bool value);
6363

64+
bool get_mesh_largest_component();
65+
void set_mesh_largest_component(bool value);
66+
6467
bool get_auto_pad_tool();
6568
void set_auto_pad_tool(bool value);
6669

Libs/Mesh/Mesh.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,22 @@ Mesh& Mesh::fixNonManifold() {
597597
return *this;
598598
}
599599

600+
Mesh& Mesh::extractLargestComponent() {
601+
auto connectivityFilter = vtkSmartPointer<vtkPolyDataConnectivityFilter>::New();
602+
connectivityFilter->SetExtractionModeToLargestRegion();
603+
connectivityFilter->SetInputData(poly_data_);
604+
connectivityFilter->Update();
605+
606+
// Clean to remove unused points from other components
607+
auto cleanFilter = vtkSmartPointer<vtkCleanPolyData>::New();
608+
cleanFilter->SetInputData(connectivityFilter->GetOutput());
609+
cleanFilter->Update();
610+
poly_data_ = cleanFilter->GetOutput();
611+
612+
this->invalidateLocators();
613+
return *this;
614+
}
615+
600616
bool Mesh::detectNonManifold() {
601617
auto features = vtkSmartPointer<vtkFeatureEdges>::New();
602618
features->SetInputData(this->poly_data_);

Libs/Mesh/Mesh.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class Mesh {
128128
/// Attempt to fix non-manifold edges
129129
Mesh& fixNonManifold();
130130

131+
/// Extract the largest connected component from the mesh
132+
Mesh& extractLargestComponent();
133+
131134
/// Detect if mesh contain non-manifold edges
132135
bool detectNonManifold();
133136

Libs/Python/ShapeworksPython.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,8 @@ PYBIND11_MODULE(shapeworks_py, m) {
935935

936936
.def("fixElement", &Mesh::fixElement, "fix element winding of mesh")
937937

938+
.def("extractLargestComponent", &Mesh::extractLargestComponent, "extract the largest connected component from the mesh")
939+
938940
.def(
939941
"distance",
940942
[](Mesh& mesh, const Mesh& target, const Mesh::DistanceMethod method) -> decltype(auto) {

Studio/Groom/GroomTool.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ void GroomTool::set_ui_from_params(GroomParameters params) {
489489
ui_->blur_checkbox->setChecked(params.get_blur_tool());
490490
ui_->isolate_checkbox->setChecked(params.get_isolate_tool());
491491
ui_->fill_holes_checkbox->setChecked(params.get_fill_holes_tool());
492+
ui_->mesh_largest_component->setChecked(params.get_mesh_largest_component());
492493
ui_->mesh_fill_holes->setChecked(params.get_fill_mesh_holes_tool());
493494
ui_->antialias_iterations->setValue(params.get_antialias_iterations());
494495
ui_->blur_sigma->setValue(params.get_blur_amount());
@@ -586,6 +587,7 @@ void GroomTool::store_params() {
586587
params.set_blur_amount(ui_->blur_sigma->value());
587588
params.set_isolate_tool(ui_->isolate_checkbox->isChecked());
588589
params.set_fill_holes_tool(ui_->fill_holes_checkbox->isChecked());
590+
params.set_mesh_largest_component(ui_->mesh_largest_component->isChecked());
589591
params.set_fill_mesh_holes_tool(ui_->mesh_fill_holes->isChecked());
590592
params.set_antialias_iterations(ui_->antialias_iterations->value());
591593
params.set_groom_output_prefix(preferences_.get_groom_file_template().toStdString());

0 commit comments

Comments
 (0)