diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui
index 6497cf24fb..8299ff1d6a 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui
+++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingGUIControls.ui
@@ -1,347 +1,231 @@
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>
Qt::RichText
true
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 100000
- 16777215
-
-
-
- Install SAM
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Install Options
-
-
- true
-
-
- 5
-
-
- true
-
-
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 6
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- System Python:
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 100000
- 16777215
-
-
-
- Clear Install
-
-
-
-
-
-
-
-
-
- -
+
-
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
-
-
-
- Model Type:
-
-
-
- -
-
-
-
0
0
100000
16777215
Reset Picks
-
0
0
100000
16777215
Activate SAM
-
0
0
true
-
1
0
false
ctkComboBox
QComboBox
1
ctkCollapsibleGroupBox
QWidget
diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp
index 982a9fc549..9c416893da 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp
+++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.cpp
@@ -1,530 +1,341 @@
/*============================================================================
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 TotalSegmentator tool can be very slow.";
+ 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);
-#ifndef _WIN32
- m_Controls.sysPythonComboBox->addItem("/usr/bin");
-#endif
- this->AutoParsePythonPaths();
- m_Controls.sysPythonComboBox->addItem("Select...");
- m_Controls.sysPythonComboBox->setCurrentIndex(0);
m_Controls.statusLabel->setTextFormat(Qt::RichText);
- m_Controls.modelTypeComboBox->addItems(VALID_MODELS_URL_MAP.keys());
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()));
- connect(m_Controls.installButton, SIGNAL(clicked()), this, SLOT(OnInstallBtnClicked()));
- connect(m_Controls.clearButton, SIGNAL(clicked()), this, SLOT(OnClearInstall()));
- connect(m_Controls.sysPythonComboBox,
- QOverload::of(&QComboBox::activated),
- [=](int index) { OnSystemPythonChanged(m_Controls.sysPythonComboBox->itemText(index)); });
- connect(m_Controls.gpuComboBox, SIGNAL(currentTextChanged(const QString &)), this,
- SLOT(OnParametersChanged(const QString &)));
- connect(m_Controls.modelTypeComboBox, SIGNAL(currentTextChanged(const QString &)), this,
- SLOT(OnParametersChanged(const QString &)));
- QIcon deleteIcon =
- QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/edit-delete.svg"));
QIcon arrowIcon =
QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/go-next.svg"));
- m_Controls.clearButton->setIcon(deleteIcon);
m_Controls.activateButton->setIcon(arrowIcon);
- const QString storageDir = m_Installer.GetVirtualEnvPath();
- m_IsInstalled = this->IsSAMInstalled(storageDir);
- if (m_IsInstalled)
+ bool isInstalled = this->ValidatePrefences();
+ if (isInstalled)
{
- m_PythonPath = GetExactPythonPath(storageDir);
- m_Installer.SetVirtualEnvPath(m_PythonPath);
+ m_PythonPath = QString::fromStdString(m_Prefences->Get("sam python path", ""));
welcomeText += " SAM is already found installed.";
}
else
{
- welcomeText += " SAM is not installed. Please click on \"Install SAM\" above.";
+ welcomeText += " SAM is not configured correctly. Please go to Prefences (Cntl+P) to configure and/or install SAM.";
}
- this->EnableAll(m_IsInstalled);
+ this->EnableAll(isInstalled);
this->WriteStatusMessage(welcomeText);
this->ShowProgressBar(false);
m_Controls.samProgressBar->setMaximum(0);
mainLayout->addLayout(m_Controls.verticalLayout);
Superclass::InitializeUI(mainLayout);
}
-QString QmitkSegmentAnythingToolGUI::GetExactPythonPath(const QString &pyEnv) const
+bool QmitkSegmentAnythingToolGUI::ValidatePrefences()
{
- 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;
+ 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", "");
+ return (isInstalled && !modelType.empty() && !path.empty());
}
void QmitkSegmentAnythingToolGUI::EnableAll(bool isEnable)
{
m_Controls.activateButton->setEnabled(isEnable);
- m_Controls.installButton->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;
}
-void QmitkSegmentAnythingToolGUI::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.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_Controls.sysPythonComboBox->addItem("(" + envName + "): " + subIt.filePath());
- }
- }
- }
-}
-
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 (!this->IsSAMInstalled(m_PythonPath))
+ if (!QmitkSegmentAnythingToolGUI::IsSAMInstalled(m_PythonPath))
{
throw std::runtime_error(WARNING_SAM_NOT_FOUND);
}
tool->SetIsAuto(false);
tool->SetPythonPath(m_PythonPath.toStdString());
tool->SetGpuId(FetchSelectedGPUFromUI());
- QString modelType = m_Controls.modelTypeComboBox->currentText();
+ 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);
}
-QString QmitkSegmentAnythingToolGUI::GetPythonPathFromUI(const QString &pyUI) const
-{
- QString fullPath = pyUI;
- if (-1 != fullPath.indexOf(")"))
- {
- fullPath = fullPath.mid(fullPath.indexOf(")") + 2);
- }
- return fullPath.simplified();
-}
-
bool QmitkSegmentAnythingToolGUI::DownloadModel(const QString &modelType)
{
- QUrl url = VALID_MODELS_URL_MAP[modelType];
+ QUrl url = QmitkSegmentAnythingToolGUI::VALID_MODELS_URL_MAP[modelType];
QString modelFileName = url.fileName();
- const QString& storageDir = m_Installer.STORAGE_DIR;
+ 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 = m_Installer.STORAGE_DIR;
+ 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);
}
-QString QmitkSegmentAnythingToolGUI::OnSystemPythonChanged(const QString &pyEnv)
-{
- QString pyPath;
- if (pyEnv == QString("Select..."))
- {
- m_Controls.activateButton->setDisabled(true);
- QString path =
- QFileDialog::getExistingDirectory(m_Controls.sysPythonComboBox->parentWidget(), "Python Path", "dir");
- if (!path.isEmpty())
- {
- this->OnSystemPythonChanged(path); // recall same function for new path validation
- bool oldState = m_Controls.sysPythonComboBox->blockSignals(true); // block signal firing while inserting item
- m_Controls.sysPythonComboBox->insertItem(0, path);
- m_Controls.sysPythonComboBox->setCurrentIndex(0);
- m_Controls.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;
-}
-
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
- bool isExists = /*QFile::exists(fullPath + QDir::separator() + QString("MITK_SAM"))*/ true && isPythonExists;
+ 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();
}
}
-
-void QmitkSegmentAnythingToolGUI::OnInstallBtnClicked()
-{
- bool isInstalled = false;
- QString systemPython = OnSystemPythonChanged(m_Controls.sysPythonComboBox->currentText());
- if (systemPython.isEmpty())
- {
- this->WriteErrorMessage("ERROR: Couldn't find Python.");
- }
- else
- {
- this->WriteStatusMessage("STATUS: Installing SAM...");
- m_Installer.SetSystemPythonPath(systemPython);
- isInstalled = m_Installer.SetupVirtualEnv(m_Installer.VENV_NAME);
- if (isInstalled)
- {
- m_PythonPath = this->GetExactPythonPath(m_Installer.GetVirtualEnvPath());
- this->WriteStatusMessage("STATUS: Successfully installed SAM.");
- }
- else
- {
- this->WriteErrorMessage("ERROR: Couldn't install SAM.");
- }
- }
- this->EnableAll(isInstalled);
-}
-
-void QmitkSegmentAnythingToolGUI::OnClearInstall()
-{
- QDir folderPath(m_Installer.GetVirtualEnvPath());
- if (folderPath.removeRecursively())
- {
- m_Controls.installButton->setEnabled(true);
- m_IsInstalled = false;
- }
- else
- {
- 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.";
- }
- this->EnableAll(m_IsInstalled);
-}
-
-bool QmitkSegmentAnythingToolInstaller::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;
-}
-
-QString QmitkSegmentAnythingToolInstaller::GetVirtualEnvPath()
-{
- return STORAGE_DIR + VENV_NAME;
-}
diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h
index 2b9e140672..0ecad9672f 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h
+++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentAnythingToolGUI.h
@@ -1,197 +1,138 @@
/*============================================================================
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
-
-
-/**
- * @brief Installer class for SegmentAnythingModel Tool.
- * Class specifies the virtual environment name, install version, packages required to pip install
- * and implements SetupVirtualEnv method.
- *
- */
-class QmitkSegmentAnythingToolInstaller : 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 QmitkSegmentAnythingToolInstaller(
- 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;
-};
-
+#include
/**
\ingroup org_mitk_gui_qt_interactivesegmentation_internal
-\brief GUI for mitk::PickingTool.
+\brief GUI for mitk::SegmentAnythingTool.
\sa mitk::PickingTool
*/
class MITKSEGMENTATIONUI_EXPORT QmitkSegmentAnythingToolGUI : public QmitkSegWithPreviewToolGUIBase
{
Q_OBJECT
public:
mitkClassMacro(QmitkSegmentAnythingToolGUI, QmitkSegWithPreviewToolGUIBase);
itkFactorylessNewMacro(Self);
itkCloneMacro(Self);
-protected slots:
- /**
- * @brief Qt Slot
- */
- void OnResetPicksClicked();
-
- /**
- * @brief Qt Slot
- */
- void OnActivateBtnClicked();
+ 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 Qt Slot
+ * @brief Checks if SegmentAnything is found inside the selected python virtual environment.
+ * @return bool
*/
- void OnInstallBtnClicked();
+ static bool IsSAMInstalled(const QString &);
+protected slots:
/**
* @brief Qt Slot
*/
- QString OnSystemPythonChanged(const QString&);
+ void OnResetPicksClicked();
/**
* @brief Qt Slot
*/
- void OnClearInstall();
+ void OnActivateBtnClicked();
/**
* @brief Qt Slot
*/
void FileDownloaded(QNetworkReply *);
/**
* @brief Qt Slot
*/
- void OnParametersChanged(const QString &);
+ 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 Searches and parses paths of python virtual enviroments
- * from predefined lookout locations
- */
- void AutoParsePythonPaths();
-
/**
* @brief Returns GPU id of the selected GPU from the Combo box.
* @return unsigned int
*/
unsigned int FetchSelectedGPUFromUI() const;
- /**
- * @brief Checks if TotalSegmentator command is valid in the selected python virtual environment.
- * @return bool
- */
- bool IsSAMInstalled(const QString &);
-
- /**
- * @brief Get the Exact Python Path for any OS
- * from the virtual environment path.
- * @return QString
- */
- QString GetExactPythonPath(const QString &) const;
-
/**
* @brief Enable (or Disable) GUI elements.
*/
void EnableAll(bool);
-
- /**
- * @brief Get the virtual env path from UI combobox removing any
- * extra special characters.
- *
- * @return QString
- */
- QString GetPythonPathFromUI(const QString &) const;
/**
*
*/
bool DownloadModel(const QString &);
/**
*
*/
void ShowProgressBar(bool);
void ActivateSAMDaemon();
+ bool ValidatePrefences();
+
private:
- QmitkSegmentAnythingToolInstaller m_Installer;
+ mitk::IPreferences *m_Prefences;
QNetworkAccessManager m_Manager;
Ui_QmitkSegmentAnythingGUIControls m_Controls;
QString m_PythonPath;
QmitkGPULoader m_GpuLoader;
bool m_FirstPreviewComputation = true;
- bool m_IsInstalled = false;
const std::string WARNING_SAM_NOT_FOUND =
- "SAM is not detected in the selected python environment.Please reinstall SAM.";
- 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")}};
+ "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 e1d8403795..9e7f6a193e 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp
@@ -1,179 +1,419 @@
/*============================================================================
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->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());
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));
}
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)
+{
+ 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)))
+ {
+ 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*/
+// bool isExists = /*QFile::exists(fullPath + QDir::separator() + QString("MITK_SAM"))*/ true && isPythonExists;
+// return isExists;
+//}
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()
+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 QString("help");
+ return STORAGE_DIR + VENV_NAME;
}
-bool QmitkSAMInstaller::SetupVirtualEnv(const QString &)
+bool QmitkSAMInstaller::SetupVirtualEnv(const QString &venvName)
{
- return true;
+ 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 099d455bbc..a4af736897 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h
@@ -1,87 +1,114 @@
/*============================================================================
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
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;
+ void WriteStatusMessage(const QString&);
+ void WriteErrorMessage(const QString&);
+
+ QNetworkAccessManager m_Manager;
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 febf113317..4e94cc1b70 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePageControls.ui
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePageControls.ui
@@ -1,282 +1,302 @@
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
+
+
+
-
Qt::Vertical
20
40