diff --git a/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp new file mode 100644 index 0000000000..c975a580b5 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp @@ -0,0 +1,165 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +// MITK +#include "mitkTotalSegmentatorTool.h" + + +#include "mitkIOUtil.h" +#include +#include "mitkProcessExecutor.h" + +// us +#include +#include +#include +#include +#include + +namespace mitk +{ + MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, TotalSegmentatorTool, "Total Segmentator"); +} + +mitk::TotalSegmentatorTool::TotalSegmentatorTool() +{ + this->SetMitkTempDir(IOUtil::CreateTemporaryDirectory("mitk-XXXXXX")); +} + +mitk::TotalSegmentatorTool::~TotalSegmentatorTool() +{ + itksys::SystemTools::RemoveADirectory(this->GetMitkTempDir()); +} + +void mitk::TotalSegmentatorTool::Activated() +{ + Superclass::Activated(); + this->SetLabelTransferMode(LabelTransferMode::AllLabels); +} + +const char **mitk::TotalSegmentatorTool::GetXPM() const +{ + return nullptr; +} + +us::ModuleResource mitk::TotalSegmentatorTool::GetIconResource() const +{ + us::Module *module = us::GetModuleContext()->GetModule(); + us::ModuleResource resource = module->GetResource("AI.svg"); + return resource; +} + +const char *mitk::TotalSegmentatorTool::GetName() const +{ + return "Total Segmentator"; +} + +namespace +{ + void onPythonProcessEvent(itk::Object * /*pCaller*/, const itk::EventObject &e, void *) + { + std::string testCOUT; + std::string testCERR; + const auto *pEvent = dynamic_cast(&e); + + if (pEvent) + { + testCOUT = testCOUT + pEvent->GetOutput(); + MITK_INFO << testCOUT; + } + + const auto *pErrEvent = dynamic_cast(&e); + + if (pErrEvent) + { + testCERR = testCERR + pErrEvent->GetOutput(); + MITK_ERROR << testCERR; + } + } +} // namespace + + +void mitk::TotalSegmentatorTool::DoUpdatePreview(const Image *inputAtTimeStep, + const Image * /*oldSegAtTimeStep*/, + LabelSetImage *previewImage, + TimeStepType timeStep) +{ + std::string inDir, outDir, inputImagePath, outputImagePath, scriptPath; + + ProcessExecutor::Pointer spExec = ProcessExecutor::New(); + itk::CStyleCommand::Pointer spCommand = itk::CStyleCommand::New(); + spCommand->SetCallback(&onPythonProcessEvent); + spExec->AddObserver(ExternalProcessOutputEvent(), spCommand); + + inDir = IOUtil::CreateTemporaryDirectory("totalseg-in-XXXXXX", this->GetMitkTempDir()); + std::ofstream tmpStream; + inputImagePath = IOUtil::CreateTemporaryFile(tmpStream, m_TEMPLATE_FILENAME, inDir + IOUtil::GetDirectorySeparator()); + tmpStream.close(); + std::size_t found = inputImagePath.find_last_of(IOUtil::GetDirectorySeparator()); + std::string fileName = inputImagePath.substr(found + 1); + std::string token = fileName.substr(0, fileName.find("_")); + outDir = IOUtil::CreateTemporaryDirectory("totalseg-out-XXXXXX", this->GetMitkTempDir()); + outputImagePath = outDir + IOUtil::GetDirectorySeparator() + token + "_000.nii.gz"; + ProcessExecutor::ArgumentListType args; + + MITK_INFO << inputImagePath; + MITK_INFO << outputImagePath; + + IOUtil::Save(inputAtTimeStep, inputImagePath); + + // Code calls external process + std::string command = "TotalSegmentator"; +#ifdef _WIN32 + command = "python"; +#else + command = "TotalSegmentator"; +#endif + + args.clear(); + +#ifdef _WIN32 + args.push_back("TotalSegmentator"); +#endif + + args.push_back("-i"); + args.push_back(inputImagePath); + + args.push_back("-o"); + args.push_back(outputImagePath); + + args.push_back("--ml"); + + try + { + std::string cudaEnv = "CUDA_VISIBLE_DEVICES=" + std::to_string(this->GetGpuId()); + itksys::SystemTools::PutEnv(cudaEnv.c_str()); + + for (auto &arg : args) + MITK_INFO << arg; + MITK_INFO << this->GetPythonPath(); + + spExec->Execute(this->GetPythonPath(), command, args); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + return; + } + + Image::Pointer outputImage = IOUtil::Load(outputImagePath); + auto outputBuffer = mitk::LabelSetImage::New(); + outputBuffer->InitializeByLabeledImage(outputImage); + outputBuffer->SetGeometry(inputAtTimeStep->GetGeometry()); + + TransferLabelSetImageContent(outputBuffer, previewImage, timeStep); + +} diff --git a/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.h b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.h new file mode 100644 index 0000000000..7df467d055 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.h @@ -0,0 +1,76 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ +#ifndef MITKTOTALSEGMENTATORTOOL_H +#define MITKTOTALSEGMENTATORTOOL_H + +#include "mitkSegWithPreviewTool.h" +#include + + +namespace us +{ + class ModuleResource; +} + +namespace mitk +{ + + class MITKSEGMENTATION_EXPORT TotalSegmentatorTool : public SegWithPreviewTool + { + public: + mitkClassMacro(TotalSegmentatorTool, SegWithPreviewTool); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + const char *GetName() const override; + const char **GetXPM() const override; + us::ModuleResource GetIconResource() const override; + + void Activated() override; + + itkSetMacro(MitkTempDir, std::string); + itkGetConstMacro(MitkTempDir, std::string); + + itkSetMacro(PythonPath, std::string); + itkGetConstMacro(PythonPath, std::string); + + itkSetMacro(GpuId, unsigned int); + itkGetConstMacro(GpuId, unsigned int); + + protected: + TotalSegmentatorTool(); + ~TotalSegmentatorTool(); + + /** + * @brief Overriden method from the tool manager to execute the segmentation + * Implementation: + * 1. Saves the inputAtTimeStep in a temporary directory. + * 3. Sets CUDA_VISIBLE_DEVICES variables in the environment. + * 3. Executes "TotalSegmentator" command with the parameters + * 4. Expects an output image to be saved in the temporary directory by the python proces. Loads it as + * LabelSetImage and sets to previewImage. + * + * @param inputAtTimeStep + * @param oldSegAtTimeStep + * @param previewImage + * @param timeStep + */ + void DoUpdatePreview(const Image* inputAtTimeStep, const Image* oldSegAtTimeStep, LabelSetImage* previewImage, TimeStepType timeStep) override; + + private: + std::string m_MitkTempDir; + std::string m_PythonPath; + unsigned int m_GpuId; + const std::string m_TEMPLATE_FILENAME = "XXXXXX_000_0000.nii.gz"; + }; // class +} // namespace +#endif diff --git a/Modules/Segmentation/files.cmake b/Modules/Segmentation/files.cmake index 4520f0edc0..a91d62226e 100644 --- a/Modules/Segmentation/files.cmake +++ b/Modules/Segmentation/files.cmake @@ -1,117 +1,118 @@ set(CPP_FILES Algorithms/mitkCalculateSegmentationVolume.cpp Algorithms/mitkContourModelSetToImageFilter.cpp Algorithms/mitkContourSetToPointSetFilter.cpp Algorithms/mitkContourUtils.cpp Algorithms/mitkCorrectorAlgorithm.cpp Algorithms/mitkDiffImageApplier.cpp Algorithms/mitkDiffSliceOperation.cpp Algorithms/mitkDiffSliceOperationApplier.cpp Algorithms/mitkFeatureBasedEdgeDetectionFilter.cpp Algorithms/mitkGrowCutSegmentationFilter.cpp Algorithms/mitkImageLiveWireContourModelFilter.cpp Algorithms/mitkImageToContourFilter.cpp #Algorithms/mitkImageToContourModelFilter.cpp Algorithms/mitkImageToLiveWireContourFilter.cpp Algorithms/mitkManualSegmentationToSurfaceFilter.cpp Algorithms/mitkOtsuSegmentationFilter.cpp Algorithms/mitkSegmentationHelper.cpp Algorithms/mitkSegmentationObjectFactory.cpp Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp Algorithms/mitkShowSegmentationAsSurface.cpp Algorithms/mitkVtkImageOverwrite.cpp Controllers/mitkSegmentationInterpolationController.cpp Controllers/mitkToolManager.cpp Controllers/mitkSegmentationModuleActivator.cpp Controllers/mitkToolManagerProvider.cpp DataManagement/mitkContour.cpp DataManagement/mitkContourSet.cpp DataManagement/mitkExtrudedContour.cpp Interactions/mitkAddContourTool.cpp Interactions/mitkAutoCropTool.cpp Interactions/mitkSegWithPreviewTool.cpp Interactions/mitkBinaryThresholdBaseTool.cpp Interactions/mitkBinaryThresholdTool.cpp Interactions/mitkBinaryThresholdULTool.cpp Interactions/mitkCloseRegionTool.cpp Interactions/mitkContourModelInteractor.cpp Interactions/mitkContourModelLiveWireInteractor.cpp Interactions/mitkEditableContourTool.cpp Interactions/mitkLiveWireTool2D.cpp Interactions/mitkLassoTool.cpp Interactions/mitkContourTool.cpp Interactions/mitkDrawPaintbrushTool.cpp Interactions/mitkErasePaintbrushTool.cpp Interactions/mitkEraseRegionTool.cpp Interactions/mitkFeedbackContourTool.cpp Interactions/mitkFillRegionBaseTool.cpp Interactions/mitkFillRegionTool.cpp Interactions/mitkGrowCutTool.cpp Interactions/mitkOtsuTool3D.cpp Interactions/mitkPaintbrushTool.cpp Interactions/mitkRegionGrowingTool.cpp Interactions/mitkSegmentationsProcessingTool.cpp Interactions/mitkSegTool2D.cpp Interactions/mitkSubtractContourTool.cpp Interactions/mitkTool.cpp Interactions/mitkToolCommand.cpp Interactions/mitkPickingTool.cpp Interactions/mitknnUnetTool.cpp Interactions/mitkSegmentationInteractor.cpp #SO Interactions/mitkProcessExecutor.cpp + Interactions/mitkTotalSegmentatorTool.cpp Rendering/mitkContourMapper2D.cpp Rendering/mitkContourSetMapper2D.cpp Rendering/mitkContourSetVtkMapper3D.cpp Rendering/mitkContourVtkMapper3D.cpp SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp #Added from ML Controllers/mitkSliceBasedInterpolationController.cpp Algorithms/mitkSurfaceStampImageFilter.cpp ) set(RESOURCE_FILES Add.svg Add_Cursor.svg AI.svg AI_Cursor.svg Close.svg Close_Cursor.svg Erase.svg Erase_Cursor.svg Fill.svg Fill_Cursor.svg LiveWire.svg LiveWire_Cursor.svg Lasso.svg GrowCut.svg Lasso_Cursor.svg Otsu.svg Paint.svg Paint_Cursor.svg Picking.svg RegionGrowing.svg RegionGrowing_Cursor.svg Subtract.svg Subtract_Cursor.svg Threshold.svg ULThreshold.svg Wipe.svg Wipe_Cursor.svg Interactions/dummy.xml Interactions/EditableContourTool.xml Interactions/PickingTool.xml Interactions/MouseReleaseOnly.xml Interactions/PressMoveRelease.xml Interactions/PressMoveReleaseAndPointSetting.xml Interactions/PressMoveReleaseWithCTRLInversion.xml Interactions/PressMoveReleaseWithCTRLInversionAllMouseMoves.xml Interactions/SegmentationConfig.xml Interactions/SegmentationInteraction.xml Interactions/SegmentationToolsConfig.xml Interactions/ContourModelModificationConfig.xml Interactions/ContourModelModificationInteractor.xml ) diff --git a/Modules/SegmentationUI/Qmitk/QmitkTotalSegmentatorGUIControls.ui b/Modules/SegmentationUI/Qmitk/QmitkTotalSegmentatorGUIControls.ui new file mode 100644 index 0000000000..41ec662b32 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkTotalSegmentatorGUIControls.ui @@ -0,0 +1,135 @@ + + + QmitkTotalSegmentatorToolGUIControls + + + + 0 + 0 + 699 + 352 + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 100000 + 100000 + + + + QmitkTotalSegmentatorToolWidget + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Welcome to Total Segmentator tool in MITK. [Experimental]</p><p>Please note that this is only an interface to Total Segmentator. MITK does not ship with Total Segmentator. Make sure to have a working Python environment with nnUNet set up beforehand. Choose that environment in the Python Path before inferencing. </p><p>Refer to <a href="https://github.com/wasserth/TotalSegmentator"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/wasserth/TotalSegmentator</span></a> to learn everything about the Total Segmentator.</p><p><br/></p></body></html> + + + Qt::RichText + + + true + + + + + + + + 0 + 0 + + + + Python Path: + + + + + + + + + + + + + 0 + 0 + + + + + 100000 + 16777215 + + + + Run Total Segmentator + + + + + + + + 0 + 0 + + + + true + + + + + + + + ctkComboBox + QComboBox +
ctkComboBox.h
+ 1 +
+
+ + + + +
diff --git a/Modules/SegmentationUI/Qmitk/QmitkTotalSegmentatorToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkTotalSegmentatorToolGUI.cpp new file mode 100644 index 0000000000..2910088d54 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkTotalSegmentatorToolGUI.cpp @@ -0,0 +1,260 @@ +#include "QmitkTotalSegmentatorToolGUI.h" + +#include "usServiceReference.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mitkTotalSegmentatorTool.h" + + +MITK_TOOL_GUI_MACRO(MITKSEGMENTATIONUI_EXPORT, QmitkTotalSegmentatorToolGUI, "") + +QmitkTotalSegmentatorToolGUI::QmitkTotalSegmentatorToolGUI() + : QmitkMultiLabelSegWithPreviewToolGUIBase(), m_SuperclassEnableConfirmSegBtnFnc(m_EnableConfirmSegBtnFnc) +{ + // Nvidia-smi command returning zero doesn't always imply lack of GPUs. + // Pytorch uses its own libraries to communicate to the GPUs. Hence, only a warning can be given. + if (m_GpuLoader.GetGPUCount() == 0) + { + std::string warning = "WARNING: No GPUs were detected on your machine. The TotalSegmentator tool can be very slow."; + this->ShowErrorMessage(warning); + } + m_EnableConfirmSegBtnFnc = [this](bool enabled) + { return !m_FirstPreviewComputation ? m_SuperclassEnableConfirmSegBtnFnc(enabled) : false; }; +} + +void QmitkTotalSegmentatorToolGUI::ConnectNewTool(mitk::SegWithPreviewTool *newTool) +{ + Superclass::ConnectNewTool(newTool); + newTool->IsTimePointChangeAwareOff(); + m_FirstPreviewComputation = true; +} + +void QmitkTotalSegmentatorToolGUI::InitializeUI(QBoxLayout *mainLayout) +{ + m_Controls.setupUi(this); + m_Controls.pythonEnvComboBox->addItem("Select"); + m_Controls.previewButton->setDisabled(true); + m_Controls.statusLabel->setTextFormat(Qt::RichText); + AutoParsePythonPaths(); + if (m_GpuLoader.GetGPUCount() != 0) + { + WriteStatusMessage(QString("STATUS: Welcome to Total Segmentator tool. You're in luck: " + QString::number(m_GpuLoader.GetGPUCount()) + + " GPU(s) were detected.")); + } + else + { + WriteErrorMessage(QString("STATUS: Welcome to Total Segmentator tool. Sorry, " + QString::number(m_GpuLoader.GetGPUCount()) + + " GPUs were detected.")); + } + mainLayout->addLayout(m_Controls.verticalLayout); + + connect(m_Controls.previewButton, SIGNAL(clicked()), this, SLOT(OnPreviewBtnClicked())); + connect(m_Controls.pythonEnvComboBox, + SIGNAL(currentTextChanged(const QString &)), + this, + SLOT(OnPythonPathChanged(const QString &))); + + Superclass::InitializeUI(mainLayout); + + QString lastSelectedPyEnv = m_Settings.value("TotalSeg/LastPythonPath").toString(); + m_Controls.pythonEnvComboBox->setCurrentText(lastSelectedPyEnv); +} + +void QmitkTotalSegmentatorToolGUI::EnableWidgets(bool enabled) +{ + Superclass::EnableWidgets(enabled); +} + + +void QmitkTotalSegmentatorToolGUI::OnPreviewBtnClicked() +{ + auto tool = this->GetConnectedToolAs(); + if (nullptr == tool) + { + return; + } + QString pythonPathTextItem = ""; + try + { + m_Controls.previewButton->setEnabled(false); + qApp->processEvents(); + pythonPathTextItem = m_Controls.pythonEnvComboBox->currentText(); + + if (!this->IsTotalSegmentatorInstalled(m_PythonPath)) + { + throw std::runtime_error("TotalSegmentator is not detected in the selected python environment. Please select a valid " + "python environment or install TotalSegmentator."); + } + tool->SetPythonPath(m_PythonPath.toStdString()); + tool->SetGpuId(0); + this->WriteStatusMessage(QString("STATUS: Starting Segmentation task... This might take a while.")); + tool->UpdatePreview(); + m_Controls.previewButton->setEnabled(true); + } + catch (const std::exception &e) + { + std::stringstream errorMsg; + errorMsg << "STATUS: Error while processing parameters for TotalSegmentator segmentation. Reason: " << e.what(); + this->ShowErrorMessage(errorMsg.str()); + this->WriteErrorMessage(QString::fromStdString(errorMsg.str())); + m_Controls.previewButton->setEnabled(true); + return; + } + catch (...) + { + std::string errorMsg = "Unkown error occured while generation TotalSegmentator segmentation."; + this->ShowErrorMessage(errorMsg); + m_Controls.previewButton->setEnabled(true); + return; + } + this->SetLabelSetPreview(tool->GetPreviewSegmentation()); + tool->IsTimePointChangeAwareOn(); + this->ActualizePreviewLabelVisibility(); + if (!pythonPathTextItem.isEmpty()) + { // only cache if the prediction ended without errors. + m_Settings.setValue("TotalSeg/LastPythonPath", pythonPathTextItem); + } +} + + +void QmitkTotalSegmentatorToolGUI::ShowErrorMessage(const std::string &message, QMessageBox::Icon icon) +{ + this->setCursor(Qt::ArrowCursor); + QMessageBox *messageBox = new QMessageBox(icon, nullptr, message.c_str()); + messageBox->exec(); + delete messageBox; + MITK_WARN << message; +} + +void QmitkTotalSegmentatorToolGUI::WriteStatusMessage(const QString &message) +{ + m_Controls.statusLabel->setText(message); + m_Controls.statusLabel->setStyleSheet("font-weight: bold; color: white"); +} + +void QmitkTotalSegmentatorToolGUI::WriteErrorMessage(const QString &message) +{ + m_Controls.statusLabel->setText(message); + m_Controls.statusLabel->setStyleSheet("font-weight: bold; color: red"); +} + + +bool QmitkTotalSegmentatorToolGUI::IsTotalSegmentatorInstalled(const QString &pythonPath) +{ + QString fullPath = pythonPath; +#ifdef _WIN32 + if (!(fullPath.endsWith("Scripts", Qt::CaseInsensitive) || fullPath.endsWith("Scripts/", Qt::CaseInsensitive))) + { + fullPath += QDir::separator() + QString("Scripts"); + } +#else + if (!(fullPath.endsWith("bin", Qt::CaseInsensitive) || fullPath.endsWith("bin/", Qt::CaseInsensitive))) + { + fullPath += QDir::separator() + QString("bin"); + } +#endif + fullPath = fullPath.mid(fullPath.indexOf(" ") + 1); + bool isExists = QFile::exists(fullPath + QDir::separator() + QString("TotalSegmentator")) && +#ifdef _WIN32 + QFile::exists(fullPath + QDir::separator() + QString("python.exe")); +#else + QFile::exists(fullPath + QDir::separator() + QString("python3")); +#endif + return isExists; +} + +void QmitkTotalSegmentatorToolGUI::AutoParsePythonPaths() +{ + + QString homeDir = QDir::homePath(); + std::vector searchDirs; +#ifdef _WIN32 + searchDirs.push_back(QString("C:") + QDir::separator() + QString("ProgramData") + QDir::separator() + + QString("anaconda3")); +#else + // Add search locations for possible standard python paths here + searchDirs.push_back(homeDir + QDir::separator() + "environments"); + searchDirs.push_back(homeDir + QDir::separator() + "anaconda3"); + searchDirs.push_back(homeDir + QDir::separator() + "miniconda3"); + searchDirs.push_back(homeDir + QDir::separator() + "opt" + QDir::separator() + "miniconda3"); + searchDirs.push_back(homeDir + QDir::separator() + "opt" + QDir::separator() + "anaconda3"); +#endif + for (QString searchDir : searchDirs) + { + if (searchDir.endsWith("anaconda3", Qt::CaseInsensitive)) + { + if (QDir(searchDir).exists()) + { + m_Controls.pythonEnvComboBox->insertItem(0, "(base): " + searchDir); + searchDir.append((QDir::separator() + QString("envs"))); + } + } + for (QDirIterator subIt(searchDir, QDir::AllDirs, QDirIterator::NoIteratorFlags); subIt.hasNext();) + { + subIt.next(); + QString envName = subIt.fileName(); + if (!envName.startsWith('.')) // Filter out irrelevent hidden folders, if any. + { + m_Controls.pythonEnvComboBox->insertItem(0, "(" + envName + "): " + subIt.filePath()); + } + } + } + m_Controls.pythonEnvComboBox->setCurrentIndex(-1); +} + +void QmitkTotalSegmentatorToolGUI::OnPythonPathChanged(const QString &pyEnv) +{ + if (pyEnv == QString("Select")) + { + QString path = + QFileDialog::getExistingDirectory(m_Controls.pythonEnvComboBox->parentWidget(), "Python Path", "dir"); + if (!path.isEmpty()) + { + this->OnPythonPathChanged(path); // recall same function for new path validation + bool oldState = m_Controls.pythonEnvComboBox->blockSignals(true); // block signal firing while inserting item + m_Controls.pythonEnvComboBox->insertItem(0, path); + m_Controls.pythonEnvComboBox->setCurrentIndex(0); + m_Controls.pythonEnvComboBox->blockSignals(oldState); // unblock signal firing after inserting item. Remove this after Qt6 migration + } + } + else if (!this->IsTotalSegmentatorInstalled(pyEnv)) + { + std::string warning = + "WARNING: nnUNet is not detected on the Python environment you selected. Please select another " + "environment or create one. For more info refer https://github.com/MIC-DKFZ/nnUNet"; + this->ShowErrorMessage(warning); + m_Controls.previewButton->setDisabled(true); + } + else + { + // Show positive status meeage + m_Controls.previewButton->setDisabled(false); + m_PythonPath = pyEnv.mid(pyEnv.indexOf(" ") + 1); +#ifdef _WIN32 + if (!(m_PythonPath.endsWith("Scripts", Qt::CaseInsensitive) || + m_PythonPath.endsWith("Scripts/", Qt::CaseInsensitive))) + { + m_PythonPath += QDir::separator() + QString("Scripts"); + } +#else + if (!(m_PythonPath.endsWith("bin", Qt::CaseInsensitive) || m_PythonPath.endsWith("bin/", Qt::CaseInsensitive))) + { + m_PythonPath += QDir::separator() + QString("bin"); + } +#endif + } +} diff --git a/Modules/SegmentationUI/Qmitk/QmitkTotalSegmentatorToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkTotalSegmentatorToolGUI.h new file mode 100644 index 0000000000..4ac8977cd6 --- /dev/null +++ b/Modules/SegmentationUI/Qmitk/QmitkTotalSegmentatorToolGUI.h @@ -0,0 +1,80 @@ +#ifndef QmitkTotalSegmentatorToolGUI_h_Included +#define QmitkTotalSegmentatorToolGUI_h_Included + +#include "QmitkMultiLabelSegWithPreviewToolGUIBase.h" +#include "ui_QmitkTotalSegmentatorGUIControls.h" +#include +#include +#include "QmitknnUNetGPU.h" +#include + + +class MITKSEGMENTATIONUI_EXPORT QmitkTotalSegmentatorToolGUI : public QmitkMultiLabelSegWithPreviewToolGUIBase +{ + Q_OBJECT + +public: + mitkClassMacro(QmitkTotalSegmentatorToolGUI, QmitkMultiLabelSegWithPreviewToolGUIBase); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + +protected slots : + + void OnPreviewBtnClicked(); + + /** + * @brief Qt Slot + */ + void OnPythonPathChanged(const QString &); + +protected: + QmitkTotalSegmentatorToolGUI(); + ~QmitkTotalSegmentatorToolGUI() = default; + + void ConnectNewTool(mitk::SegWithPreviewTool* newTool) override; + void InitializeUI(QBoxLayout* mainLayout) override; + + void EnableWidgets(bool enabled) override; + + /** + * @brief Searches and parses paths of python virtual enviroments + * from predefined lookout locations + */ + void AutoParsePythonPaths(); + + /** + * @brief Checks if TotalSegmentator command is valid in the selected python virtual environment. + * + * @return bool + */ + bool IsTotalSegmentatorInstalled(const QString &); + + /** + * @brief Creates a QMessage object and shows on screen. + */ + void ShowErrorMessage(const std::string &, QMessageBox::Icon = QMessageBox::Critical); + + /** + * @brief Writes any message in white on the tool pane. + */ + void WriteStatusMessage(const QString &); + + /** + * @brief Writes any message in red on the tool pane. + */ + void WriteErrorMessage(const QString &); + + /** + * @brief For storing values like Python path across sessions. + */ + QSettings m_Settings; + + QString m_PythonPath; + QmitkGPULoader m_GpuLoader; + Ui_QmitkTotalSegmentatorToolGUIControls m_Controls; + bool m_FirstPreviewComputation = true; + EnableConfirmSegBtnFunctionType m_SuperclassEnableConfirmSegBtnFnc; + +}; + +#endif diff --git a/Modules/SegmentationUI/files.cmake b/Modules/SegmentationUI/files.cmake index adfa9a06ad..a9413ab463 100644 --- a/Modules/SegmentationUI/files.cmake +++ b/Modules/SegmentationUI/files.cmake @@ -1,99 +1,102 @@ set(CPP_FILES Qmitk/QmitkSegWithPreviewToolGUIBase.cpp Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.cpp Qmitk/QmitkBinaryThresholdToolGUIBase.cpp Qmitk/QmitkBinaryThresholdToolGUI.cpp Qmitk/QmitkBinaryThresholdULToolGUI.cpp Qmitk/QmitkConfirmSegmentationDialog.cpp Qmitk/QmitkCopyToClipBoardDialog.cpp Qmitk/QmitkDrawPaintbrushToolGUI.cpp Qmitk/QmitkErasePaintbrushToolGUI.cpp Qmitk/QmitkEditableContourToolGUIBase.cpp Qmitk/QmitkGrowCutToolGUI.cpp Qmitk/QmitkLiveWireTool2DGUI.cpp Qmitk/QmitkLassoToolGUI.cpp Qmitk/QmitkOtsuTool3DGUI.cpp Qmitk/QmitkPaintbrushToolGUI.cpp Qmitk/QmitkPickingToolGUI.cpp Qmitk/QmitkSlicesInterpolator.cpp Qmitk/QmitkToolGUI.cpp Qmitk/QmitkToolGUIArea.cpp Qmitk/QmitkToolSelectionBox.cpp Qmitk/QmitknnUNetFolderParser.cpp Qmitk/QmitknnUNetToolGUI.cpp Qmitk/QmitknnUNetWorker.cpp Qmitk/QmitknnUNetGPU.cpp Qmitk/QmitkSurfaceStampWidget.cpp Qmitk/QmitkMaskStampWidget.cpp Qmitk/QmitkStaticDynamicSegmentationDialog.cpp Qmitk/QmitkSurfaceBasedInterpolatorWidget.cpp Qmitk/QmitkSimpleLabelSetListWidget.cpp + Qmitk/QmitkTotalSegmentatorToolGUI.cpp SegmentationUtilities/QmitkBooleanOperationsWidget.cpp SegmentationUtilities/QmitkContourModelToImageWidget.cpp SegmentationUtilities/QmitkImageMaskingWidget.cpp SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp SegmentationUtilities/QmitkSurfaceToImageWidget.cpp SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp SegmentationUtilities/QmitkDataSelectionWidget.cpp ) set(MOC_H_FILES Qmitk/QmitkSegWithPreviewToolGUIBase.h Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.h Qmitk/QmitkBinaryThresholdToolGUIBase.h Qmitk/QmitkBinaryThresholdToolGUI.h Qmitk/QmitkBinaryThresholdULToolGUI.h Qmitk/QmitkConfirmSegmentationDialog.h Qmitk/QmitkCopyToClipBoardDialog.h Qmitk/QmitkDrawPaintbrushToolGUI.h Qmitk/QmitkErasePaintbrushToolGUI.h Qmitk/QmitkEditableContourToolGUIBase.h Qmitk/QmitkGrowCutToolGUI.h Qmitk/QmitkLiveWireTool2DGUI.h Qmitk/QmitkLassoToolGUI.h Qmitk/QmitkOtsuTool3DGUI.h Qmitk/QmitkPaintbrushToolGUI.h Qmitk/QmitkPickingToolGUI.h Qmitk/QmitkSlicesInterpolator.h Qmitk/QmitkToolGUI.h Qmitk/QmitkToolGUIArea.h Qmitk/QmitkToolSelectionBox.h Qmitk/QmitknnUNetFolderParser.h Qmitk/QmitknnUNetToolGUI.h Qmitk/QmitknnUNetGPU.h Qmitk/QmitknnUNetWorker.h Qmitk/QmitknnUNetEnsembleLayout.h Qmitk/QmitkSurfaceStampWidget.h Qmitk/QmitkMaskStampWidget.h Qmitk/QmitkStaticDynamicSegmentationDialog.h Qmitk/QmitkSurfaceBasedInterpolatorWidget.h Qmitk/QmitkSimpleLabelSetListWidget.h + Qmitk/QmitkTotalSegmentatorToolGUI.h SegmentationUtilities/QmitkBooleanOperationsWidget.h SegmentationUtilities/QmitkContourModelToImageWidget.h SegmentationUtilities/QmitkImageMaskingWidget.h SegmentationUtilities/QmitkMorphologicalOperationsWidget.h SegmentationUtilities/QmitkSurfaceToImageWidget.h SegmentationUtilities/QmitkSegmentationUtilityWidget.h SegmentationUtilities/QmitkDataSelectionWidget.h ) set(UI_FILES Qmitk/QmitkConfirmSegmentationDialog.ui Qmitk/QmitkGrowCutToolWidgetControls.ui Qmitk/QmitkOtsuToolWidgetControls.ui Qmitk/QmitkSurfaceStampWidgetGUIControls.ui Qmitk/QmitkMaskStampWidgetGUIControls.ui Qmitk/QmitkSurfaceBasedInterpolatorWidgetGUIControls.ui Qmitk/QmitknnUNetToolGUIControls.ui Qmitk/QmitkEditableContourToolGUIControls.ui + Qmitk/QmitkTotalSegmentatorGUIControls.ui SegmentationUtilities/QmitkBooleanOperationsWidgetControls.ui SegmentationUtilities/QmitkContourModelToImageWidgetControls.ui SegmentationUtilities/QmitkImageMaskingWidgetControls.ui SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui SegmentationUtilities/QmitkSurfaceToImageWidgetControls.ui SegmentationUtilities/QmitkDataSelectionWidgetControls.ui ) set(QRC_FILES resources/SegmentationUI.qrc )