diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui
index 8299ff1d6a..f04eece6e1 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui
+++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui
@@ -1,231 +1,169 @@
QmitkSegmentAnythingGUIControls
0
0
699
490
0
0
100
0
100000
100000
QmitkSegmentAnythingToolWidget
0
0
0
0
-
-
0
0
- <html><head/><body><p>Welcome to Segment Anything Model (SAM) tool in MITK. [Experimental]</p><p>Please note that this is only an interface to SAM. MITK does not ship with SAM. Make sure to have a working internet connection to install SAM via MITK.
- </p><p>Refer to <a href="https://segment-anything.com/"><span style=" text-decoration: underline; color:#0000ff;">https://segment-anything.com</span></a> to learn everything about the SAM.</p><p><br/></p></body></html>
+ <html><head/><body><p>Welcome to Segment Anything Model (SAM) tool in MITK. [Experimental]</p><p>Please note that this is only an interface to SAM. MITK does not ship with SAM. Make sure to have a working internet connection to install SAM via MITK. </p><p>Refer to <a href="https://segment-anything.com/"><span style=" text-decoration: underline; color:#0000ff;">https://segment-anything.com</span></a> to learn everything about the SAM.</p></body></html>
Qt::RichText
true
-
0
0
Press SHIFT+Left-click for positive seeds.
Press SHIFT+Right-click for negative seeds.
Press DEL to remove last seed.
-
- -
-
-
-
- 0
- 0
-
-
-
- Preferences
-
-
- true
-
-
- 5
-
-
- true
-
-
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 6
-
-
-
-
-
-
- 0
- 0
-
-
-
- GPU Id:
-
-
-
- -
-
-
-
-
-
-
-
-
-
0
0
100000
16777215
Reset Picks
-
0
0
100000
16777215
Activate SAM
-
0
0
true
-
- 1
-
-
- 0
+ 1
+
+
+ 0
false
ctkComboBox
QComboBox
1
ctkCollapsibleGroupBox
QWidget
diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp
index 9c416893da..9f5668f26f 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp
+++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp
@@ -1,341 +1,312 @@
/*============================================================================
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.
============================================================================*/
#include "QmitkSegmentAnythingToolGUI.h"
#include "mitkSegmentAnythingTool.h"
#include "mitkProcessExecutor.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
MITK_TOOL_GUI_MACRO(MITKSEGMENTATIONUI_EXPORT, QmitkSegmentAnythingToolGUI, "")
namespace
{
mitk::IPreferences *GetPreferences()
{
auto *preferencesService = mitk::CoreServices::GetPreferencesService();
return preferencesService->GetSystemPreferences()->Node("org.mitk.views.segmentation");
}
}
QmitkSegmentAnythingToolGUI::QmitkSegmentAnythingToolGUI() : QmitkSegWithPreviewToolGUIBase(true)
{
// 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 SegmentAnything tool can be very slow.";
this->ShowErrorMessage(warning);
}
m_EnableConfirmSegBtnFnc = [this](bool enabled)
{
bool result = false;
auto tool = this->GetConnectedToolAs();
if (nullptr != tool)
{
result = enabled && tool->HasPicks();
}
return result;
};
m_Prefences = GetPreferences();
}
void QmitkSegmentAnythingToolGUI::InitializeUI(QBoxLayout *mainLayout)
{
m_Controls.setupUi(this);
m_Controls.statusLabel->setTextFormat(Qt::RichText);
QString welcomeText;
- this->SetGPUInfo();
if (m_GpuLoader.GetGPUCount() != 0)
{
welcomeText = "STATUS: Welcome to Segment Anything tool. You're in luck: " +
QString::number(m_GpuLoader.GetGPUCount()) + " GPU(s) were detected.";
}
else
{
welcomeText = "STATUS: Welcome to Segment Anything tool. Sorry, " +
QString::number(m_GpuLoader.GetGPUCount()) + " GPUs were detected.";
}
connect(m_Controls.activateButton, SIGNAL(clicked()), this, SLOT(OnActivateBtnClicked()));
connect(m_Controls.resetButton, SIGNAL(clicked()), this, SLOT(OnResetPicksClicked()));
QIcon arrowIcon =
QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/go-next.svg"));
m_Controls.activateButton->setIcon(arrowIcon);
bool isInstalled = this->ValidatePrefences();
if (isInstalled)
{
m_PythonPath = QString::fromStdString(m_Prefences->Get("sam python path", ""));
- welcomeText += " SAM is already found installed.";
+ QString modelType = QString::fromStdString(m_Prefences->Get("sam modeltype", ""));
+ welcomeText += " SAM is already found installed. Model type '" + modelType + "' selected in Preferences.";
}
else
{
- welcomeText += " SAM is not configured correctly. Please go to Prefences (Cntl+P) to configure and/or install SAM.";
+ welcomeText += " SAM is not configured correctly. Please go to Preferences (Cntl+P) to configure and/or install SAM.";
}
this->EnableAll(isInstalled);
this->WriteStatusMessage(welcomeText);
this->ShowProgressBar(false);
m_Controls.samProgressBar->setMaximum(0);
mainLayout->addLayout(m_Controls.verticalLayout);
Superclass::InitializeUI(mainLayout);
}
bool QmitkSegmentAnythingToolGUI::ValidatePrefences()
{
const QString storageDir = QString::fromStdString(m_Prefences->Get("sam python path", ""));
bool isInstalled = QmitkSegmentAnythingToolGUI::IsSAMInstalled(storageDir);
- std::string modelType = m_Prefences->Get("sam modeltype", "");
- std::string path = m_Prefences->Get("sam parent path", "");
+ std::string &modelType = m_Prefences->Get("sam modeltype", "");
+ std::string &path = m_Prefences->Get("sam parent path", "");
return (isInstalled && !modelType.empty() && !path.empty());
}
void QmitkSegmentAnythingToolGUI::EnableAll(bool isEnable)
{
m_Controls.activateButton->setEnabled(isEnable);
}
-void QmitkSegmentAnythingToolGUI::SetGPUInfo()
-{
- std::vector specs = m_GpuLoader.GetAllGPUSpecs();
- for (const QmitkGPUSpec &gpuSpec : specs)
- {
- m_Controls.gpuComboBox->addItem(QString::number(gpuSpec.id) + ": " + gpuSpec.name + " (" + gpuSpec.memory + ")");
- }
- if (specs.empty())
- {
- m_Controls.gpuComboBox->setEditable(true);
- m_Controls.gpuComboBox->addItem(QString::number(0));
- m_Controls.gpuComboBox->setValidator(new QIntValidator(0, 999, this));
- }
-}
-
void QmitkSegmentAnythingToolGUI::WriteStatusMessage(const QString &message)
{
m_Controls.statusLabel->setText(message);
m_Controls.statusLabel->setStyleSheet("font-weight: bold; color: white");
qApp->processEvents();
}
void QmitkSegmentAnythingToolGUI::WriteErrorMessage(const QString &message)
{
m_Controls.statusLabel->setText(message);
m_Controls.statusLabel->setStyleSheet("font-weight: bold; color: red");
qApp->processEvents();
}
void QmitkSegmentAnythingToolGUI::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;
}
-unsigned int QmitkSegmentAnythingToolGUI::FetchSelectedGPUFromUI() const
-{
- QString gpuInfo = m_Controls.gpuComboBox->currentText();
- if (m_GpuLoader.GetGPUCount() == 0)
- {
- return static_cast(gpuInfo.toInt());
- }
- else
- {
- QString gpuId = gpuInfo.split(":", QString::SplitBehavior::SkipEmptyParts).first();
- return static_cast(gpuId.toInt());
- }
-}
-
void QmitkSegmentAnythingToolGUI::OnActivateBtnClicked()
{
auto tool = this->GetConnectedToolAs();
if (nullptr == tool)
{
return;
}
try
{
m_Controls.activateButton->setEnabled(false);
qApp->processEvents();
if (!QmitkSegmentAnythingToolGUI::IsSAMInstalled(m_PythonPath))
{
throw std::runtime_error(WARNING_SAM_NOT_FOUND);
}
tool->SetIsAuto(false);
tool->SetPythonPath(m_PythonPath.toStdString());
- tool->SetGpuId(FetchSelectedGPUFromUI());
+ tool->SetGpuId(m_Prefences->GetInt("sam gpuid", 0));
const QString modelType = QString::fromStdString(m_Prefences->Get("sam modeltype", ""));
tool->SetModelType(modelType.toStdString());
this->WriteStatusMessage(
QString("STATUS: Checking if model is already downloaded... This might take a while."));
if (this->DownloadModel(modelType))
{
this->ActivateSAMDaemon();
this->WriteStatusMessage(QString("STATUS: Model found. SAM Activated."));
}
else
{
tool->IsReadyOff();
this->WriteStatusMessage(QString("STATUS: Model not found. Starting download..."));
}
}
catch (const std::exception &e)
{
std::stringstream errorMsg;
errorMsg << "STATUS: Error while processing parameters for SAM segmentation. Reason: " << e.what();
this->ShowErrorMessage(errorMsg.str());
this->WriteErrorMessage(QString::fromStdString(errorMsg.str()));
m_Controls.activateButton->setEnabled(true);
return;
}
catch (...)
{
std::string errorMsg = "Unkown error occured while generation SAM segmentation.";
this->ShowErrorMessage(errorMsg);
m_Controls.activateButton->setEnabled(true);
return;
}
}
void QmitkSegmentAnythingToolGUI::ActivateSAMDaemon()
{
auto tool = this->GetConnectedToolAs();
if (nullptr == tool)
{
return;
}
this->ShowProgressBar(true);
tool->InitSAMPythonProcess();
while (!tool->IsPythonReady())
{
qApp->processEvents();
}
tool->IsReadyOn();
m_Controls.activateButton->setEnabled(true);
this->ShowProgressBar(false);
}
bool QmitkSegmentAnythingToolGUI::DownloadModel(const QString &modelType)
{
QUrl url = QmitkSegmentAnythingToolGUI::VALID_MODELS_URL_MAP[modelType];
QString modelFileName = url.fileName();
const QString storageDir = QString::fromStdString(m_Prefences->Get("sam parent path", ""));
QString checkPointPath = storageDir + QDir::separator() + modelFileName;
if (QFile::exists(checkPointPath))
{
auto tool = this->GetConnectedToolAs();
if (nullptr != tool)
{
tool->SetCheckpointPath(checkPointPath.toStdString());
}
return true;
}
connect(&m_Manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(FileDownloaded(QNetworkReply*)));
QNetworkRequest request(url);
m_Manager.get(request);
this->ShowProgressBar(true);
return false;
}
void QmitkSegmentAnythingToolGUI::FileDownloaded(QNetworkReply *reply)
{
const QString storageDir = QString::fromStdString(m_Prefences->Get("sam parent path", ""));
const QString &modelFileName = reply->url().fileName();
QFile file(storageDir + QDir::separator() + modelFileName);
if (file.open(QIODevice::WriteOnly))
{
file.write(reply->readAll());
file.close();
disconnect(&m_Manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(FileDownloaded(QNetworkReply *)));
this->WriteStatusMessage(QString("STATUS: Model successfully downloaded. Activating SAM...."));
auto tool = this->GetConnectedToolAs();
if (nullptr != tool)
{
tool->SetCheckpointPath(file.fileName().toStdString());
this->ActivateSAMDaemon();
this->WriteStatusMessage(QString("STATUS: Model successfully downloaded. SAM Activated."));
}
}
else
{
this->WriteErrorMessage("STATUS: Model couldn't be downloaded. SAM not activated.");
}
this->EnableAll(true);
this->ShowProgressBar(false);
}
void QmitkSegmentAnythingToolGUI::ShowProgressBar(bool enabled)
{
m_Controls.samProgressBar->setEnabled(enabled);
m_Controls.samProgressBar->setVisible(enabled);
}
bool QmitkSegmentAnythingToolGUI::IsSAMInstalled(const QString &pythonPath)
{
QString fullPath = pythonPath;
bool isPythonExists = false;
bool samExists = false;
#ifdef _WIN32
isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python.exe"));
if (!(fullPath.endsWith("Scripts", Qt::CaseInsensitive) || fullPath.endsWith("Scripts/", Qt::CaseInsensitive)))
{
fullPath += QDir::separator() + QString("Scripts");
isPythonExists =
(!isPythonExists) ? QFile::exists(fullPath + QDir::separator() + QString("python.exe")) : isPythonExists;
}
#else
isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python3"));
if (!(fullPath.endsWith("bin", Qt::CaseInsensitive) || fullPath.endsWith("bin/", Qt::CaseInsensitive)))
{
fullPath += QDir::separator() + QString("bin");
isPythonExists =
(!isPythonExists) ? QFile::exists(fullPath + QDir::separator() + QString("python3")) : isPythonExists;
}
#endif
QDir folderPath(fullPath);
folderPath.cdUp();
if (folderPath.cd("Lib/site-packages/segment_anything"))
{
samExists = true;
}
bool isExists = samExists && isPythonExists;
return isExists;
}
void QmitkSegmentAnythingToolGUI::OnParametersChanged(const QString &)
{
if (m_Controls.activateButton->isEnabled())
{
this->WriteStatusMessage("STATUS: Please Reactivate SAM.");
}
}
void QmitkSegmentAnythingToolGUI::OnResetPicksClicked()
{
auto tool = this->GetConnectedToolAs();
if (nullptr != tool)
{
tool->ClearPicks();
}
}
diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h
index 0ecad9672f..a01b616766 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h
+++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h
@@ -1,138 +1,125 @@
/*============================================================================
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 QmitkSegmentAnythingToolGUI_h
#define QmitkSegmentAnythingToolGUI_h
#include "QmitkSegWithPreviewToolGUIBase.h"
#include
#include "ui_QmitkSegmentAnythingGUIControls.h"
#include "QmitknnUNetGPU.h"
#include "QmitkSetupVirtualEnvUtil.h"
#include
#include
#include
#include
#include
/**
\ingroup org_mitk_gui_qt_interactivesegmentation_internal
\brief GUI for mitk::SegmentAnythingTool.
\sa mitk::PickingTool
*/
class MITKSEGMENTATIONUI_EXPORT QmitkSegmentAnythingToolGUI : public QmitkSegWithPreviewToolGUIBase
{
Q_OBJECT
public:
mitkClassMacro(QmitkSegmentAnythingToolGUI, QmitkSegWithPreviewToolGUIBase);
itkFactorylessNewMacro(Self);
itkCloneMacro(Self);
inline static const QMap VALID_MODELS_URL_MAP = {
{"vit_b", QUrl("https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth")},
//{"vit_b", QUrl("http://www.google.ru/images/srpr/logo3w.png")},
{"vit_l", QUrl("https://dl.fbaipublicfiles.com/segment_anything/sam_vit_l_0b3195.pth")},
{"vit_h", QUrl("https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth")}};
/**
* @brief Checks if SegmentAnything is found inside the selected python virtual environment.
* @return bool
*/
static bool IsSAMInstalled(const QString &);
protected slots:
/**
* @brief Qt Slot
*/
void OnResetPicksClicked();
/**
* @brief Qt Slot
*/
void OnActivateBtnClicked();
/**
* @brief Qt Slot
*/
void FileDownloaded(QNetworkReply *);
/**
* @brief Qt Slot
*/
void OnParametersChanged(const QString&);
protected:
QmitkSegmentAnythingToolGUI();
~QmitkSegmentAnythingToolGUI() = default;
void InitializeUI(QBoxLayout *mainLayout) override;
/**
* @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 Creates a QMessage object and shows on screen.
*/
void ShowErrorMessage(const std::string &, QMessageBox::Icon = QMessageBox::Critical);
- /**
- * @brief Adds GPU information to the gpu combo box.
- * In case, there aren't any GPUs avaialble, the combo box will be
- * rendered editable.
- */
- void SetGPUInfo();
-
- /**
- * @brief Returns GPU id of the selected GPU from the Combo box.
- * @return unsigned int
- */
- unsigned int FetchSelectedGPUFromUI() const;
-
/**
* @brief Enable (or Disable) GUI elements.
*/
void EnableAll(bool);
/**
*
*/
bool DownloadModel(const QString &);
/**
*
*/
void ShowProgressBar(bool);
void ActivateSAMDaemon();
bool ValidatePrefences();
private:
mitk::IPreferences *m_Prefences;
QNetworkAccessManager m_Manager;
Ui_QmitkSegmentAnythingGUIControls m_Controls;
QString m_PythonPath;
QmitkGPULoader m_GpuLoader;
bool m_FirstPreviewComputation = true;
const std::string WARNING_SAM_NOT_FOUND =
"SAM is not detected in the selected python environment. Please reinstall SAM.";
};
#endif
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp
index 9e7f6a193e..96baff9346 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp
@@ -1,419 +1,427 @@
/*============================================================================
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.
============================================================================*/
#include "QmitkSegmentationPreferencePage.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace
{
mitk::IPreferences* GetPreferences()
{
auto* preferencesService = mitk::CoreServices::GetPreferencesService();
return preferencesService->GetSystemPreferences()->Node("org.mitk.views.segmentation");
}
}
QmitkSegmentationPreferencePage::QmitkSegmentationPreferencePage()
: m_Ui(new Ui::QmitkSegmentationPreferencePageControls),
m_Control(nullptr),
m_Initializing(false)
{
}
QmitkSegmentationPreferencePage::~QmitkSegmentationPreferencePage()
{
}
void QmitkSegmentationPreferencePage::Init(berry::IWorkbench::Pointer)
{
}
void QmitkSegmentationPreferencePage::CreateQtControl(QWidget* parent)
{
m_Initializing = true;
m_Control = new QWidget(parent);
m_Ui->setupUi(m_Control);
#ifndef _WIN32
m_Ui->sysPythonComboBox->addItem("/usr/bin");
#endif
this->AutoParsePythonPaths();
m_Ui->sysPythonComboBox->addItem("Select...");
m_Ui->sysPythonComboBox->setCurrentIndex(0);
connect(m_Ui->labelSetPresetToolButton, SIGNAL(clicked()), this, SLOT(OnLabelSetPresetButtonClicked()));
connect(m_Ui->suggestionsToolButton, SIGNAL(clicked()), this, SLOT(OnSuggestionsButtonClicked()));
connect(m_Ui->installSAMButton, SIGNAL(clicked()), this, SLOT(OnInstallBtnClicked()));
connect(m_Ui->clearSAMButton, SIGNAL(clicked()), this, SLOT(OnClearInstall()));
connect(m_Ui->sysPythonComboBox, QOverload::of(&QComboBox::activated),
[=](int index) { OnSystemPythonChanged(m_Ui->sysPythonComboBox->itemText(index)); });
QIcon deleteIcon =
QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/edit-delete.svg"));
m_Ui->clearSAMButton->setIcon(deleteIcon);
const QString storageDir = m_Installer.GetVirtualEnvPath();
m_IsInstalled = QmitkSegmentAnythingToolGUI::IsSAMInstalled(storageDir);
QString welcomeText;
if (m_IsInstalled)
{
m_PythonPath = GetExactPythonPath(storageDir);
m_Installer.SetVirtualEnvPath(m_PythonPath);
welcomeText += " SAM is already found installed.";
}
else
{
welcomeText += " SAM is not installed. Please click on \"Install SAM\" above.";
}
this->WriteStatusMessage(welcomeText);
m_Ui->samModelTypeComboBox->addItems(QmitkSegmentAnythingToolGUI::VALID_MODELS_URL_MAP.keys());
-
+ this->SetGPUInfo();
this->Update();
m_Initializing = false;
}
QWidget* QmitkSegmentationPreferencePage::GetQtControl() const
{
return m_Control;
}
bool QmitkSegmentationPreferencePage::PerformOk()
{
auto* prefs = GetPreferences();
prefs->PutBool("compact view", m_Ui->compactViewCheckBox->isChecked());
prefs->PutBool("draw outline", m_Ui->outlineRadioButton->isChecked());
prefs->PutBool("selection mode", m_Ui->selectionModeCheckBox->isChecked());
prefs->Put("label set preset", m_Ui->labelSetPresetLineEdit->text().toStdString());
prefs->PutBool("default label naming", m_Ui->defaultNameRadioButton->isChecked());
prefs->Put("label suggestions", m_Ui->suggestionsLineEdit->text().toStdString());
prefs->PutBool("replace standard suggestions", m_Ui->replaceStandardSuggestionsCheckBox->isChecked());
prefs->PutBool("suggest once", m_Ui->suggestOnceCheckBox->isChecked());
prefs->Put("sam parent path", m_Installer.STORAGE_DIR.toStdString());
prefs->Put("sam python path", m_PythonPath.toStdString());
prefs->Put("sam modeltype", m_Ui->samModelTypeComboBox->currentText().toStdString());
+ prefs->PutInt("sam gpuid", FetchSelectedGPUFromUI());
+
return true;
}
void QmitkSegmentationPreferencePage::PerformCancel()
{
}
void QmitkSegmentationPreferencePage::Update()
{
auto* prefs = GetPreferences();
m_Ui->compactViewCheckBox->setChecked(prefs->GetBool("compact view", false));
if (prefs->GetBool("draw outline", true))
{
m_Ui->outlineRadioButton->setChecked(true);
}
else
{
m_Ui->overlayRadioButton->setChecked(true);
}
m_Ui->selectionModeCheckBox->setChecked(prefs->GetBool("selection mode", false));
auto labelSetPreset = mitk::BaseApplication::instance().config().getString(mitk::BaseApplication::ARG_SEGMENTATION_LABELSET_PRESET.toStdString(), "");
bool isOverriddenByCmdLineArg = !labelSetPreset.empty();
if (!isOverriddenByCmdLineArg)
labelSetPreset = prefs->Get("label set preset", "");
m_Ui->labelSetPresetLineEdit->setDisabled(isOverriddenByCmdLineArg);
m_Ui->labelSetPresetToolButton->setDisabled(isOverriddenByCmdLineArg);
m_Ui->labelSetPresetCmdLineArgLabel->setVisible(isOverriddenByCmdLineArg);
m_Ui->labelSetPresetLineEdit->setText(QString::fromStdString(labelSetPreset));
if (prefs->GetBool("default label naming", true))
{
m_Ui->defaultNameRadioButton->setChecked(true);
}
else
{
m_Ui->askForNameRadioButton->setChecked(true);
}
auto labelSuggestions = mitk::BaseApplication::instance().config().getString(mitk::BaseApplication::ARG_SEGMENTATION_LABEL_SUGGESTIONS.toStdString(), "");
isOverriddenByCmdLineArg = !labelSuggestions.empty();
if (!isOverriddenByCmdLineArg)
labelSuggestions = prefs->Get("label suggestions", "");
m_Ui->defaultNameRadioButton->setDisabled(isOverriddenByCmdLineArg);
m_Ui->askForNameRadioButton->setDisabled(isOverriddenByCmdLineArg);
m_Ui->suggestionsLineEdit->setDisabled(isOverriddenByCmdLineArg);
m_Ui->suggestionsToolButton->setDisabled(isOverriddenByCmdLineArg);
m_Ui->suggestionsCmdLineArgLabel->setVisible(isOverriddenByCmdLineArg);
m_Ui->suggestionsLineEdit->setText(QString::fromStdString(labelSuggestions));
m_Ui->replaceStandardSuggestionsCheckBox->setChecked(prefs->GetBool("replace standard suggestions", true));
m_Ui->suggestOnceCheckBox->setChecked(prefs->GetBool("suggest once", true));
+
+ m_Ui->samModelTypeComboBox->setCurrentText(QString::fromStdString(prefs->Get("sam modeltype", "vit_b")));
}
void QmitkSegmentationPreferencePage::OnLabelSetPresetButtonClicked()
{
const auto filename = QFileDialog::getOpenFileName(m_Control, QStringLiteral("Load Label Set Preset"), QString(), QStringLiteral("Label set preset (*.lsetp)"));
if (!filename.isEmpty())
m_Ui->labelSetPresetLineEdit->setText(filename);
}
void QmitkSegmentationPreferencePage::OnSuggestionsButtonClicked()
{
const auto filename = QFileDialog::getOpenFileName(m_Control, QStringLiteral("Load Label Suggestions"), QString(), QStringLiteral("Label suggestions (*.json)"));
if (!filename.isEmpty())
m_Ui->suggestionsLineEdit->setText(filename);
}
QString QmitkSegmentationPreferencePage::OnSystemPythonChanged(const QString &pyEnv)
{
QString pyPath;
if (pyEnv == QString("Select..."))
{
QString path = QFileDialog::getExistingDirectory(m_Ui->sysPythonComboBox->parentWidget(), "Python Path", "dir");
if (!path.isEmpty())
{
this->OnSystemPythonChanged(path); // recall same function for new path validation
bool oldState = m_Ui->sysPythonComboBox->blockSignals(true); // block signal firing while inserting item
m_Ui->sysPythonComboBox->insertItem(0, path);
m_Ui->sysPythonComboBox->setCurrentIndex(0);
m_Ui->sysPythonComboBox->blockSignals(oldState); // unblock signal firing after inserting item. Remove this after Qt6 migration
}
}
else
{
QString uiPyPath = this->GetPythonPathFromUI(pyEnv);
pyPath = this->GetExactPythonPath(uiPyPath);
}
return pyPath;
}
QString QmitkSegmentationPreferencePage::GetPythonPathFromUI(const QString &pyUI) const
{
QString fullPath = pyUI;
if (-1 != fullPath.indexOf(")"))
{
fullPath = fullPath.mid(fullPath.indexOf(")") + 2);
}
return fullPath.simplified();
}
QString QmitkSegmentationPreferencePage::GetExactPythonPath(const QString &pyEnv) const
{
QString fullPath = pyEnv;
bool isPythonExists = false;
#ifdef _WIN32
isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python.exe"));
if (!isPythonExists &&
!(fullPath.endsWith("Scripts", Qt::CaseInsensitive) || fullPath.endsWith("Scripts/", Qt::CaseInsensitive)))
{
fullPath += QDir::separator() + QString("Scripts");
isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python.exe"));
}
#else
isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python3"));
if (!isPythonExists &&
!(fullPath.endsWith("bin", Qt::CaseInsensitive) || fullPath.endsWith("bin/", Qt::CaseInsensitive)))
{
fullPath += QDir::separator() + QString("bin");
isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python3"));
}
#endif
if (!isPythonExists)
{
fullPath.clear();
}
return fullPath;
}
void QmitkSegmentationPreferencePage::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() + "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_Ui->sysPythonComboBox->addItem("(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_Ui->sysPythonComboBox->addItem("(" + envName + "): " + subIt.filePath());
}
}
}
}
-/* bool QmitkSegmentationPreferencePage::IsSAMInstalled(const QString &pythonPath)
+void QmitkSegmentationPreferencePage::SetGPUInfo()
{
- QString fullPath = pythonPath;
- bool isPythonExists = false;
-#ifdef _WIN32
- isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python.exe"));
- if (!(fullPath.endsWith("Scripts", Qt::CaseInsensitive) || fullPath.endsWith("Scripts/", Qt::CaseInsensitive)))
+ std::vector specs = m_GpuLoader.GetAllGPUSpecs();
+ for (const QmitkGPUSpec &gpuSpec : specs)
{
- fullPath += QDir::separator() + QString("Scripts");
- isPythonExists =
- (!isPythonExists) ? QFile::exists(fullPath + QDir::separator() + QString("python.exe")) : isPythonExists;
+ m_Ui->gpuComboBox->addItem(QString::number(gpuSpec.id) + ": " + gpuSpec.name + " (" + gpuSpec.memory + ")");
}
-#else
- isPythonExists = QFile::exists(fullPath + QDir::separator() + QString("python3"));
- if (!(fullPath.endsWith("bin", Qt::CaseInsensitive) || fullPath.endsWith("bin/", Qt::CaseInsensitive)))
+ if (specs.empty())
{
- fullPath += QDir::separator() + QString("bin");
- isPythonExists =
- (!isPythonExists) ? QFile::exists(fullPath + QDir::separator() + QString("python3")) : isPythonExists;
+ m_Ui->gpuComboBox->setEditable(true);
+ m_Ui->gpuComboBox->addItem(QString::number(0));
+ m_Ui->gpuComboBox->setValidator(new QIntValidator(0, 999, this));
}
-#endif*/
-// bool isExists = /*QFile::exists(fullPath + QDir::separator() + QString("MITK_SAM"))*/ true && isPythonExists;
-// return isExists;
-//}
+}
+
+unsigned int QmitkSegmentationPreferencePage::FetchSelectedGPUFromUI() const
+{
+ QString gpuInfo = m_Ui->gpuComboBox->currentText();
+ if (m_GpuLoader.GetGPUCount() == 0)
+ {
+ return static_cast(gpuInfo.toInt());
+ }
+ else
+ {
+ QString gpuId = gpuInfo.split(":", QString::SplitBehavior::SkipEmptyParts).first();
+ return static_cast(gpuId.toInt());
+ }
+}
void QmitkSegmentationPreferencePage::OnInstallBtnClicked()
{
MITK_INFO << "Install clicked";
QString systemPython = OnSystemPythonChanged(m_Ui->sysPythonComboBox->currentText());
if (!systemPython.isEmpty())
{
this->WriteStatusMessage("STATUS: Installing SAM...");
m_Installer.SetSystemPythonPath(systemPython);
m_IsInstalled = m_Installer.SetupVirtualEnv(m_Installer.VENV_NAME);
if (m_IsInstalled)
{
m_PythonPath = this->GetExactPythonPath(m_Installer.GetVirtualEnvPath());
this->WriteStatusMessage("STATUS: Successfully installed SAM.");
auto *prefs = GetPreferences();
prefs->Put("sam python path", m_PythonPath.toStdString());
}
else
{
this->WriteErrorMessage("ERROR: Couldn't install SAM.");
}
}
}
void QmitkSegmentationPreferencePage::OnClearInstall()
{
MITK_INFO << "OnClearInstall clicked";
QDir folderPath(m_Installer.GetVirtualEnvPath());
m_IsInstalled = folderPath.removeRecursively();
if (!m_IsInstalled)
{
MITK_ERROR << "The virtual environment couldn't be removed. Please check if you have the required access "
"privileges or, some other process is accessing the folders.";
}
}
void QmitkSegmentationPreferencePage::WriteStatusMessage(const QString &message)
{
m_Ui->samInstallStatusLabel->setText(message);
m_Ui->samInstallStatusLabel->setStyleSheet("font-weight: bold; color: white");
qApp->processEvents();
}
void QmitkSegmentationPreferencePage::WriteErrorMessage(const QString &message)
{
m_Ui->samInstallStatusLabel->setText(message);
m_Ui->samInstallStatusLabel->setStyleSheet("font-weight: bold; color: red");
qApp->processEvents();
}
QString QmitkSAMInstaller::GetVirtualEnvPath()
{
return STORAGE_DIR + VENV_NAME;
}
bool QmitkSAMInstaller::SetupVirtualEnv(const QString &venvName)
{
if (GetSystemPythonPath().isEmpty())
{
return false;
}
QDir folderPath(GetBaseDir());
folderPath.mkdir(venvName);
if (!folderPath.cd(venvName))
{
return false; // Check if directory creation was successful.
}
mitk::ProcessExecutor::ArgumentListType args;
auto spExec = mitk::ProcessExecutor::New();
auto spCommand = itk::CStyleCommand::New();
spCommand->SetCallback(&PrintProcessEvent);
spExec->AddObserver(mitk::ExternalProcessOutputEvent(), spCommand);
args.push_back("-m");
args.push_back("venv");
args.push_back(venvName.toStdString());
#ifdef _WIN32
QString pythonFile = GetSystemPythonPath() + QDir::separator() + "python.exe";
QString pythonExeFolder = "Scripts";
#else
QString pythonFile = GetSystemPythonPath() + QDir::separator() + "python3";
QString pythonExeFolder = "bin";
#endif
spExec->Execute(GetBaseDir().toStdString(), pythonFile.toStdString(), args); // Setup local virtual environment
if (folderPath.cd(pythonExeFolder))
{
this->SetPythonPath(folderPath.absolutePath());
this->SetPipPath(folderPath.absolutePath());
this->InstallPytorch();
for (auto &package : PACKAGES)
{
this->PipInstall(package.toStdString(), &PrintProcessEvent);
}
std::string pythonCode; // python syntax to check if torch is installed with CUDA.
pythonCode.append("import torch;");
pythonCode.append("print('Pytorch was installed with CUDA') if torch.cuda.is_available() else print('PyTorch was "
"installed WITHOUT CUDA');");
this->ExecutePython(pythonCode, &PrintProcessEvent);
return true;
}
return false;
}
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h
index a4af736897..2e7a833f1c 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h
@@ -1,114 +1,130 @@
/*============================================================================
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 QmitkSegmentationPreferencePage_h
#define QmitkSegmentationPreferencePage_h
#include "org_mitk_gui_qt_segmentation_Export.h"
#include
#include
#include
#include
#include
+#include
class QWidget;
namespace Ui
{
class QmitkSegmentationPreferencePageControls;
}
class QmitkSAMInstaller : public QmitkSetupVirtualEnvUtil
{
public:
const QString VENV_NAME = ".sam";
const QString SAM_VERSION = "1.0"; // currently, unused
const std::vector PACKAGES = {QString("numpy"),
QString("opencv-python"),
QString("git+https://github.com/facebookresearch/segment-anything.git"),
QString("SimpleITK")};
const QString STORAGE_DIR;
inline QmitkSAMInstaller(
const QString baseDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QDir::separator() +
qApp->organizationName() + QDir::separator())
: QmitkSetupVirtualEnvUtil(baseDir), STORAGE_DIR(baseDir){};
bool SetupVirtualEnv(const QString &) override;
QString GetVirtualEnvPath() override;
};
class MITK_QT_SEGMENTATION QmitkSegmentationPreferencePage : public QObject, public berry::IQtPreferencePage
{
Q_OBJECT
Q_INTERFACES(berry::IPreferencePage)
public:
QmitkSegmentationPreferencePage();
~QmitkSegmentationPreferencePage() override;
void Init(berry::IWorkbench::Pointer workbench) override;
void CreateQtControl(QWidget* widget) override;
QWidget* GetQtControl() const override;
bool PerformOk() override;
void PerformCancel() override;
void Update() override;
protected Q_SLOTS:
void OnLabelSetPresetButtonClicked();
void OnSuggestionsButtonClicked();
void OnInstallBtnClicked();
void OnClearInstall();
QString OnSystemPythonChanged(const QString&);
protected:
/**
* @brief Searches and parses paths of python virtual enviroments
* from predefined lookout locations
*/
void AutoParsePythonPaths();
/**
* @brief Get the virtual env path from UI combobox removing any
* extra special characters.
*
* @return QString
*/
QString GetPythonPathFromUI(const QString&) const;
/**
* @brief Get the Exact Python Path for any OS
* from the virtual environment path.
* @return QString
*/
QString GetExactPythonPath(const QString&) const;
+
+ /**
+ * @brief Adds GPU information to the gpu combo box.
+ * In case, there aren't any GPUs avaialble, the combo box will be
+ * rendered editable.
+ */
+ void SetGPUInfo();
+
+ /**
+ * @brief Returns GPU id of the selected GPU from the Combo box.
+ * @return unsigned int
+ */
+ unsigned int FetchSelectedGPUFromUI() const;
+
void WriteStatusMessage(const QString&);
void WriteErrorMessage(const QString&);
QNetworkAccessManager m_Manager;
+ QmitkGPULoader m_GpuLoader;
Ui::QmitkSegmentationPreferencePageControls* m_Ui;
QmitkSAMInstaller m_Installer;
QWidget* m_Control;
QString m_PythonPath;
bool m_IsInstalled = false;
bool m_Initializing;
};
#endif
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePageControls.ui b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePageControls.ui
index 4e94cc1b70..f11dc36c2d 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePageControls.ui
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePageControls.ui
@@ -1,302 +1,317 @@
QmitkSegmentationPreferencePageControls
0
0
656
779
Form
-
Compact view
-
Hide tool button texts and increase icon size
-
2D display
-
-
Draw as outline
true
displayButtonGroup
-
Draw as transparent overlay
displayButtonGroup
-
Data node selection mode
-
If checked the segmentation plugin ensures that only the selected segmentation and the reference image are visible at one time.
Show only selected nodes
-
Default label set preset
-
-
true
-
...
-
<html><head/><body><p><span style=" color:#ff0000;">The default label set preset is currently overriden by the </span><span style=" font-family:'Courier New'; color:#ff0000;">Segmentation.labelSetPreset</span><span style=" color:#ff0000;"> command-line argument.</span></p></body></html>
Qt::RichText
true
-
Label creation
-
-
Assign default name and color
true
labelCreationButtonGroup
-
Ask for name and color
labelCreationButtonGroup
-
Label suggestions
-
-
true
-
...
-
<html><head/><body><p><span style=" color:#ff0000;">Suggestions are currently enforced by the </span><span style=" font-family:'Courier New'; color:#ff0000;">Segmentation.labelSuggestions</span><span style=" color:#ff0000;"> command-line argument.</span></p></body></html>
Qt::RichText
true
-
Replace standard organ suggestions
true
-
Suggest once per segmentation
true
-
- -
-
-
- SAM Tool
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Install SAM
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Clear Install
-
-
-
- -
-
-
- System Python
-
-
-
- -
-
-
- -
-
-
- Model Type:
-
-
-
- -
-
-
- -
-
-
- Qt::RichText
-
-
- true
-
-
-
-
-
+ -
+
+
+ SAM Tool
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Install SAM
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Clear Install
+
+
+
+ -
+
+
+ System Python
+
+
+
+ -
+
+
+ -
+
+
+ Model Type:
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ GPU Id:
+
+
+
+ -
+
+
+ Qt::RichText
+
+
+ true
+
+
+
+
+
-
Qt::Vertical
20
40