From fff9ba0965aa84827adae59c6b5b1e53389360b8 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Sun, 17 Aug 2025 15:35:20 -0600 Subject: [PATCH 01/13] Clean up headers, switch Session to Project to eliminate Studio dep. --- Libs/Optimize/Optimize.h | 1 - Studio/DeepSSM/DeepSSMJob.cpp | 17 +++-------------- Studio/DeepSSM/DeepSSMJob.h | 4 ++-- Studio/DeepSSM/DeepSSMTool.cpp | 6 +++--- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/Libs/Optimize/Optimize.h b/Libs/Optimize/Optimize.h index 3f86a2f059a..d09d2833059 100644 --- a/Libs/Optimize/Optimize.h +++ b/Libs/Optimize/Optimize.h @@ -5,7 +5,6 @@ #endif // std -#include #include #include diff --git a/Studio/DeepSSM/DeepSSMJob.cpp b/Studio/DeepSSM/DeepSSMJob.cpp index 78989469dfe..ced2be62570 100644 --- a/Studio/DeepSSM/DeepSSMJob.cpp +++ b/Studio/DeepSSM/DeepSSMJob.cpp @@ -2,23 +2,15 @@ #include #include -#include "qdir.h" namespace py = pybind11; using namespace pybind11::literals; // to bring in the `_a` literal -// std -#include -#include -#include -#include - // qt #include #include #include // shapeworks -#include #include #include #include @@ -30,10 +22,9 @@ using namespace pybind11::literals; // to bring in the `_a` literal namespace shapeworks { //--------------------------------------------------------------------------- -DeepSSMJob::DeepSSMJob(QSharedPointer session, DeepSSMTool::ToolMode tool_mode, - DeepSSMTool::PrepStep prep_step) - : session_(session), tool_mode_(tool_mode), prep_step_(prep_step) { - project_ = session_->get_project(); +DeepSSMJob::DeepSSMJob(std::shared_ptr project, DeepSSMTool::ToolMode tool_mode, + DeepSSMTool::PrepStep prep_step) + : project_(project), tool_mode_(tool_mode), prep_step_(prep_step) { } //--------------------------------------------------------------------------- @@ -85,7 +76,6 @@ QString DeepSSMJob::name() { void DeepSSMJob::run_prep() { // groom training auto subjects = project_->get_subjects(); - auto shapes = session_->get_shapes(); SW_LOG("DeepSSM: Grooming Training Data"); py::module py_deep_ssm_utils = py::module::import("DeepSSMUtils"); @@ -113,7 +103,6 @@ void DeepSSMJob::run_prep() { if (num_train == 0 || num_val == 0) { SW_ERROR("DeepSSM: Not enough subjects in training and validation. Please check split."); abort(); - //return; } if (is_aborted()) { diff --git a/Studio/DeepSSM/DeepSSMJob.h b/Studio/DeepSSM/DeepSSMJob.h index 19ab46ad99d..50ad0307cfb 100644 --- a/Studio/DeepSSM/DeepSSMJob.h +++ b/Studio/DeepSSM/DeepSSMJob.h @@ -17,7 +17,7 @@ class DeepSSMJob : public Job { Q_OBJECT; public: - DeepSSMJob(QSharedPointer session, DeepSSMTool::ToolMode tool_mode, + DeepSSMJob(std::shared_ptr project, DeepSSMTool::ToolMode tool_mode, DeepSSMTool::PrepStep prep_step = DeepSSMTool::NOT_STARTED); ~DeepSSMJob(); @@ -37,7 +37,7 @@ class DeepSSMJob : public Job { void process_test_results(); QSharedPointer session_; - ProjectHandle project_; + std::shared_ptr project_; DeepSSMTool::ToolMode tool_mode_; diff --git a/Studio/DeepSSM/DeepSSMTool.cpp b/Studio/DeepSSM/DeepSSMTool.cpp index b474318bc2d..0df975a488e 100644 --- a/Studio/DeepSSM/DeepSSMTool.cpp +++ b/Studio/DeepSSM/DeepSSMTool.cpp @@ -604,7 +604,7 @@ void DeepSSMTool::show_training_meshes() { //--------------------------------------------------------------------------- void DeepSSMTool::show_testing_meshes() { shapes_.clear(); - deep_ssm_ = QSharedPointer::create(session_, DeepSSMTool::ToolMode::DeepSSM_TestingType); + deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMTool::ToolMode::DeepSSM_TestingType); auto id_list = get_split(session_->get_project(), SplitType::TEST); auto subjects = session_->get_project()->get_subjects(); @@ -664,7 +664,7 @@ void DeepSSMTool::show_testing_meshes() { //--------------------------------------------------------------------------- void DeepSSMTool::update_testing_meshes() { try { - deep_ssm_ = QSharedPointer::create(session_, DeepSSMTool::ToolMode::DeepSSM_TestingType); + deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMTool::ToolMode::DeepSSM_TestingType); auto id_list = get_split(session_->get_project(), SplitType::TEST); auto subjects = session_->get_project()->get_subjects(); @@ -947,7 +947,7 @@ void DeepSSMTool::run_tool(DeepSSMTool::ToolMode type) { store_params(); - deep_ssm_ = QSharedPointer::create(session_, type, prep_step_); + deep_ssm_ = QSharedPointer::create(session_->get_project(), type, prep_step_); connect(deep_ssm_.data(), &DeepSSMJob::progress, this, &DeepSSMTool::handle_progress); connect(deep_ssm_.data(), &DeepSSMJob::finished, this, &DeepSSMTool::handle_thread_complete); From 3e1087e53317f64d0bd46e43ba2ab436157d3b3e Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Sun, 17 Aug 2025 15:43:55 -0600 Subject: [PATCH 02/13] Move Job class to the new Application library --- Libs/Application/CMakeLists.txt | 34 ++++++++++++++++++++++++ {Studio => Libs/Application}/Job/Job.cpp | 0 {Studio => Libs/Application}/Job/Job.h | 0 Libs/CMakeLists.txt | 1 + Studio/CMakeLists.txt | 3 +-- 5 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 Libs/Application/CMakeLists.txt rename {Studio => Libs/Application}/Job/Job.cpp (100%) rename {Studio => Libs/Application}/Job/Job.h (100%) diff --git a/Libs/Application/CMakeLists.txt b/Libs/Application/CMakeLists.txt new file mode 100644 index 00000000000..0271818b128 --- /dev/null +++ b/Libs/Application/CMakeLists.txt @@ -0,0 +1,34 @@ +SET(APPLICATION_MOC_HDRS + Job/Job.h +) + +qt5_wrap_cpp( APPLICATION_MOC_SRCS ${APPLICATION_MOC_HDRS} ) + +SET(Application_headers + ) + +add_library(Application STATIC + Job/Job.cpp + ${APPLICATION_MOC_SRCS} + ) + +target_include_directories(Application PUBLIC + $ + $) + +target_link_libraries(Application PUBLIC + Mesh + Utils + Particles + ) + +# set +set_target_properties(Application PROPERTIES PUBLIC_HEADER + "${Application_headers}") + +install(TARGETS Application EXPORT ShapeWorksTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION include/Application + ) diff --git a/Studio/Job/Job.cpp b/Libs/Application/Job/Job.cpp similarity index 100% rename from Studio/Job/Job.cpp rename to Libs/Application/Job/Job.cpp diff --git a/Studio/Job/Job.h b/Libs/Application/Job/Job.h similarity index 100% rename from Studio/Job/Job.h rename to Libs/Application/Job/Job.h diff --git a/Libs/CMakeLists.txt b/Libs/CMakeLists.txt index 75adb39e983..5cba523b616 100644 --- a/Libs/CMakeLists.txt +++ b/Libs/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(Application) add_subdirectory(Common) add_subdirectory(Mesh) add_subdirectory(Image) diff --git a/Studio/CMakeLists.txt b/Studio/CMakeLists.txt index fb6f135bd26..86490a55db3 100644 --- a/Studio/CMakeLists.txt +++ b/Studio/CMakeLists.txt @@ -102,7 +102,6 @@ SET(STUDIO_DATA_MOC_HDRS ) SET(STUDIO_JOB_SRCS - Job/Job.cpp Job/GroupPvalueJob.cpp Job/ParticleAreaJob.cpp Job/NetworkAnalysisJob.cpp @@ -112,7 +111,6 @@ SET(STUDIO_JOB_SRCS ) SET(STUDIO_JOB_MOC_HDRS - Job/Job.h Job/GroupPvalueJob.h Job/NetworkAnalysisJob.h Job/ParticleAreaJob.h @@ -385,6 +383,7 @@ TARGET_LINK_LIBRARIES(ShapeWorksStudio ${ITK_LIBRARIES} ${OPENGL_LIBRARIES} tinyxml + Application Alignment Analyze OptimizeLibraries From 0066dd96c0ff09076315f9536a1070515a60a3b4 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Sun, 17 Aug 2025 15:53:47 -0600 Subject: [PATCH 03/13] Isolate DeepSSMJob from Studio --- Studio/DeepSSM/DeepSSMJob.cpp | 82 ++++++++++++++++-------- Studio/DeepSSM/DeepSSMJob.h | 32 +++++++-- Studio/DeepSSM/DeepSSMTool.cpp | 114 ++++++++++++--------------------- Studio/DeepSSM/DeepSSMTool.h | 26 ++------ 4 files changed, 126 insertions(+), 128 deletions(-) diff --git a/Studio/DeepSSM/DeepSSMJob.cpp b/Studio/DeepSSM/DeepSSMJob.cpp index ced2be62570..34079a5bc85 100644 --- a/Studio/DeepSSM/DeepSSMJob.cpp +++ b/Studio/DeepSSM/DeepSSMJob.cpp @@ -22,10 +22,8 @@ using namespace pybind11::literals; // to bring in the `_a` literal namespace shapeworks { //--------------------------------------------------------------------------- -DeepSSMJob::DeepSSMJob(std::shared_ptr project, DeepSSMTool::ToolMode tool_mode, - DeepSSMTool::PrepStep prep_step) - : project_(project), tool_mode_(tool_mode), prep_step_(prep_step) { -} +DeepSSMJob::DeepSSMJob(std::shared_ptr project, DeepSSMJob::ToolMode tool_mode, DeepSSMJob::PrepStep prep_step) + : project_(project), tool_mode_(tool_mode), prep_step_(prep_step) {} //--------------------------------------------------------------------------- DeepSSMJob::~DeepSSMJob() {} @@ -34,16 +32,16 @@ DeepSSMJob::~DeepSSMJob() {} void DeepSSMJob::run() { try { switch (tool_mode_) { - case DeepSSMTool::ToolMode::DeepSSM_PrepType: + case DeepSSMJob::ToolMode::DeepSSM_PrepType: run_prep(); break; - case DeepSSMTool::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: run_augmentation(); break; - case DeepSSMTool::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::ToolMode::DeepSSM_TrainingType: run_training(); break; - case DeepSSMTool::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::ToolMode::DeepSSM_TestingType: run_testing(); break; } @@ -55,16 +53,16 @@ void DeepSSMJob::run() { //--------------------------------------------------------------------------- QString DeepSSMJob::name() { switch (tool_mode_) { - case DeepSSMTool::ToolMode::DeepSSM_PrepType: + case DeepSSMJob::ToolMode::DeepSSM_PrepType: return "DeepSSM: Prep"; break; - case DeepSSMTool::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: return "DeepSSM: Augmentation"; break; - case DeepSSMTool::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::ToolMode::DeepSSM_TrainingType: return "DeepSSM: Training"; break; - case DeepSSMTool::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::ToolMode::DeepSSM_TestingType: return "DeepSSM: Testing"; break; } @@ -86,7 +84,7 @@ void DeepSSMJob::run_prep() { params.set_training_step_complete(false); params.save_to_project(); - if (prep_step_ == DeepSSMTool::PrepStep::NOT_STARTED || prep_step_ == DeepSSMTool::PrepStep::GROOM_TRAINING) { + if (prep_step_ == DeepSSMJob::PrepStep::NOT_STARTED || prep_step_ == DeepSSMJob::PrepStep::GROOM_TRAINING) { SW_LOG("Creating Split..."); ///////////////////////////////////////////////////////// /// Step 1. Create Split @@ -97,9 +95,9 @@ void DeepSSMJob::run_prep() { py::object create_split = py_deep_ssm_utils.attr("create_split"); create_split(project_, train_split, val_split, test_split); - int num_train = DeepSSMTool::get_split(project_, DeepSSMTool::SplitType::TRAIN).size(); - int num_val = DeepSSMTool::get_split(project_, DeepSSMTool::SplitType::VAL).size(); - int num_test = DeepSSMTool::get_split(project_, DeepSSMTool::SplitType::TEST).size(); + int num_train = get_split(project_, SplitType::TRAIN).size(); + int num_val = get_split(project_, SplitType::VAL).size(); + int num_test = get_split(project_, SplitType::TEST).size(); if (num_train == 0 || num_val == 0) { SW_ERROR("DeepSSM: Not enough subjects in training and validation. Please check split."); abort(); @@ -112,7 +110,7 @@ void DeepSSMJob::run_prep() { ///////////////////////////////////////////////////////// /// Step 2. Groom Training Shapes ///////////////////////////////////////////////////////// - update_prep_stage(DeepSSMTool::PrepStep::GROOM_TRAINING); + update_prep_stage(DeepSSMJob::PrepStep::GROOM_TRAINING); py::object groom_training_shapes = py_deep_ssm_utils.attr("groom_training_shapes"); QElapsedTimer timer; @@ -142,11 +140,11 @@ void DeepSSMJob::run_prep() { } } - if (prep_step_ == DeepSSMTool::PrepStep::NOT_STARTED || prep_step_ == DeepSSMTool::PrepStep::OPTIMIZE_TRAINING) { + if (prep_step_ == DeepSSMJob::PrepStep::NOT_STARTED || prep_step_ == DeepSSMJob::PrepStep::OPTIMIZE_TRAINING) { ///////////////////////////////////////////////////////// /// Step 3. Optimize Training Particles ///////////////////////////////////////////////////////// - update_prep_stage(DeepSSMTool::PrepStep::OPTIMIZE_TRAINING); + update_prep_stage(DeepSSMJob::PrepStep::OPTIMIZE_TRAINING); QElapsedTimer timer; timer.start(); py::object optimize_training_particles = py_deep_ssm_utils.attr("optimize_training_particles"); @@ -160,11 +158,11 @@ void DeepSSMJob::run_prep() { } } - if (prep_step_ == DeepSSMTool::PrepStep::NOT_STARTED || prep_step_ == DeepSSMTool::PrepStep::OPTIMIZE_VALIDATION) { + if (prep_step_ == DeepSSMJob::PrepStep::NOT_STARTED || prep_step_ == DeepSSMJob::PrepStep::OPTIMIZE_VALIDATION) { ///////////////////////////////////////////////////////// /// Step 6. Optimize Validation Particles with Fixed Domains ///////////////////////////////////////////////////////// - update_prep_stage(DeepSSMTool::PrepStep::OPTIMIZE_VALIDATION); + update_prep_stage(DeepSSMJob::PrepStep::OPTIMIZE_VALIDATION); py::object prep_project_for_val_particles = py_deep_ssm_utils.attr("prep_project_for_val_particles"); prep_project_for_val_particles(project_); @@ -188,12 +186,12 @@ void DeepSSMJob::run_prep() { SW_LOG("DeepSSM: Optimize Validation Particles complete. Duration: {} seconds", duration.toStdString()); } - if (prep_step_ == DeepSSMTool::PrepStep::NOT_STARTED || prep_step_ == DeepSSMTool::PrepStep::GROOM_IMAGES) { + if (prep_step_ == DeepSSMJob::PrepStep::NOT_STARTED || prep_step_ == DeepSSMJob::PrepStep::GROOM_IMAGES) { ///////////////////////////////////////////////////////// /// Step 4. Groom Training Images ///////////////////////////////////////////////////////// - update_prep_stage(DeepSSMTool::PrepStep::GROOM_IMAGES); + update_prep_stage(DeepSSMJob::PrepStep::GROOM_IMAGES); QElapsedTimer timer; timer.start(); py::object groom_training_images = py_deep_ssm_utils.attr("groom_training_images"); @@ -210,7 +208,7 @@ void DeepSSMJob::run_prep() { ///////////////////////////////////////////////////////// timer.start(); py::object groom_val_test_images = py_deep_ssm_utils.attr("groom_val_test_images"); - groom_val_test_images(project_, DeepSSMTool::get_split(project_, DeepSSMTool::SplitType::VAL)); + groom_val_test_images(project_, get_split(project_, SplitType::VAL)); project_->save(); duration = QString::number(timer.elapsed() / 1000.0, 'f', 1); SW_LOG("DeepSSM: Groom Validation Images complete. Duration: {} seconds", duration.toStdString()); @@ -221,7 +219,7 @@ void DeepSSMJob::run_prep() { } ///////////////////////////////////////////////////////// - update_prep_stage(DeepSSMTool::PrepStep::DONE); + update_prep_stage(DeepSSMJob::PrepStep::DONE); params.set_prep_step_complete(true); params.set_aug_step_complete(false); params.set_training_step_complete(false); @@ -317,7 +315,7 @@ void DeepSSMJob::run_testing() { py::module py_deep_ssm_utils = py::module::import("DeepSSMUtils"); - std::vector test_indices = DeepSSMTool::get_split(project_, DeepSSMTool::SplitType::TEST); + std::vector test_indices = get_split(project_, SplitType::TEST); // Groom Test Images SW_MESSAGE("Grooming Test Images"); @@ -360,7 +358,37 @@ void DeepSSMJob::run_testing() { void DeepSSMJob::python_message(std::string str) { SW_LOG(str); } //--------------------------------------------------------------------------- -void DeepSSMJob::update_prep_stage(DeepSSMTool::PrepStep step) { +std::vector DeepSSMJob::get_split(ProjectHandle project, SplitType split_type) { + auto subjects = project->get_subjects(); + + std::vector list; + + for (int id = 0; id < subjects.size(); id++) { + auto extra_values = subjects[id]->get_extra_values(); + + std::string split = extra_values["split"]; + + if (split_type == DeepSSMJob::SplitType::TRAIN) { + if (split != "train") { + continue; + } + } else if (split_type == DeepSSMJob::SplitType::VAL) { + if (split != "val") { + continue; + } + } else if (split_type == DeepSSMJob::SplitType::TEST) { + if (split != "test") { + continue; + } + } + + list.push_back(id); + } + return list; +} + +//--------------------------------------------------------------------------- +void DeepSSMJob::update_prep_stage(PrepStep step) { /* std::lock_guard lock(mutex_); diff --git a/Studio/DeepSSM/DeepSSMJob.h b/Studio/DeepSSM/DeepSSMJob.h index 50ad0307cfb..b6ff531a77a 100644 --- a/Studio/DeepSSM/DeepSSMJob.h +++ b/Studio/DeepSSM/DeepSSMJob.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -17,8 +16,26 @@ class DeepSSMJob : public Job { Q_OBJECT; public: - DeepSSMJob(std::shared_ptr project, DeepSSMTool::ToolMode tool_mode, - DeepSSMTool::PrepStep prep_step = DeepSSMTool::NOT_STARTED); + enum class ToolMode { + DeepSSM_PrepType = 0, + DeepSSM_AugmentationType = 1, + DeepSSM_TrainingType = 2, + DeepSSM_TestingType = 3 + }; + + enum PrepStep { + NOT_STARTED = 0, + GROOM_TRAINING = 1, + OPTIMIZE_TRAINING = 2, + OPTIMIZE_VALIDATION = 3, + GROOM_IMAGES = 4, + DONE = 5 + }; + + enum class SplitType { TRAIN, VAL, TEST }; + + DeepSSMJob(std::shared_ptr project, DeepSSMJob::ToolMode tool_mode, + DeepSSMJob::PrepStep prep_step = DeepSSMJob::NOT_STARTED); ~DeepSSMJob(); void run() override; @@ -32,17 +49,18 @@ class DeepSSMJob : public Job { void python_message(std::string str); + static std::vector get_split(ProjectHandle project, DeepSSMJob::SplitType split_type); + private: - void update_prep_stage(DeepSSMTool::PrepStep step); + void update_prep_stage(DeepSSMJob::PrepStep step); void process_test_results(); - QSharedPointer session_; std::shared_ptr project_; - DeepSSMTool::ToolMode tool_mode_; + DeepSSMJob::ToolMode tool_mode_; QString prep_message_; - DeepSSMTool::PrepStep prep_step_{DeepSSMTool::NOT_STARTED}; + DeepSSMJob::PrepStep prep_step_{DeepSSMJob::NOT_STARTED}; // mutex std::mutex mutex_; diff --git a/Studio/DeepSSM/DeepSSMTool.cpp b/Studio/DeepSSM/DeepSSMTool.cpp index 0df975a488e..b1591136d58 100644 --- a/Studio/DeepSSM/DeepSSMTool.cpp +++ b/Studio/DeepSSM/DeepSSMTool.cpp @@ -124,16 +124,16 @@ DeepSSMTool::DeepSSMTool(Preferences& prefs) : preferences_(prefs) { void DeepSSMTool::tab_changed(int tab) { switch (tab) { case 0: - current_tool_ = DeepSSMTool::ToolMode::DeepSSM_PrepType; + current_tool_ = DeepSSMJob::ToolMode::DeepSSM_PrepType; break; case 1: - current_tool_ = DeepSSMTool::ToolMode::DeepSSM_AugmentationType; + current_tool_ = DeepSSMJob::ToolMode::DeepSSM_AugmentationType; break; case 2: - current_tool_ = DeepSSMTool::ToolMode::DeepSSM_TrainingType; + current_tool_ = DeepSSMJob::ToolMode::DeepSSM_TrainingType; break; case 3: - current_tool_ = DeepSSMTool::ToolMode::DeepSSM_TestingType; + current_tool_ = DeepSSMJob::ToolMode::DeepSSM_TestingType; break; } update_panels(); @@ -249,7 +249,7 @@ void DeepSSMTool::run_clicked() { } else { session_->trigger_save(); if (ui_->run_all->isChecked()) { - run_tool(DeepSSMTool::ToolMode::DeepSSM_PrepType); + run_tool(DeepSSMJob::ToolMode::DeepSSM_PrepType); } else { run_tool(current_tool_); } @@ -258,7 +258,7 @@ void DeepSSMTool::run_clicked() { //--------------------------------------------------------------------------- void DeepSSMTool::run_prep_clicked(int step) { - prep_step_ = static_cast(step); + prep_step_ = static_cast(step); run_clicked(); } @@ -266,16 +266,16 @@ void DeepSSMTool::run_prep_clicked(int step) { void DeepSSMTool::handle_thread_complete() { try { if (!deep_ssm_->is_aborted()) { - if (current_tool_ == DeepSSMTool::ToolMode::DeepSSM_PrepType) { + if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_PrepType) { auto params = DeepSSMParameters(session_->get_project()); params.set_prep_stage(static_cast(prep_step_)); - if (prep_step_ == DeepSSMTool::PrepStep::NOT_STARTED || prep_step_ == DeepSSMTool::PrepStep::GROOM_IMAGES) { + if (prep_step_ == DeepSSMJob::PrepStep::NOT_STARTED || prep_step_ == DeepSSMJob::PrepStep::GROOM_IMAGES) { params.set_prep_step_complete(true); - params.set_prep_stage(static_cast(DeepSSMTool::PrepStep::DONE)); + params.set_prep_stage(static_cast(DeepSSMJob::PrepStep::DONE)); } params.save_to_project(); update_panels(); - prep_step_ = DeepSSMTool::PrepStep::NOT_STARTED; + prep_step_ = DeepSSMJob::PrepStep::NOT_STARTED; } } Q_EMIT progress(100); @@ -286,12 +286,12 @@ void DeepSSMTool::handle_thread_complete() { if (!deep_ssm_->is_aborted()) { if (ui_->run_all->isChecked()) { - if (current_tool_ == ToolMode::DeepSSM_PrepType) { - run_tool(DeepSSMTool::ToolMode::DeepSSM_AugmentationType); - } else if (current_tool_ == ToolMode::DeepSSM_AugmentationType) { - run_tool(DeepSSMTool::ToolMode::DeepSSM_TrainingType); - } else if (current_tool_ == ToolMode::DeepSSM_TrainingType) { - run_tool(DeepSSMTool::ToolMode::DeepSSM_TestingType); + if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_PrepType) { + run_tool(DeepSSMJob::ToolMode::DeepSSM_AugmentationType); + } else if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_AugmentationType) { + run_tool(DeepSSMJob::ToolMode::DeepSSM_TrainingType); + } else if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_TrainingType) { + run_tool(DeepSSMJob::ToolMode::DeepSSM_TestingType); } } } @@ -302,7 +302,7 @@ void DeepSSMTool::handle_thread_complete() { //--------------------------------------------------------------------------- void DeepSSMTool::handle_progress(int val, QString message) { - if (current_tool_ == DeepSSMTool::ToolMode::DeepSSM_PrepType) { + if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_PrepType) { //?? TODO ui_->prep_text_edit->setText(deep_ssm_->get_prep_message()); //?? TODO ui_->prep_text_edit->setEnabled(true); } @@ -333,20 +333,20 @@ void DeepSSMTool::update_panels() { ui_->training_panel->hide(); bool enabled = true; switch (current_tool_) { - case DeepSSMTool::ToolMode::DeepSSM_PrepType: + case DeepSSMJob::ToolMode::DeepSSM_PrepType: string = "All Prep Stages"; break; - case DeepSSMTool::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: string = "Data Augmentation"; ui_->data_panel->show(); enabled = params.get_prep_step_complete(); break; - case DeepSSMTool::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::ToolMode::DeepSSM_TrainingType: string = "Training"; ui_->training_panel->show(); enabled = params.get_aug_step_complete(); break; - case DeepSSMTool::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::ToolMode::DeepSSM_TestingType: string = "Testing"; enabled = params.get_training_step_complete(); break; @@ -406,7 +406,7 @@ void DeepSSMTool::update_split() { //--------------------------------------------------------------------------- void DeepSSMTool::handle_new_mesh() { - if (current_tool_ == DeepSSMTool::ToolMode::DeepSSM_TestingType) { + if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_TestingType) { update_testing_meshes(); } } @@ -604,8 +604,8 @@ void DeepSSMTool::show_training_meshes() { //--------------------------------------------------------------------------- void DeepSSMTool::show_testing_meshes() { shapes_.clear(); - deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMTool::ToolMode::DeepSSM_TestingType); - auto id_list = get_split(session_->get_project(), SplitType::TEST); + deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMJob::ToolMode::DeepSSM_TestingType); + auto id_list = DeepSSMJob::get_split(session_->get_project(), DeepSSMJob::SplitType::TEST); auto subjects = session_->get_project()->get_subjects(); auto shapes = session_->get_shapes(); @@ -664,8 +664,8 @@ void DeepSSMTool::show_testing_meshes() { //--------------------------------------------------------------------------- void DeepSSMTool::update_testing_meshes() { try { - deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMTool::ToolMode::DeepSSM_TestingType); - auto id_list = get_split(session_->get_project(), SplitType::TEST); + deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMJob::ToolMode::DeepSSM_TestingType); + auto id_list = DeepSSMJob::get_split(session_->get_project(), DeepSSMJob::SplitType::TEST); auto subjects = session_->get_project()->get_subjects(); auto shapes = session_->get_shapes(); @@ -685,17 +685,17 @@ void DeepSSMTool::update_meshes() { return; } switch (current_tool_) { - case DeepSSMTool::ToolMode::DeepSSM_PrepType: + case DeepSSMJob::ToolMode::DeepSSM_PrepType: shapes_.clear(); Q_EMIT update_view(); break; - case DeepSSMTool::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: show_augmentation_meshes(); break; - case DeepSSMTool::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::ToolMode::DeepSSM_TrainingType: show_training_meshes(); break; - case DeepSSMTool::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::ToolMode::DeepSSM_TestingType: show_testing_meshes(); break; } @@ -835,43 +835,13 @@ void DeepSSMTool::resizeEvent(QResizeEvent* event) { //--------------------------------------------------------------------------- std::string DeepSSMTool::get_display_feature() { - if (current_tool_ == DeepSSMTool::ToolMode::DeepSSM_TrainingType || - current_tool_ == DeepSSMTool::ToolMode::DeepSSM_TestingType) { + if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_TrainingType || + current_tool_ == DeepSSMJob::ToolMode::DeepSSM_TestingType) { return "deepssm_error"; } return ""; } -//--------------------------------------------------------------------------- -std::vector DeepSSMTool::get_split(ProjectHandle project, SplitType split_type) { - auto subjects = project->get_subjects(); - - std::vector list; - - for (int id = 0; id < subjects.size(); id++) { - auto extra_values = subjects[id]->get_extra_values(); - - std::string split = extra_values["split"]; - - if (split_type == SplitType::TRAIN) { - if (split != "train") { - continue; - } - } else if (split_type == SplitType::VAL) { - if (split != "val") { - continue; - } - } else if (split_type == SplitType::TEST) { - if (split != "test") { - continue; - } - } - - list.push_back(id); - } - return list; -} - //--------------------------------------------------------------------------- void DeepSSMTool::restore_defaults() { // need to save values from the other pages @@ -880,16 +850,16 @@ void DeepSSMTool::restore_defaults() { auto params = DeepSSMParameters(session_->get_project()); switch (current_tool_) { - case DeepSSMTool::ToolMode::DeepSSM_PrepType: + case DeepSSMJob::ToolMode::DeepSSM_PrepType: params.restore_split_defaults(); break; - case DeepSSMTool::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: params.restore_augmentation_defaults(); break; - case DeepSSMTool::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::ToolMode::DeepSSM_TrainingType: params.restore_training_defaults(); break; - case DeepSSMTool::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::ToolMode::DeepSSM_TestingType: // params.restore_inference_defaults(); break; } @@ -900,17 +870,17 @@ void DeepSSMTool::restore_defaults() { } //--------------------------------------------------------------------------- -void DeepSSMTool::run_tool(DeepSSMTool::ToolMode type) { +void DeepSSMTool::run_tool(DeepSSMJob::ToolMode type) { current_tool_ = type; Q_EMIT progress(-1); - if (type == DeepSSMTool::ToolMode::DeepSSM_AugmentationType) { + if (type == DeepSSMJob::ToolMode::DeepSSM_AugmentationType) { ui_->tab_widget->setCurrentIndex(1); SW_LOG("Please Wait: Running Data Augmentation..."); // clean QFile("deepssm/augmentation/TotalData.csv").remove(); - } else if (type == DeepSSMTool::ToolMode::DeepSSM_TrainingType) { + } else if (type == DeepSSMJob::ToolMode::DeepSSM_TrainingType) { ui_->tab_widget->setCurrentIndex(2); SW_LOG("Please Wait: Running Training..."); @@ -919,17 +889,15 @@ void DeepSSMTool::run_tool(DeepSSMTool::ToolMode type) { dir.removeRecursively(); show_training_meshes(); - } else if (type == DeepSSMTool::ToolMode::DeepSSM_TestingType) { + } else if (type == DeepSSMJob::ToolMode::DeepSSM_TestingType) { ui_->tab_widget->setCurrentIndex(3); SW_LOG("Please Wait: Running Testing..."); - } else if (type == DeepSSMTool::ToolMode::DeepSSM_PrepType) { + } else if (type == DeepSSMJob::ToolMode::DeepSSM_PrepType) { ui_->tab_widget->setCurrentIndex(0); // check that there are at least 1 subject in test/val/train each - - SW_LOG("Please Wait: Running Groom/Optimize..."); } else { SW_ERROR("Unknown tool mode"); diff --git a/Studio/DeepSSM/DeepSSMTool.h b/Studio/DeepSSM/DeepSSMTool.h index efd4bc306a7..e42cae925ba 100644 --- a/Studio/DeepSSM/DeepSSMTool.h +++ b/Studio/DeepSSM/DeepSSMTool.h @@ -5,6 +5,8 @@ #include #include +#include + // studio #include #include @@ -26,23 +28,6 @@ class DeepSSMTool : public QWidget { Q_OBJECT; public: - enum class ToolMode { - DeepSSM_PrepType = 0, - DeepSSM_AugmentationType = 1, - DeepSSM_TrainingType = 2, - DeepSSM_TestingType = 3 - }; - - enum PrepStep { - NOT_STARTED = 0, - GROOM_TRAINING = 1, - OPTIMIZE_TRAINING = 2, - OPTIMIZE_VALIDATION = 3, - GROOM_IMAGES = 4, - DONE = 5 - }; - - enum class SplitType { TRAIN, VAL, TEST }; DeepSSMTool(Preferences& prefs); ~DeepSSMTool(); @@ -67,7 +52,6 @@ class DeepSSMTool : public QWidget { std::string get_display_feature(); - static std::vector get_split(ProjectHandle project, SplitType split_type); public Q_SLOTS: @@ -96,7 +80,7 @@ class DeepSSMTool : public QWidget { private: void update_meshes(); - void run_tool(DeepSSMTool::ToolMode type); + void run_tool(DeepSSMJob::ToolMode type); void show_augmentation_meshes(); void update_tables(); void show_training_meshes(); @@ -120,10 +104,10 @@ class DeepSSMTool : public QWidget { Ui_DeepSSMTool* ui_; QSharedPointer session_; ShapeWorksStudioApp* app_; - PrepStep prep_step_ = PrepStep::NOT_STARTED; + DeepSSMJob::PrepStep prep_step_ = DeepSSMJob::PrepStep::NOT_STARTED; bool tool_is_running_ = false; - DeepSSMTool::ToolMode current_tool_ = DeepSSMTool::ToolMode::DeepSSM_AugmentationType; + DeepSSMJob::ToolMode current_tool_ = DeepSSMJob::ToolMode::DeepSSM_AugmentationType; QSharedPointer deep_ssm_; QElapsedTimer timer_; From 616c7ce2e67efc1a1a740b2184536f52f68129b1 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Sun, 17 Aug 2025 15:57:10 -0600 Subject: [PATCH 04/13] Move DeepSSMParameters to Project library --- Libs/Project/CMakeLists.txt | 2 ++ {Studio/DeepSSM => Libs/Project}/DeepSSMParameters.cpp | 0 {Studio/DeepSSM => Libs/Project}/DeepSSMParameters.h | 0 Studio/CMakeLists.txt | 1 - Studio/DeepSSM/DeepSSMJob.cpp | 2 +- Studio/DeepSSM/DeepSSMTool.cpp | 2 +- 6 files changed, 4 insertions(+), 3 deletions(-) rename {Studio/DeepSSM => Libs/Project}/DeepSSMParameters.cpp (100%) rename {Studio/DeepSSM => Libs/Project}/DeepSSMParameters.h (100%) diff --git a/Libs/Project/CMakeLists.txt b/Libs/Project/CMakeLists.txt index fdf03cb29a6..7cc14dd63a8 100644 --- a/Libs/Project/CMakeLists.txt +++ b/Libs/Project/CMakeLists.txt @@ -1,6 +1,7 @@ set(SOURCES ExcelProjectReader.cpp ExcelProjectWriter.cpp + DeepSSMParameters.cpp JsonProjectReader.cpp JsonProjectWriter.cpp Parameters.cpp @@ -12,6 +13,7 @@ set(SOURCES ) set(HEADERS + DeepSSMParameters.h Project.h Subject.h Parameters.h diff --git a/Studio/DeepSSM/DeepSSMParameters.cpp b/Libs/Project/DeepSSMParameters.cpp similarity index 100% rename from Studio/DeepSSM/DeepSSMParameters.cpp rename to Libs/Project/DeepSSMParameters.cpp diff --git a/Studio/DeepSSM/DeepSSMParameters.h b/Libs/Project/DeepSSMParameters.h similarity index 100% rename from Studio/DeepSSM/DeepSSMParameters.h rename to Libs/Project/DeepSSMParameters.h diff --git a/Studio/CMakeLists.txt b/Studio/CMakeLists.txt index 86490a55db3..78235ec5c3c 100644 --- a/Studio/CMakeLists.txt +++ b/Studio/CMakeLists.txt @@ -157,7 +157,6 @@ SET(STUDIO_ANALYSIS_MOC_HDRS SET(STUDIO_DEEPSSM_SRCS DeepSSM/DeepSSMTool.cpp - DeepSSM/DeepSSMParameters.cpp DeepSSM/DeepSSMJob.cpp ) SET(STUDIO_DEEPSSM_MOC_HDRS diff --git a/Studio/DeepSSM/DeepSSMJob.cpp b/Studio/DeepSSM/DeepSSMJob.cpp index 34079a5bc85..174d914a689 100644 --- a/Studio/DeepSSM/DeepSSMJob.cpp +++ b/Studio/DeepSSM/DeepSSMJob.cpp @@ -12,7 +12,7 @@ using namespace pybind11::literals; // to bring in the `_a` literal // shapeworks #include -#include +#include #include #include #include diff --git a/Studio/DeepSSM/DeepSSMTool.cpp b/Studio/DeepSSM/DeepSSMTool.cpp index b1591136d58..e5d2047caa5 100644 --- a/Studio/DeepSSM/DeepSSMTool.cpp +++ b/Studio/DeepSSM/DeepSSMTool.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include From ef35a672cd2aa853f146bdb66ce967b3947201a9 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Sun, 17 Aug 2025 16:07:21 -0600 Subject: [PATCH 05/13] Move DeepSSMJob to Application library --- Libs/Application/CMakeLists.txt | 11 +++++++++++ {Studio => Libs/Application}/DeepSSM/DeepSSMJob.cpp | 2 +- {Studio => Libs/Application}/DeepSSM/DeepSSMJob.h | 0 Studio/CMakeLists.txt | 2 -- 4 files changed, 12 insertions(+), 3 deletions(-) rename {Studio => Libs/Application}/DeepSSM/DeepSSMJob.cpp (99%) rename {Studio => Libs/Application}/DeepSSM/DeepSSMJob.h (100%) diff --git a/Libs/Application/CMakeLists.txt b/Libs/Application/CMakeLists.txt index 0271818b128..66d9c58d597 100644 --- a/Libs/Application/CMakeLists.txt +++ b/Libs/Application/CMakeLists.txt @@ -1,4 +1,5 @@ SET(APPLICATION_MOC_HDRS + DeepSSM/DeepSSMJob.h Job/Job.h ) @@ -8,6 +9,7 @@ SET(Application_headers ) add_library(Application STATIC + DeepSSM/DeepSSMJob.cpp Job/Job.cpp ${APPLICATION_MOC_SRCS} ) @@ -16,10 +18,19 @@ target_include_directories(Application PUBLIC $ $) +set(SW_PYTHON_LIBS pybind11::embed) + +if (APPLE) + include_directories(${_Python3_INCLUDE_DIR}) + set(SW_PYTHON_LIBS "") +endif(APPLE) + target_link_libraries(Application PUBLIC + Groom Mesh Utils Particles + ${SW_PYTHON_LIBS} ) # set diff --git a/Studio/DeepSSM/DeepSSMJob.cpp b/Libs/Application/DeepSSM/DeepSSMJob.cpp similarity index 99% rename from Studio/DeepSSM/DeepSSMJob.cpp rename to Libs/Application/DeepSSM/DeepSSMJob.cpp index 174d914a689..c8c853410a7 100644 --- a/Studio/DeepSSM/DeepSSMJob.cpp +++ b/Libs/Application/DeepSSM/DeepSSMJob.cpp @@ -11,7 +11,7 @@ using namespace pybind11::literals; // to bring in the `_a` literal #include // shapeworks -#include +#include "DeepSSMJob.h" #include #include #include diff --git a/Studio/DeepSSM/DeepSSMJob.h b/Libs/Application/DeepSSM/DeepSSMJob.h similarity index 100% rename from Studio/DeepSSM/DeepSSMJob.h rename to Libs/Application/DeepSSM/DeepSSMJob.h diff --git a/Studio/CMakeLists.txt b/Studio/CMakeLists.txt index 78235ec5c3c..06fb243337f 100644 --- a/Studio/CMakeLists.txt +++ b/Studio/CMakeLists.txt @@ -157,11 +157,9 @@ SET(STUDIO_ANALYSIS_MOC_HDRS SET(STUDIO_DEEPSSM_SRCS DeepSSM/DeepSSMTool.cpp - DeepSSM/DeepSSMJob.cpp ) SET(STUDIO_DEEPSSM_MOC_HDRS DeepSSM/DeepSSMTool.h - DeepSSM/DeepSSMJob.h ) From f25a0da9a013090ca0235997e7d5ca49cd5572ff Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Sun, 17 Aug 2025 16:15:56 -0600 Subject: [PATCH 06/13] Fix 'restore defaults' for DeepSSM splits --- Studio/DeepSSM/DeepSSMTool.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Studio/DeepSSM/DeepSSMTool.cpp b/Studio/DeepSSM/DeepSSMTool.cpp index e5d2047caa5..a4b61ed3720 100644 --- a/Studio/DeepSSM/DeepSSMTool.cpp +++ b/Studio/DeepSSM/DeepSSMTool.cpp @@ -160,6 +160,8 @@ void DeepSSMTool::load_params() { ui_->validation_split->setText(QString::number(params.get_validation_split())); ui_->testing_split->setText(QString::number(params.get_testing_split())); + ui_->training_split->setText(QString::number(params.get_training_split())); + update_split(); auto spacing = params.get_spacing(); ui_->spacing_x->setText(QString::number(spacing[0])); From 4fd4ab78f4f3c685e9c673505a54c8e834f44ed5 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 18 Aug 2025 11:05:50 -0600 Subject: [PATCH 07/13] Working on DeepSSM command --- Applications/shapeworks/CMakeLists.txt | 2 +- Applications/shapeworks/Command.h | 9 ++ Applications/shapeworks/Commands.cpp | 112 +++++++++++++++++++++++- Applications/shapeworks/Commands.h | 1 + Applications/shapeworks/shapeworks.cpp | 1 + Libs/Application/DeepSSM/DeepSSMJob.cpp | 24 ++--- Libs/Application/DeepSSM/DeepSSMJob.h | 11 ++- Studio/DeepSSM/DeepSSMTool.cpp | 74 ++++++++-------- Studio/DeepSSM/DeepSSMTool.h | 4 +- 9 files changed, 179 insertions(+), 59 deletions(-) diff --git a/Applications/shapeworks/CMakeLists.txt b/Applications/shapeworks/CMakeLists.txt index b6cafe7f4c7..eded1b33e89 100644 --- a/Applications/shapeworks/CMakeLists.txt +++ b/Applications/shapeworks/CMakeLists.txt @@ -23,7 +23,7 @@ target_include_directories(shapeworks_exe PUBLIC target_link_libraries(shapeworks_exe Mesh ${VTK_LIBRARIES} Optimize Utils trimesh2 Particles - pybind11::embed Project Image Groom Analyze + pybind11::embed Project Image Groom Analyze Application ) message(STATUS "opt libs ${OPTIMIZE_LIBRARIES}") diff --git a/Applications/shapeworks/Command.h b/Applications/shapeworks/Command.h index 881e448e575..8c6db366ef0 100644 --- a/Applications/shapeworks/Command.h +++ b/Applications/shapeworks/Command.h @@ -103,6 +103,15 @@ class ParticleSystemCommand : public Command private: }; +class DeepSSMCommandGroup : public Command +{ +public: + const std::string type() override { return "DeepSSM"; } + +private: +}; + + class ShapeworksCommand : public Command { public: diff --git a/Applications/shapeworks/Commands.cpp b/Applications/shapeworks/Commands.cpp index b94955282be..d78fea6d0a1 100644 --- a/Applications/shapeworks/Commands.cpp +++ b/Applications/shapeworks/Commands.cpp @@ -1,18 +1,18 @@ #include "Commands.h" #include +#include #include #include #include #include #include +#include #include #include #include -#include - namespace shapeworks { // boilerplate for a command. Copy this to start a new command @@ -43,8 +43,6 @@ bool Example::execute(const optparse::Values &options, SharedCommandData &shared } #endif - - /////////////////////////////////////////////////////////////////////////////// // Seed /////////////////////////////////////////////////////////////////////////////// @@ -331,4 +329,110 @@ bool ConvertProjectCommand::execute(const optparse::Values& options, SharedComma return false; } } + +/////////////////////////////////////////////////////////////////////////////// +// DeepSSM +/////////////////////////////////////////////////////////////////////////////// +void DeepSSMCommand::buildParser() { + const std::string prog = "deepssm"; + const std::string desc = "run deepssm steps"; + parser.prog(prog).description(desc); + + parser.add_option("--name").action("store").type("string").set_default("").help( + "Path to input project file (xlsx or swproj)."); + + // Create a vector of choices first + std::vector prep_choices = {"all", "groom_training", "optimize_training", "optimize_validation", + "groom_images"}; + + // --prep option with choices + parser.add_option("--prep") + .action("store") + .type("choice") + .choices(prep_choices.begin(), prep_choices.end()) + .set_default("all") + .help("Preparation step to run"); + + // Boolean flag options + parser.add_option("--augment").action("store_true").help("Run data augmentation"); + + parser.add_option("--train").action("store_true").help("Run training"); + + parser.add_option("--test").action("store_true").help("Run testing"); + + parser.add_option("--all").action("store_true").help("Run all steps"); + + Command::buildParser(); +} + +bool DeepSSMCommand::execute(const optparse::Values& options, SharedCommandData& sharedData) { + // Handle project file: either from --name or first positional argument + std::string project_file; + if (options.is_set_by_user("name")) { + // User explicitly provided --name + project_file = options["name"]; + } else if (!parser.args().empty()) { + // Use first positional argument + project_file = parser.args()[0]; + } else { + // No project file provided at all + parser.error("Project file must be provided either as --name or as a positional argument"); + } + + std::cout << "DeepSSM: Using project file: " << project_file << std::endl; + + bool do_prep = options.is_set("prep") || options.is_set("all"); + std::string prep_step = options["prep"]; + bool do_augment = options.is_set("augment") || options.is_set("all"); + bool do_train = options.is_set("train") || options.is_set("all"); + bool do_test = options.is_set("test") || options.is_set("all"); + if (!do_prep && !do_augment && !do_train && !do_test) { + do_prep = true; + do_augment = true; + do_train = true; + do_test = true; + } + + ProjectHandle project = std::make_shared(); + project->load(project_file); + + DeepSSMJob job(project, DeepSSMJob::JobType::DeepSSM_PrepType); + + if (do_prep) { + if (prep_step == "all") { + job.set_prep_step(DeepSSMJob::PrepStep::NOT_STARTED); + } else if (prep_step == "groom_training") { + job.set_prep_step(DeepSSMJob::PrepStep::GROOM_TRAINING); + } else if (prep_step == "optimize_training") { + job.set_prep_step(DeepSSMJob::PrepStep::OPTIMIZE_TRAINING); + } else if (prep_step == "optimize_validation") { + job.set_prep_step(DeepSSMJob::PrepStep::OPTIMIZE_VALIDATION); + } else if (prep_step == "groom_images") { + job.set_prep_step(DeepSSMJob::PrepStep::GROOM_IMAGES); + } else { + SW_ERROR("Unknown prep step: {}", prep_step); + return false; + } + std::cout << "Running DeepSSM preparation step...\n"; + job.run_prep(); + } + if (do_augment) { + std::cout << "Running DeepSSM data augmentation...\n"; + job.run_augmentation(); + } + if (do_train) { + std::cout << "Running DeepSSM training...\n"; + job.run_training(); + } + if (do_test) { + std::cout << "Running DeepSSM testing...\n"; + job.run_testing(); + } + + project->save(); + + SW_ERROR("DeepSSM command is not implemented yet."); + return false; +} + } // namespace shapeworks diff --git a/Applications/shapeworks/Commands.h b/Applications/shapeworks/Commands.h index 631a96643c3..3cbfc6fb2b8 100644 --- a/Applications/shapeworks/Commands.h +++ b/Applications/shapeworks/Commands.h @@ -101,5 +101,6 @@ COMMAND_DECLARE(OptimizeCommand, OptimizeCommandGroup); COMMAND_DECLARE(GroomCommand, GroomCommandGroup); COMMAND_DECLARE(AnalyzeCommand, AnalyzeCommandGroup); COMMAND_DECLARE(ConvertProjectCommand, ProjectCommandGroup); +COMMAND_DECLARE(DeepSSMCommand, DeepSSMCommandGroup); } // shapeworks diff --git a/Applications/shapeworks/shapeworks.cpp b/Applications/shapeworks/shapeworks.cpp index 63cd6ad7513..06866ac3f54 100644 --- a/Applications/shapeworks/shapeworks.cpp +++ b/Applications/shapeworks/shapeworks.cpp @@ -110,6 +110,7 @@ int main(int argc, char *argv[]) shapeworks.addCommand(GroomCommand::getCommand()); shapeworks.addCommand(AnalyzeCommand::getCommand()); shapeworks.addCommand(ConvertProjectCommand::getCommand()); + shapeworks.addCommand(DeepSSMCommand::getCommand()); try { TIME_START("shapeworks"); diff --git a/Libs/Application/DeepSSM/DeepSSMJob.cpp b/Libs/Application/DeepSSM/DeepSSMJob.cpp index c8c853410a7..7de61cd6437 100644 --- a/Libs/Application/DeepSSM/DeepSSMJob.cpp +++ b/Libs/Application/DeepSSM/DeepSSMJob.cpp @@ -22,8 +22,8 @@ using namespace pybind11::literals; // to bring in the `_a` literal namespace shapeworks { //--------------------------------------------------------------------------- -DeepSSMJob::DeepSSMJob(std::shared_ptr project, DeepSSMJob::ToolMode tool_mode, DeepSSMJob::PrepStep prep_step) - : project_(project), tool_mode_(tool_mode), prep_step_(prep_step) {} +DeepSSMJob::DeepSSMJob(std::shared_ptr project, DeepSSMJob::JobType tool_mode, DeepSSMJob::PrepStep prep_step) + : project_(project), job_type_(tool_mode), prep_step_(prep_step) {} //--------------------------------------------------------------------------- DeepSSMJob::~DeepSSMJob() {} @@ -31,17 +31,17 @@ DeepSSMJob::~DeepSSMJob() {} //--------------------------------------------------------------------------- void DeepSSMJob::run() { try { - switch (tool_mode_) { - case DeepSSMJob::ToolMode::DeepSSM_PrepType: + switch (job_type_) { + case DeepSSMJob::JobType::DeepSSM_PrepType: run_prep(); break; - case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::JobType::DeepSSM_AugmentationType: run_augmentation(); break; - case DeepSSMJob::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::JobType::DeepSSM_TrainingType: run_training(); break; - case DeepSSMJob::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::JobType::DeepSSM_TestingType: run_testing(); break; } @@ -52,17 +52,17 @@ void DeepSSMJob::run() { //--------------------------------------------------------------------------- QString DeepSSMJob::name() { - switch (tool_mode_) { - case DeepSSMJob::ToolMode::DeepSSM_PrepType: + switch (job_type_) { + case DeepSSMJob::JobType::DeepSSM_PrepType: return "DeepSSM: Prep"; break; - case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::JobType::DeepSSM_AugmentationType: return "DeepSSM: Augmentation"; break; - case DeepSSMJob::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::JobType::DeepSSM_TrainingType: return "DeepSSM: Training"; break; - case DeepSSMJob::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::JobType::DeepSSM_TestingType: return "DeepSSM: Testing"; break; } diff --git a/Libs/Application/DeepSSM/DeepSSMJob.h b/Libs/Application/DeepSSM/DeepSSMJob.h index b6ff531a77a..f3c26dbcb94 100644 --- a/Libs/Application/DeepSSM/DeepSSMJob.h +++ b/Libs/Application/DeepSSM/DeepSSMJob.h @@ -16,7 +16,7 @@ class DeepSSMJob : public Job { Q_OBJECT; public: - enum class ToolMode { + enum class JobType { DeepSSM_PrepType = 0, DeepSSM_AugmentationType = 1, DeepSSM_TrainingType = 2, @@ -34,7 +34,7 @@ class DeepSSMJob : public Job { enum class SplitType { TRAIN, VAL, TEST }; - DeepSSMJob(std::shared_ptr project, DeepSSMJob::ToolMode tool_mode, + DeepSSMJob(std::shared_ptr project, DeepSSMJob::JobType tool_mode, DeepSSMJob::PrepStep prep_step = DeepSSMJob::NOT_STARTED); ~DeepSSMJob(); @@ -51,13 +51,18 @@ class DeepSSMJob : public Job { static std::vector get_split(ProjectHandle project, DeepSSMJob::SplitType split_type); + void set_prep_step(DeepSSMJob::PrepStep step) { + std::lock_guard lock(mutex_); + prep_step_ = step; + } + private: void update_prep_stage(DeepSSMJob::PrepStep step); void process_test_results(); std::shared_ptr project_; - DeepSSMJob::ToolMode tool_mode_; + DeepSSMJob::JobType job_type_; QString prep_message_; DeepSSMJob::PrepStep prep_step_{DeepSSMJob::NOT_STARTED}; diff --git a/Studio/DeepSSM/DeepSSMTool.cpp b/Studio/DeepSSM/DeepSSMTool.cpp index a4b61ed3720..0ca37279891 100644 --- a/Studio/DeepSSM/DeepSSMTool.cpp +++ b/Studio/DeepSSM/DeepSSMTool.cpp @@ -124,16 +124,16 @@ DeepSSMTool::DeepSSMTool(Preferences& prefs) : preferences_(prefs) { void DeepSSMTool::tab_changed(int tab) { switch (tab) { case 0: - current_tool_ = DeepSSMJob::ToolMode::DeepSSM_PrepType; + current_tool_ = DeepSSMJob::JobType::DeepSSM_PrepType; break; case 1: - current_tool_ = DeepSSMJob::ToolMode::DeepSSM_AugmentationType; + current_tool_ = DeepSSMJob::JobType::DeepSSM_AugmentationType; break; case 2: - current_tool_ = DeepSSMJob::ToolMode::DeepSSM_TrainingType; + current_tool_ = DeepSSMJob::JobType::DeepSSM_TrainingType; break; case 3: - current_tool_ = DeepSSMJob::ToolMode::DeepSSM_TestingType; + current_tool_ = DeepSSMJob::JobType::DeepSSM_TestingType; break; } update_panels(); @@ -251,7 +251,7 @@ void DeepSSMTool::run_clicked() { } else { session_->trigger_save(); if (ui_->run_all->isChecked()) { - run_tool(DeepSSMJob::ToolMode::DeepSSM_PrepType); + run_tool(DeepSSMJob::JobType::DeepSSM_PrepType); } else { run_tool(current_tool_); } @@ -268,7 +268,7 @@ void DeepSSMTool::run_prep_clicked(int step) { void DeepSSMTool::handle_thread_complete() { try { if (!deep_ssm_->is_aborted()) { - if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_PrepType) { + if (current_tool_ == DeepSSMJob::JobType::DeepSSM_PrepType) { auto params = DeepSSMParameters(session_->get_project()); params.set_prep_stage(static_cast(prep_step_)); if (prep_step_ == DeepSSMJob::PrepStep::NOT_STARTED || prep_step_ == DeepSSMJob::PrepStep::GROOM_IMAGES) { @@ -288,12 +288,12 @@ void DeepSSMTool::handle_thread_complete() { if (!deep_ssm_->is_aborted()) { if (ui_->run_all->isChecked()) { - if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_PrepType) { - run_tool(DeepSSMJob::ToolMode::DeepSSM_AugmentationType); - } else if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_AugmentationType) { - run_tool(DeepSSMJob::ToolMode::DeepSSM_TrainingType); - } else if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_TrainingType) { - run_tool(DeepSSMJob::ToolMode::DeepSSM_TestingType); + if (current_tool_ == DeepSSMJob::JobType::DeepSSM_PrepType) { + run_tool(DeepSSMJob::JobType::DeepSSM_AugmentationType); + } else if (current_tool_ == DeepSSMJob::JobType::DeepSSM_AugmentationType) { + run_tool(DeepSSMJob::JobType::DeepSSM_TrainingType); + } else if (current_tool_ == DeepSSMJob::JobType::DeepSSM_TrainingType) { + run_tool(DeepSSMJob::JobType::DeepSSM_TestingType); } } } @@ -304,7 +304,7 @@ void DeepSSMTool::handle_thread_complete() { //--------------------------------------------------------------------------- void DeepSSMTool::handle_progress(int val, QString message) { - if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_PrepType) { + if (current_tool_ == DeepSSMJob::JobType::DeepSSM_PrepType) { //?? TODO ui_->prep_text_edit->setText(deep_ssm_->get_prep_message()); //?? TODO ui_->prep_text_edit->setEnabled(true); } @@ -335,20 +335,20 @@ void DeepSSMTool::update_panels() { ui_->training_panel->hide(); bool enabled = true; switch (current_tool_) { - case DeepSSMJob::ToolMode::DeepSSM_PrepType: + case DeepSSMJob::JobType::DeepSSM_PrepType: string = "All Prep Stages"; break; - case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::JobType::DeepSSM_AugmentationType: string = "Data Augmentation"; ui_->data_panel->show(); enabled = params.get_prep_step_complete(); break; - case DeepSSMJob::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::JobType::DeepSSM_TrainingType: string = "Training"; ui_->training_panel->show(); enabled = params.get_aug_step_complete(); break; - case DeepSSMJob::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::JobType::DeepSSM_TestingType: string = "Testing"; enabled = params.get_training_step_complete(); break; @@ -408,7 +408,7 @@ void DeepSSMTool::update_split() { //--------------------------------------------------------------------------- void DeepSSMTool::handle_new_mesh() { - if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_TestingType) { + if (current_tool_ == DeepSSMJob::JobType::DeepSSM_TestingType) { update_testing_meshes(); } } @@ -606,7 +606,7 @@ void DeepSSMTool::show_training_meshes() { //--------------------------------------------------------------------------- void DeepSSMTool::show_testing_meshes() { shapes_.clear(); - deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMJob::ToolMode::DeepSSM_TestingType); + deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMJob::JobType::DeepSSM_TestingType); auto id_list = DeepSSMJob::get_split(session_->get_project(), DeepSSMJob::SplitType::TEST); auto subjects = session_->get_project()->get_subjects(); @@ -666,7 +666,7 @@ void DeepSSMTool::show_testing_meshes() { //--------------------------------------------------------------------------- void DeepSSMTool::update_testing_meshes() { try { - deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMJob::ToolMode::DeepSSM_TestingType); + deep_ssm_ = QSharedPointer::create(session_->get_project(), DeepSSMJob::JobType::DeepSSM_TestingType); auto id_list = DeepSSMJob::get_split(session_->get_project(), DeepSSMJob::SplitType::TEST); auto subjects = session_->get_project()->get_subjects(); @@ -687,17 +687,17 @@ void DeepSSMTool::update_meshes() { return; } switch (current_tool_) { - case DeepSSMJob::ToolMode::DeepSSM_PrepType: + case DeepSSMJob::JobType::DeepSSM_PrepType: shapes_.clear(); Q_EMIT update_view(); break; - case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::JobType::DeepSSM_AugmentationType: show_augmentation_meshes(); break; - case DeepSSMJob::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::JobType::DeepSSM_TrainingType: show_training_meshes(); break; - case DeepSSMJob::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::JobType::DeepSSM_TestingType: show_testing_meshes(); break; } @@ -837,8 +837,8 @@ void DeepSSMTool::resizeEvent(QResizeEvent* event) { //--------------------------------------------------------------------------- std::string DeepSSMTool::get_display_feature() { - if (current_tool_ == DeepSSMJob::ToolMode::DeepSSM_TrainingType || - current_tool_ == DeepSSMJob::ToolMode::DeepSSM_TestingType) { + if (current_tool_ == DeepSSMJob::JobType::DeepSSM_TrainingType || + current_tool_ == DeepSSMJob::JobType::DeepSSM_TestingType) { return "deepssm_error"; } return ""; @@ -852,16 +852,16 @@ void DeepSSMTool::restore_defaults() { auto params = DeepSSMParameters(session_->get_project()); switch (current_tool_) { - case DeepSSMJob::ToolMode::DeepSSM_PrepType: + case DeepSSMJob::JobType::DeepSSM_PrepType: params.restore_split_defaults(); break; - case DeepSSMJob::ToolMode::DeepSSM_AugmentationType: + case DeepSSMJob::JobType::DeepSSM_AugmentationType: params.restore_augmentation_defaults(); break; - case DeepSSMJob::ToolMode::DeepSSM_TrainingType: + case DeepSSMJob::JobType::DeepSSM_TrainingType: params.restore_training_defaults(); break; - case DeepSSMJob::ToolMode::DeepSSM_TestingType: + case DeepSSMJob::JobType::DeepSSM_TestingType: // params.restore_inference_defaults(); break; } @@ -872,17 +872,17 @@ void DeepSSMTool::restore_defaults() { } //--------------------------------------------------------------------------- -void DeepSSMTool::run_tool(DeepSSMJob::ToolMode type) { - current_tool_ = type; +void DeepSSMTool::run_tool(DeepSSMJob::JobType job_type) { + current_tool_ = job_type; Q_EMIT progress(-1); - if (type == DeepSSMJob::ToolMode::DeepSSM_AugmentationType) { + if (job_type == DeepSSMJob::JobType::DeepSSM_AugmentationType) { ui_->tab_widget->setCurrentIndex(1); SW_LOG("Please Wait: Running Data Augmentation..."); // clean QFile("deepssm/augmentation/TotalData.csv").remove(); - } else if (type == DeepSSMJob::ToolMode::DeepSSM_TrainingType) { + } else if (job_type == DeepSSMJob::JobType::DeepSSM_TrainingType) { ui_->tab_widget->setCurrentIndex(2); SW_LOG("Please Wait: Running Training..."); @@ -891,11 +891,11 @@ void DeepSSMTool::run_tool(DeepSSMJob::ToolMode type) { dir.removeRecursively(); show_training_meshes(); - } else if (type == DeepSSMJob::ToolMode::DeepSSM_TestingType) { + } else if (job_type == DeepSSMJob::JobType::DeepSSM_TestingType) { ui_->tab_widget->setCurrentIndex(3); SW_LOG("Please Wait: Running Testing..."); - } else if (type == DeepSSMJob::ToolMode::DeepSSM_PrepType) { + } else if (job_type == DeepSSMJob::JobType::DeepSSM_PrepType) { ui_->tab_widget->setCurrentIndex(0); // check that there are at least 1 subject in test/val/train each @@ -917,7 +917,7 @@ void DeepSSMTool::run_tool(DeepSSMJob::ToolMode type) { store_params(); - deep_ssm_ = QSharedPointer::create(session_->get_project(), type, prep_step_); + deep_ssm_ = QSharedPointer::create(session_->get_project(), job_type, prep_step_); connect(deep_ssm_.data(), &DeepSSMJob::progress, this, &DeepSSMTool::handle_progress); connect(deep_ssm_.data(), &DeepSSMJob::finished, this, &DeepSSMTool::handle_thread_complete); diff --git a/Studio/DeepSSM/DeepSSMTool.h b/Studio/DeepSSM/DeepSSMTool.h index e42cae925ba..3e36dce6334 100644 --- a/Studio/DeepSSM/DeepSSMTool.h +++ b/Studio/DeepSSM/DeepSSMTool.h @@ -80,7 +80,7 @@ class DeepSSMTool : public QWidget { private: void update_meshes(); - void run_tool(DeepSSMJob::ToolMode type); + void run_tool(DeepSSMJob::JobType type); void show_augmentation_meshes(); void update_tables(); void show_training_meshes(); @@ -107,7 +107,7 @@ class DeepSSMTool : public QWidget { DeepSSMJob::PrepStep prep_step_ = DeepSSMJob::PrepStep::NOT_STARTED; bool tool_is_running_ = false; - DeepSSMJob::ToolMode current_tool_ = DeepSSMJob::ToolMode::DeepSSM_AugmentationType; + DeepSSMJob::JobType current_tool_ = DeepSSMJob::JobType::DeepSSM_AugmentationType; QSharedPointer deep_ssm_; QElapsedTimer timer_; From 8cdf6d87a1b7ef0592d02de43d6e2b6937fbdb94 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 18 Aug 2025 11:46:24 -0600 Subject: [PATCH 08/13] Rename StudioVtkOutputWindow to ShapeWorksVtkOutputWindow --- Studio/CMakeLists.txt | 4 ++-- Studio/Interface/ShapeWorksStudioApp.cpp | 2 +- Studio/Interface/ShapeWorksStudioApp.h | 4 ++-- Studio/Python/PythonWorker.cpp | 2 +- Studio/Python/PythonWorker.h | 6 +++--- ...putWindow.cpp => ShapeWorksVtkOutputWindow.cpp} | 14 +++++++------- ...kOutputWindow.h => ShapeWorksVtkOutputWindow.h} | 8 ++++---- 7 files changed, 20 insertions(+), 20 deletions(-) rename Studio/Visualization/{StudioVtkOutputWindow.cpp => ShapeWorksVtkOutputWindow.cpp} (53%) rename Studio/Visualization/{StudioVtkOutputWindow.h => ShapeWorksVtkOutputWindow.h} (68%) diff --git a/Studio/CMakeLists.txt b/Studio/CMakeLists.txt index 06fb243337f..a90472ddea6 100644 --- a/Studio/CMakeLists.txt +++ b/Studio/CMakeLists.txt @@ -228,14 +228,14 @@ SET(STUDIO_VISUALIZATION_SRCS Visualization/MeshSlice.cpp Visualization/Viewer.cpp Visualization/Visualizer.cpp - Visualization/StudioVtkOutputWindow.cpp + Visualization/ShapeWorksVtkOutputWindow.cpp Visualization/StudioHandleWidget.cpp ) SET(STUDIO_VISUALIZATION_MOC_HDRS Visualization/Lightbox.h Visualization/ParticleColors.h - Visualization/StudioVtkOutputWindow.h + Visualization/ShapeWorksVtkOutputWindow.h Visualization/Visualizer.h ) diff --git a/Studio/Interface/ShapeWorksStudioApp.cpp b/Studio/Interface/ShapeWorksStudioApp.cpp index 771c390d3d5..e851546a84c 100644 --- a/Studio/Interface/ShapeWorksStudioApp.cpp +++ b/Studio/Interface/ShapeWorksStudioApp.cpp @@ -69,7 +69,7 @@ ShapeWorksStudioApp::ShapeWorksStudioApp() { status_bar_ = new StatusBarWidget(this); connect(status_bar_, &StatusBarWidget::toggle_log_window, this, &ShapeWorksStudioApp::toggle_log_window); - studio_vtk_output_window_ = vtkSmartPointer::New(); + studio_vtk_output_window_ = vtkSmartPointer::New(); vtkOutputWindow::SetInstance(studio_vtk_output_window_); logger_.register_callbacks(); diff --git a/Studio/Interface/ShapeWorksStudioApp.h b/Studio/Interface/ShapeWorksStudioApp.h index fc84eced2be..89dd7149230 100644 --- a/Studio/Interface/ShapeWorksStudioApp.h +++ b/Studio/Interface/ShapeWorksStudioApp.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -234,7 +234,7 @@ class ShapeWorksStudioApp : public QMainWindow { QSharedPointer visualizer_; QSharedPointer preferences_window_; CompareWidget* compare_widget_ = nullptr; - vtkSmartPointer studio_vtk_output_window_; + vtkSmartPointer studio_vtk_output_window_; // all the preferences Preferences preferences_; diff --git a/Studio/Python/PythonWorker.cpp b/Studio/Python/PythonWorker.cpp index e46058ba9ca..7f13d728f94 100644 --- a/Studio/Python/PythonWorker.cpp +++ b/Studio/Python/PythonWorker.cpp @@ -72,7 +72,7 @@ PythonWorker::~PythonWorker() { } //--------------------------------------------------------------------------- -void PythonWorker::set_vtk_output_window(vtkSmartPointer output_window) { +void PythonWorker::set_vtk_output_window(vtkSmartPointer output_window) { studio_vtk_output_window_ = output_window; } diff --git a/Studio/Python/PythonWorker.h b/Studio/Python/PythonWorker.h index 71775971124..2eaa430c144 100644 --- a/Studio/Python/PythonWorker.h +++ b/Studio/Python/PythonWorker.h @@ -9,7 +9,7 @@ // studio #include -#include +#include namespace shapeworks { class PythonLogger; @@ -23,7 +23,7 @@ class PythonWorker : public QObject { PythonWorker(); ~PythonWorker(); - void set_vtk_output_window(vtkSmartPointer output_window); + void set_vtk_output_window(vtkSmartPointer output_window); void run_job(QSharedPointer job); @@ -51,7 +51,7 @@ class PythonWorker : public QObject { bool initialized_ = false; bool initialized_success_ = false; - vtkSmartPointer studio_vtk_output_window_; + vtkSmartPointer studio_vtk_output_window_; QSharedPointer python_logger_; diff --git a/Studio/Visualization/StudioVtkOutputWindow.cpp b/Studio/Visualization/ShapeWorksVtkOutputWindow.cpp similarity index 53% rename from Studio/Visualization/StudioVtkOutputWindow.cpp rename to Studio/Visualization/ShapeWorksVtkOutputWindow.cpp index cd9f794c12b..6219b26640d 100644 --- a/Studio/Visualization/StudioVtkOutputWindow.cpp +++ b/Studio/Visualization/ShapeWorksVtkOutputWindow.cpp @@ -1,26 +1,26 @@ -#include "StudioVtkOutputWindow.h" +#include "ShapeWorksVtkOutputWindow.h" #include #include namespace shapeworks { -vtkStandardNewMacro(StudioVtkOutputWindow); +vtkStandardNewMacro(ShapeWorksVtkOutputWindow); //--------------------------------------------------------------------------- -StudioVtkOutputWindow::StudioVtkOutputWindow() {} +ShapeWorksVtkOutputWindow::ShapeWorksVtkOutputWindow() {} //--------------------------------------------------------------------------- -void StudioVtkOutputWindow::DisplayErrorText(const char* text) { SW_ERROR(text); } +void ShapeWorksVtkOutputWindow::DisplayErrorText(const char* text) { SW_ERROR(text); } //--------------------------------------------------------------------------- -void StudioVtkOutputWindow::DisplayWarningText(const char* text) { SW_WARN(text); } +void ShapeWorksVtkOutputWindow::DisplayWarningText(const char* text) { SW_WARN(text); } //--------------------------------------------------------------------------- -void StudioVtkOutputWindow::DisplayGenericWarningText(const char* text) { SW_WARN(text); } +void ShapeWorksVtkOutputWindow::DisplayGenericWarningText(const char* text) { SW_WARN(text); } //--------------------------------------------------------------------------- -void StudioVtkOutputWindow::DisplayDebugText(const char* text) { SW_DEBUG(text); } +void ShapeWorksVtkOutputWindow::DisplayDebugText(const char* text) { SW_DEBUG(text); } //--------------------------------------------------------------------------- diff --git a/Studio/Visualization/StudioVtkOutputWindow.h b/Studio/Visualization/ShapeWorksVtkOutputWindow.h similarity index 68% rename from Studio/Visualization/StudioVtkOutputWindow.h rename to Studio/Visualization/ShapeWorksVtkOutputWindow.h index 721c55ff50f..0ff930710c7 100644 --- a/Studio/Visualization/StudioVtkOutputWindow.h +++ b/Studio/Visualization/ShapeWorksVtkOutputWindow.h @@ -7,15 +7,15 @@ namespace shapeworks { //! Implementation of vtkOutputWindow to capture and display VTK error messages -class StudioVtkOutputWindow : public QObject, public vtkOutputWindow { +class ShapeWorksVtkOutputWindow : public QObject, public vtkOutputWindow { Q_OBJECT; public: - static StudioVtkOutputWindow* New(); + static ShapeWorksVtkOutputWindow* New(); - vtkTypeMacro(StudioVtkOutputWindow, vtkOutputWindow); + vtkTypeMacro(ShapeWorksVtkOutputWindow, vtkOutputWindow); - StudioVtkOutputWindow(); + ShapeWorksVtkOutputWindow(); void DisplayErrorText(const char* text) override; void DisplayWarningText(const char* text) override; From a8eec613e60ee26ecc93968f94e1c7028db5a929 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 18 Aug 2025 16:15:09 -0600 Subject: [PATCH 09/13] Move PythonWorker, implement deepssm CLI command --- Applications/shapeworks/Commands.cpp | 77 +++++++++++++++---- Libs/Application/CMakeLists.txt | 4 + Libs/Application/Job/Job.h | 4 + .../Application/Job}/PythonWorker.cpp | 16 ++-- .../Application/Job}/PythonWorker.h | 5 +- .../ShapeWorksVtkOutputWindow.cpp | 0 .../Application}/ShapeWorksVtkOutputWindow.h | 0 Studio/Analysis/AnalysisTool.cpp | 2 +- Studio/Analysis/ShapeScalarPanel.cpp | 2 +- Studio/CMakeLists.txt | 11 --- Studio/DeepSSM/DeepSSMTool.cpp | 2 +- Studio/Interface/ShapeWorksStudioApp.cpp | 2 +- Studio/Interface/ShapeWorksStudioApp.h | 2 +- Studio/Job/ShapeScalarJob.cpp | 2 +- Studio/ShapeWorksMONAI/MonaiLabelTool.cpp | 2 +- 15 files changed, 93 insertions(+), 38 deletions(-) rename {Studio/Python => Libs/Application/Job}/PythonWorker.cpp (96%) rename {Studio/Python => Libs/Application/Job}/PythonWorker.h (88%) rename {Studio/Visualization => Libs/Application}/ShapeWorksVtkOutputWindow.cpp (100%) rename {Studio/Visualization => Libs/Application}/ShapeWorksVtkOutputWindow.h (100%) diff --git a/Applications/shapeworks/Commands.cpp b/Applications/shapeworks/Commands.cpp index d78fea6d0a1..02a43b6db60 100644 --- a/Applications/shapeworks/Commands.cpp +++ b/Applications/shapeworks/Commands.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -11,6 +12,7 @@ #include #include +#include #include namespace shapeworks { @@ -350,7 +352,7 @@ void DeepSSMCommand::buildParser() { .action("store") .type("choice") .choices(prep_choices.begin(), prep_choices.end()) - .set_default("all") + //.set_default("all") .help("Preparation step to run"); // Boolean flag options @@ -366,6 +368,11 @@ void DeepSSMCommand::buildParser() { } bool DeepSSMCommand::execute(const optparse::Values& options, SharedCommandData& sharedData) { + // Create a non-gui QApplication instance + int argc = 0; + char** argv = nullptr; + QApplication app(argc, argv); + // Handle project file: either from --name or first positional argument std::string project_file; if (options.is_set_by_user("name")) { @@ -379,13 +386,26 @@ bool DeepSSMCommand::execute(const optparse::Values& options, SharedCommandData& parser.error("Project file must be provided either as --name or as a positional argument"); } + // Handle prep option with manual default + std::string prep_step; + if (options.is_set_by_user("prep")) { + prep_step = options["prep"]; + } else { + prep_step = "all"; // Manual default + } + std::cout << "DeepSSM: Using project file: " << project_file << std::endl; bool do_prep = options.is_set("prep") || options.is_set("all"); - std::string prep_step = options["prep"]; bool do_augment = options.is_set("augment") || options.is_set("all"); bool do_train = options.is_set("train") || options.is_set("all"); bool do_test = options.is_set("test") || options.is_set("all"); + + std::cout << "Prep step: " << (do_prep ? "on" : "off") << "\n"; + std::cout << "Augment step: " << (do_augment ? "on" : "off") << "\n"; + std::cout << "Train step: " << (do_train ? "on" : "off") << "\n"; + std::cout << "Test step: " << (do_test ? "on" : "off") << "\n"; + if (!do_prep && !do_augment && !do_train && !do_test) { do_prep = true; do_augment = true; @@ -396,42 +416,73 @@ bool DeepSSMCommand::execute(const optparse::Values& options, SharedCommandData& ProjectHandle project = std::make_shared(); project->load(project_file); - DeepSSMJob job(project, DeepSSMJob::JobType::DeepSSM_PrepType); + PythonWorker python_worker; + + auto wait_for_job = [&](auto job) { + // This lambda will block until the job is complete + while (!job->is_complete()) { + QCoreApplication::processEvents(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if (job->is_aborted()) { + return false; + } + } + return true; + }; if (do_prep) { + auto job = QSharedPointer::create(project, DeepSSMJob::JobType::DeepSSM_PrepType); if (prep_step == "all") { - job.set_prep_step(DeepSSMJob::PrepStep::NOT_STARTED); + job->set_prep_step(DeepSSMJob::PrepStep::NOT_STARTED); } else if (prep_step == "groom_training") { - job.set_prep_step(DeepSSMJob::PrepStep::GROOM_TRAINING); + job->set_prep_step(DeepSSMJob::PrepStep::GROOM_TRAINING); } else if (prep_step == "optimize_training") { - job.set_prep_step(DeepSSMJob::PrepStep::OPTIMIZE_TRAINING); + job->set_prep_step(DeepSSMJob::PrepStep::OPTIMIZE_TRAINING); } else if (prep_step == "optimize_validation") { - job.set_prep_step(DeepSSMJob::PrepStep::OPTIMIZE_VALIDATION); + job->set_prep_step(DeepSSMJob::PrepStep::OPTIMIZE_VALIDATION); } else if (prep_step == "groom_images") { - job.set_prep_step(DeepSSMJob::PrepStep::GROOM_IMAGES); + job->set_prep_step(DeepSSMJob::PrepStep::GROOM_IMAGES); } else { SW_ERROR("Unknown prep step: {}", prep_step); return false; } std::cout << "Running DeepSSM preparation step...\n"; - job.run_prep(); + python_worker.run_job(job); + if (!wait_for_job(job)) { + return false; + } + std::cout << "DeepSSM preparation step completed.\n"; } if (do_augment) { std::cout << "Running DeepSSM data augmentation...\n"; - job.run_augmentation(); + auto job = QSharedPointer::create(project, DeepSSMJob::JobType::DeepSSM_AugmentationType); + python_worker.run_job(job); + if (!wait_for_job(job)) { + return false; + } + std::cout << "DeepSSM data augmentation completed.\n"; } if (do_train) { std::cout << "Running DeepSSM training...\n"; - job.run_training(); + auto job = QSharedPointer::create(project, DeepSSMJob::JobType::DeepSSM_TrainingType); + python_worker.run_job(job); + if (!wait_for_job(job)) { + return false; + } + std::cout << "DeepSSM training completed.\n"; } if (do_test) { std::cout << "Running DeepSSM testing...\n"; - job.run_testing(); + auto job = QSharedPointer::create(project, DeepSSMJob::JobType::DeepSSM_TestingType); + python_worker.run_job(job); + if (!wait_for_job(job)) { + return false; + } + std::cout << "DeepSSM testing completed.\n"; } project->save(); - SW_ERROR("DeepSSM command is not implemented yet."); return false; } diff --git a/Libs/Application/CMakeLists.txt b/Libs/Application/CMakeLists.txt index 66d9c58d597..85ab2b6728a 100644 --- a/Libs/Application/CMakeLists.txt +++ b/Libs/Application/CMakeLists.txt @@ -1,6 +1,8 @@ SET(APPLICATION_MOC_HDRS DeepSSM/DeepSSMJob.h Job/Job.h + Job/PythonWorker.h + ShapeWorksVtkOutputWindow.h ) qt5_wrap_cpp( APPLICATION_MOC_SRCS ${APPLICATION_MOC_HDRS} ) @@ -11,6 +13,8 @@ SET(Application_headers add_library(Application STATIC DeepSSM/DeepSSMJob.cpp Job/Job.cpp + Job/PythonWorker.cpp + ShapeWorksVtkOutputWindow.cpp ${APPLICATION_MOC_SRCS} ) diff --git a/Libs/Application/Job/Job.h b/Libs/Application/Job/Job.h index 00f9976c9c3..24bbea6ddb9 100644 --- a/Libs/Application/Job/Job.h +++ b/Libs/Application/Job/Job.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace shapeworks { @@ -62,3 +63,6 @@ class Job : public QObject { QElapsedTimer timer_; }; } // namespace shapeworks + + +Q_DECLARE_METATYPE(QSharedPointer); diff --git a/Studio/Python/PythonWorker.cpp b/Libs/Application/Job/PythonWorker.cpp similarity index 96% rename from Studio/Python/PythonWorker.cpp rename to Libs/Application/Job/PythonWorker.cpp index 7f13d728f94..eba40420fd8 100644 --- a/Studio/Python/PythonWorker.cpp +++ b/Libs/Application/Job/PythonWorker.cpp @@ -7,15 +7,14 @@ namespace py = pybind11; using namespace pybind11::literals; // to bring in the `_a` literal +#include #include -#include -#include #include #include #include +#include #include -#include namespace shapeworks { @@ -58,6 +57,8 @@ PYBIND11_EMBEDDED_MODULE(logger, m) { PythonWorker::PythonWorker() { python_logger_ = QSharedPointer::create(); + qRegisterMetaType>("QSharedPointer"); + // create singular Python thread and move this object to the new thread thread_ = new QThread(this); moveToThread(thread_); @@ -67,8 +68,10 @@ PythonWorker::PythonWorker() { //--------------------------------------------------------------------------- PythonWorker::~PythonWorker() { end_python(); - thread_->wait(); - delete thread_; + if (thread_) { + thread_->wait(); + delete thread_; + } } //--------------------------------------------------------------------------- @@ -109,6 +112,9 @@ void PythonWorker::run_job(QSharedPointer job) { QMetaObject::invokeMethod(this, "start_job", Qt::QueuedConnection, Q_ARG(QSharedPointer, job)); } +//--------------------------------------------------------------------------- +void PythonWorker::set_current_job(QSharedPointer job) { current_job_ = job; } + //--------------------------------------------------------------------------- bool PythonWorker::init() { std::string script = "install_shapeworks.sh"; diff --git a/Studio/Python/PythonWorker.h b/Libs/Application/Job/PythonWorker.h similarity index 88% rename from Studio/Python/PythonWorker.h rename to Libs/Application/Job/PythonWorker.h index 2eaa430c144..3881c9fbb90 100644 --- a/Studio/Python/PythonWorker.h +++ b/Libs/Application/Job/PythonWorker.h @@ -9,7 +9,7 @@ // studio #include -#include +#include namespace shapeworks { class PythonLogger; @@ -26,6 +26,7 @@ class PythonWorker : public QObject { void set_vtk_output_window(vtkSmartPointer output_window); void run_job(QSharedPointer job); + void set_current_job(QSharedPointer job); void incoming_python_message(std::string message_string); void incoming_python_progress(double value, std::string message); @@ -57,6 +58,6 @@ class PythonWorker : public QObject { QSharedPointer current_job_; - QThread* thread_; + QThread* thread_{nullptr}; }; } // namespace shapeworks diff --git a/Studio/Visualization/ShapeWorksVtkOutputWindow.cpp b/Libs/Application/ShapeWorksVtkOutputWindow.cpp similarity index 100% rename from Studio/Visualization/ShapeWorksVtkOutputWindow.cpp rename to Libs/Application/ShapeWorksVtkOutputWindow.cpp diff --git a/Studio/Visualization/ShapeWorksVtkOutputWindow.h b/Libs/Application/ShapeWorksVtkOutputWindow.h similarity index 100% rename from Studio/Visualization/ShapeWorksVtkOutputWindow.h rename to Libs/Application/ShapeWorksVtkOutputWindow.h diff --git a/Studio/Analysis/AnalysisTool.cpp b/Studio/Analysis/AnalysisTool.cpp index d952fb19bed..0e9d6b52f93 100644 --- a/Studio/Analysis/AnalysisTool.cpp +++ b/Studio/Analysis/AnalysisTool.cpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/Studio/Analysis/ShapeScalarPanel.cpp b/Studio/Analysis/ShapeScalarPanel.cpp index e5b49790945..0e420df1004 100644 --- a/Studio/Analysis/ShapeScalarPanel.cpp +++ b/Studio/Analysis/ShapeScalarPanel.cpp @@ -10,8 +10,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/Studio/CMakeLists.txt b/Studio/CMakeLists.txt index a90472ddea6..b7cfafd1c73 100644 --- a/Studio/CMakeLists.txt +++ b/Studio/CMakeLists.txt @@ -126,13 +126,6 @@ SET(STUDIO_GROOM_MOC_HDRS Groom/GroomTool.h ) -SET(STUDIO_PYTHON_SRCS - Python/PythonWorker.cpp - ) -SET(STUDIO_PYTHON_MOC_HDRS - Python/PythonWorker.h - ) - SET(STUDIO_OPTIMIZE_SRCS Optimize/OptimizeTool.cpp Optimize/QOptimize.cpp @@ -228,14 +221,12 @@ SET(STUDIO_VISUALIZATION_SRCS Visualization/MeshSlice.cpp Visualization/Viewer.cpp Visualization/Visualizer.cpp - Visualization/ShapeWorksVtkOutputWindow.cpp Visualization/StudioHandleWidget.cpp ) SET(STUDIO_VISUALIZATION_MOC_HDRS Visualization/Lightbox.h Visualization/ParticleColors.h - Visualization/ShapeWorksVtkOutputWindow.h Visualization/Visualizer.h ) @@ -246,7 +237,6 @@ SET(STUDIO_SRCS ${STUDIO_DEEPSSM_SRCS} ${STUDIO_MONAILABEL_SRCS} ${STUDIO_GROOM_SRCS} - ${STUDIO_PYTHON_SRCS} ${STUDIO_INTERFACE_SRCS} ${STUDIO_OPTIMIZE_SRCS} ${STUDIO_UTILS_SRCS} @@ -260,7 +250,6 @@ SET(STUDIO_MOC_HDRS ${STUDIO_DEEPSSM_MOC_HDRS} ${STUDIO_MONAILABEL_MOC_HDRS} ${STUDIO_GROOM_MOC_HDRS} - ${STUDIO_PYTHON_MOC_HDRS} ${STUDIO_INTERFACE_MOC_HDRS} ${STUDIO_OPTIMIZE_MOC_HDRS} ${STUDIO_UTILS_MOC_HDRS} diff --git a/Studio/DeepSSM/DeepSSMTool.cpp b/Studio/DeepSSM/DeepSSMTool.cpp index 0ca37279891..4a1ba2abe0b 100644 --- a/Studio/DeepSSM/DeepSSMTool.cpp +++ b/Studio/DeepSSM/DeepSSMTool.cpp @@ -7,9 +7,9 @@ #include // shapeworks +#include #include #include -#include // studio #include diff --git a/Studio/Interface/ShapeWorksStudioApp.cpp b/Studio/Interface/ShapeWorksStudioApp.cpp index e851546a84c..046eb7f8842 100644 --- a/Studio/Interface/ShapeWorksStudioApp.cpp +++ b/Studio/Interface/ShapeWorksStudioApp.cpp @@ -41,8 +41,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/Studio/Interface/ShapeWorksStudioApp.h b/Studio/Interface/ShapeWorksStudioApp.h index 89dd7149230..339459158c6 100644 --- a/Studio/Interface/ShapeWorksStudioApp.h +++ b/Studio/Interface/ShapeWorksStudioApp.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include diff --git a/Studio/Job/ShapeScalarJob.cpp b/Studio/Job/ShapeScalarJob.cpp index 4db36bcfab7..acde309d7a1 100644 --- a/Studio/Job/ShapeScalarJob.cpp +++ b/Studio/Job/ShapeScalarJob.cpp @@ -1,6 +1,6 @@ #include +#include #include -#include #include #include #include diff --git a/Studio/ShapeWorksMONAI/MonaiLabelTool.cpp b/Studio/ShapeWorksMONAI/MonaiLabelTool.cpp index 7f535c97651..a9e996cc198 100644 --- a/Studio/ShapeWorksMONAI/MonaiLabelTool.cpp +++ b/Studio/ShapeWorksMONAI/MonaiLabelTool.cpp @@ -3,8 +3,8 @@ #include #include #include +#include #include -#include #include #include #include From 005a68bee1504084ba4dce41483a1a7a781e1573 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 18 Aug 2025 16:21:22 -0600 Subject: [PATCH 10/13] Use offscreen for deepssm command --- Applications/shapeworks/Commands.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Applications/shapeworks/Commands.cpp b/Applications/shapeworks/Commands.cpp index 02a43b6db60..11a4d492c4d 100644 --- a/Applications/shapeworks/Commands.cpp +++ b/Applications/shapeworks/Commands.cpp @@ -369,8 +369,12 @@ void DeepSSMCommand::buildParser() { bool DeepSSMCommand::execute(const optparse::Values& options, SharedCommandData& sharedData) { // Create a non-gui QApplication instance - int argc = 0; - char** argv = nullptr; + int argc = 3; + char* argv[3]; + argv[0] = const_cast("shapeworks"); + argv[1] = const_cast("-platform"); + argv[2] = const_cast("offscreen"); + QApplication app(argc, argv); // Handle project file: either from --name or first positional argument From 8b598c0c7c8e7020c43f2850a30edf8583eef10a Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Mon, 18 Aug 2025 23:04:44 -0600 Subject: [PATCH 11/13] Adding check for CLI mode, to hide some messages --- Applications/shapeworks/Commands.cpp | 1 + Libs/Application/Job/PythonWorker.cpp | 12 +++++++++++- Libs/Application/Job/PythonWorker.h | 1 + Python/DeepSSMUtilsPackage/DeepSSMUtils/run_utils.py | 1 + Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py | 3 ++- Python/shapeworks/shapeworks/utils.py | 7 +++++++ 6 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Applications/shapeworks/Commands.cpp b/Applications/shapeworks/Commands.cpp index 11a4d492c4d..f595c5837e5 100644 --- a/Applications/shapeworks/Commands.cpp +++ b/Applications/shapeworks/Commands.cpp @@ -421,6 +421,7 @@ bool DeepSSMCommand::execute(const optparse::Values& options, SharedCommandData& project->load(project_file); PythonWorker python_worker; + python_worker.set_cli_mode(true); auto wait_for_job = [&](auto job) { // This lambda will block until the job is complete diff --git a/Libs/Application/Job/PythonWorker.cpp b/Libs/Application/Job/PythonWorker.cpp index eba40420fd8..d82f0e9ff15 100644 --- a/Libs/Application/Job/PythonWorker.cpp +++ b/Libs/Application/Job/PythonWorker.cpp @@ -37,11 +37,17 @@ class PythonLogger { bool check_abort() { return aborted_; } + bool is_cli_mode() { return is_cli_mode_; } + + void set_cli_mode(bool cli) { is_cli_mode_ = cli; } + private: std::function callback_; std::function progress_callback_; std::atomic aborted_{false}; + + std::atomic is_cli_mode_{false}; }; //--------------------------------------------------------------------------- @@ -50,7 +56,8 @@ PYBIND11_EMBEDDED_MODULE(logger, m) { .def(py::init<>()) .def("log", &PythonLogger::cpp_log) .def("check_abort", &PythonLogger::check_abort) - .def("progress", &PythonLogger::cpp_progress); + .def("progress", &PythonLogger::cpp_progress) + .def("is_cli_mode", &PythonLogger::is_cli_mode); }; //--------------------------------------------------------------------------- @@ -79,6 +86,9 @@ void PythonWorker::set_vtk_output_window(vtkSmartPointerset_cli_mode(cli_mode); } + //--------------------------------------------------------------------------- void PythonWorker::start_job(QSharedPointer job) { if (init()) { diff --git a/Libs/Application/Job/PythonWorker.h b/Libs/Application/Job/PythonWorker.h index 3881c9fbb90..4044185e530 100644 --- a/Libs/Application/Job/PythonWorker.h +++ b/Libs/Application/Job/PythonWorker.h @@ -24,6 +24,7 @@ class PythonWorker : public QObject { ~PythonWorker(); void set_vtk_output_window(vtkSmartPointer output_window); + void set_cli_mode(bool cli_mode); void run_job(QSharedPointer job); void set_current_job(QSharedPointer job); diff --git a/Python/DeepSSMUtilsPackage/DeepSSMUtils/run_utils.py b/Python/DeepSSMUtilsPackage/DeepSSMUtils/run_utils.py index 6dc7b5bfdb4..18a48e8a4a8 100644 --- a/Python/DeepSSMUtilsPackage/DeepSSMUtils/run_utils.py +++ b/Python/DeepSSMUtilsPackage/DeepSSMUtils/run_utils.py @@ -538,6 +538,7 @@ def process_test_predictions(project, config_file): template_particles, template_mesh, pred_dir) print("Distances: ", distances) + print("Mean distance: ", np.mean(distances)) # write to csv file in deepssm_dir csv_file = f"{deepssm_dir}/test_distances.csv" diff --git a/Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py b/Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py index 38f97cf83f3..4c9a41aaf9a 100644 --- a/Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py +++ b/Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py @@ -167,7 +167,8 @@ def supervised_train(config_file): if sw_check_abort(): sw_message("Aborted") return - sw_message(f"Epoch {e}/{num_epochs}") + if not sw_is_cli_mode(): + sw_message(f"Epoch {e}/{num_epochs}") sw_progress(e / (num_epochs + 1)) torch.cuda.empty_cache() diff --git a/Python/shapeworks/shapeworks/utils.py b/Python/shapeworks/shapeworks/utils.py index 41f4e7a0bf8..0db266b6f10 100644 --- a/Python/shapeworks/shapeworks/utils.py +++ b/Python/shapeworks/shapeworks/utils.py @@ -198,6 +198,13 @@ def sw_check_abort(): else: return False +def sw_is_cli_mode(): + """Check if the current mode is CLI mode""" + global sw_logger + if sw_logger is not None: + return sw_logger.is_cli_mode() + else: + return False def sw_progress(progress, message=""): """If sw_logger is set, use it, otherwise do nothing""" From 73b8dbccc814aa800a9ed962ff429cb8c77b2b8b Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 19 Aug 2025 11:26:37 -0600 Subject: [PATCH 12/13] Add newline to fix epoch output --- Libs/Application/Job/PythonWorker.cpp | 1 + Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Libs/Application/Job/PythonWorker.cpp b/Libs/Application/Job/PythonWorker.cpp index d82f0e9ff15..e2169cb8628 100644 --- a/Libs/Application/Job/PythonWorker.cpp +++ b/Libs/Application/Job/PythonWorker.cpp @@ -47,6 +47,7 @@ class PythonLogger { std::atomic aborted_{false}; + //! Command line interface mode std::atomic is_cli_mode_{false}; }; diff --git a/Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py b/Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py index 4c9a41aaf9a..4ed97fcc492 100644 --- a/Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py +++ b/Python/DeepSSMUtilsPackage/DeepSSMUtils/trainer.py @@ -44,6 +44,8 @@ def log_print(logger, values): print(values[i], end=' ') else: print('%.5f' % values[i], end=' ') + # print a new line + print() # csv format string_values = [str(i) for i in values] @@ -230,6 +232,7 @@ def supervised_train(config_file): log_print(logger, ["Base_Training", e, last_learning_rate, train_mr_MSE, train_rel_err, val_mr_MSE, val_rel_err, time.time() - t0]) + # plot epochs.append(e) plot_train_losses.append(train_mr_MSE) From 46c68c912f84999edfa2d8d54ff42b6261d52d8b Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 19 Aug 2025 12:52:11 -0600 Subject: [PATCH 13/13] Application library should depend on Project --- Libs/Application/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Libs/Application/CMakeLists.txt b/Libs/Application/CMakeLists.txt index 85ab2b6728a..bab42215742 100644 --- a/Libs/Application/CMakeLists.txt +++ b/Libs/Application/CMakeLists.txt @@ -34,6 +34,7 @@ target_link_libraries(Application PUBLIC Mesh Utils Particles + Project ${SW_PYTHON_LIBS} )