diff --git a/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp b/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp index 675e4b5bdd..881f688fc3 100644 --- a/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp +++ b/Modules/Segmentation/Interactions/mitkAutoMLSegmentationWithPreviewTool.cpp @@ -1,234 +1,209 @@ /*============================================================================ 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 "mitkAutoMLSegmentationWithPreviewTool.h" #include "mitkImageAccessByItk.h" #include "mitkToolManager.h" #include #include #include #include #include #include #include // ITK #include #include mitk::AutoMLSegmentationWithPreviewTool::AutoMLSegmentationWithPreviewTool() : AutoSegmentationWithPreviewTool(true) { } void mitk::AutoMLSegmentationWithPreviewTool::SetSelectedLabels(const SelectedLabelVectorType& regions) { if (m_SelectedLabels != regions) { m_SelectedLabels = regions; //Note: we do not call this->Modified() on puprose. Reason: changing the //selected regions should not force to run otsu filter in DoUpdatePreview due to changed MTime. } } const mitk::LabelSetImage* mitk::AutoMLSegmentationWithPreviewTool::GetMLPreview() const { if (m_MLPreviewNode.IsNotNull()) { const auto mlPreviewImage = dynamic_cast(this->m_MLPreviewNode->GetData()); return mlPreviewImage; } return nullptr; } mitk::AutoMLSegmentationWithPreviewTool::SelectedLabelVectorType mitk::AutoMLSegmentationWithPreviewTool::GetSelectedLabels() const { return this->m_SelectedLabels; } void mitk::AutoMLSegmentationWithPreviewTool::Activated() { Superclass::Activated(); m_SelectedLabels = {}; m_MLPreviewNode = mitk::DataNode::New(); m_MLPreviewNode->SetProperty("name", StringProperty::New(std::string(this->GetName()) + "ML preview")); m_MLPreviewNode->SetProperty("helper object", BoolProperty::New(true)); m_MLPreviewNode->SetVisibility(true); m_MLPreviewNode->SetOpacity(1.0); this->GetToolManager()->GetDataStorage()->Add(m_MLPreviewNode); } void mitk::AutoMLSegmentationWithPreviewTool::Deactivated() { this->GetToolManager()->GetDataStorage()->Remove(m_MLPreviewNode); m_MLPreviewNode = nullptr; Superclass::Deactivated(); } void mitk::AutoMLSegmentationWithPreviewTool::UpdateCleanUp() { if (m_MLPreviewNode.IsNotNull()) m_MLPreviewNode->SetVisibility(m_SelectedLabels.empty()); if (nullptr != this->GetPreviewSegmentationNode()) this->GetPreviewSegmentationNode()->SetVisibility(!m_SelectedLabels.empty()); if (m_SelectedLabels.empty()) { this->ResetPreviewNode(); } } void mitk::AutoMLSegmentationWithPreviewTool::SetNodeProperties(LabelSetImage::Pointer newMLPreview) { if (newMLPreview.IsNotNull()) { this->m_MLPreviewNode->SetData(newMLPreview); this->m_MLPreviewNode->SetProperty("binary", mitk::BoolProperty::New(false)); mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New(); renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); this->m_MLPreviewNode->SetProperty("Image Rendering.Mode", renderingMode); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); mitk::LookupTableProperty::Pointer prop = mitk::LookupTableProperty::New(lut); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetHueRange(1.0, 0.0); lookupTable->SetSaturationRange(1.0, 1.0); lookupTable->SetValueRange(1.0, 1.0); lookupTable->SetTableRange(-1.0, 1.0); lookupTable->Build(); lut->SetVtkLookupTable(lookupTable); prop->SetLookupTable(lut); this->m_MLPreviewNode->SetProperty("LookupTable", prop); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetRangeMinMax(0, newMLPreview->GetStatistics()->GetScalarValueMax()); levWinProp->SetLevelWindow(levelwindow); this->m_MLPreviewNode->SetProperty("levelwindow", levWinProp); } } void mitk::AutoMLSegmentationWithPreviewTool::DoUpdatePreview(const Image* inputAtTimeStep, const Image* /*oldSegAtTimeStep*/, Image* previewImage, TimeStepType timeStep) { const auto timePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); if (nullptr == m_MLPreviewNode->GetData() || this->GetMTime() > m_MLPreviewNode->GetData()->GetMTime() || this->m_LastMLTimeStep != timeStep //this covers the case where dynamic //segmentations have to compute a preview //for all time steps on confirmation || this->GetLastTimePointOfUpdate() != timePoint //this ensures that static seg //previews work with dynamic images //with avoiding unnecessary other computations ) { if (nullptr == inputAtTimeStep) { MITK_WARN << "Cannot run segementation. Currently selected input image is not set."; return; } this->m_LastMLTimeStep = timeStep; auto newMLPreview = ComputeMLPreview(inputAtTimeStep, timeStep); - - // if (newMLPreview.IsNotNull()) - // { - // this->m_MLPreviewNode->SetData(newMLPreview); - // this->m_MLPreviewNode->SetProperty("binary", mitk::BoolProperty::New(false)); - // mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New(); - // renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); - // this->m_MLPreviewNode->SetProperty("Image Rendering.Mode", renderingMode); - // mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); - // mitk::LookupTableProperty::Pointer prop = mitk::LookupTableProperty::New(lut); - // vtkSmartPointer lookupTable = vtkSmartPointer::New(); - // lookupTable->SetHueRange(1.0, 0.0); - // lookupTable->SetSaturationRange(1.0, 1.0); - // lookupTable->SetValueRange(1.0, 1.0); - // lookupTable->SetTableRange(-1.0, 1.0); - // lookupTable->Build(); - // lut->SetVtkLookupTable(lookupTable); - // prop->SetLookupTable(lut); - // this->m_MLPreviewNode->SetProperty("LookupTable", prop); - // mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); - // mitk::LevelWindow levelwindow; - // levelwindow.SetRangeMinMax(0, newMLPreview->GetStatistics()->GetScalarValueMax()); - // levWinProp->SetLevelWindow(levelwindow); - // this->m_MLPreviewNode->SetProperty("levelwindow", levWinProp); - // } this->SetNodeProperties(newMLPreview); } if (!m_SelectedLabels.empty()) { const auto mlPreviewImage = this->GetMLPreview(); if (nullptr != mlPreviewImage) { AccessByItk_n(mlPreviewImage, CalculateMergedSimplePreview, (previewImage, timeStep)); } } } template void mitk::AutoMLSegmentationWithPreviewTool::CalculateMergedSimplePreview(const itk::Image* itkImage, mitk::Image* segmentation, unsigned int timeStep) { typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::BinaryThresholdImageFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); // InputImageType::Pointer itkImage; typename OutputImageType::Pointer itkBinaryResultImage; filter->SetInput(itkImage); filter->SetLowerThreshold(m_SelectedLabels[0]); filter->SetUpperThreshold(m_SelectedLabels[0]); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); filter->Update(); itkBinaryResultImage = filter->GetOutput(); itkBinaryResultImage->DisconnectPipeline(); // if more than one region id is used compute the union of all given binary regions for (const auto labelID : m_SelectedLabels) { if (labelID != m_SelectedLabels[0]) { filter->SetLowerThreshold(labelID); filter->SetUpperThreshold(labelID); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->Update(); typename OutputImageType::Pointer tempImage = filter->GetOutput(); typename itk::OrImageFilter::Pointer orFilter = itk::OrImageFilter::New(); orFilter->SetInput1(tempImage); orFilter->SetInput2(itkBinaryResultImage); orFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); orFilter->UpdateLargestPossibleRegion(); itkBinaryResultImage = orFilter->GetOutput(); } } //---------------------------------------------------------------------------------------------------- segmentation->SetVolume((void*)(itkBinaryResultImage->GetPixelContainer()->GetBufferPointer()), timeStep); } diff --git a/Modules/Segmentation/Interactions/mitkProcessExecutor.cpp b/Modules/Segmentation/Interactions/mitkProcessExecutor.cpp index 27af010ebb..d65969bb8a 100644 --- a/Modules/Segmentation/Interactions/mitkProcessExecutor.cpp +++ b/Modules/Segmentation/Interactions/mitkProcessExecutor.cpp @@ -1,158 +1,153 @@ /*============================================================================ 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 "mitkProcessExecutor.h" #include #include #include #include namespace mitk { - std::string ProcessExecutor::getOSDependendExecutableName(const std::string &name) + std::string ProcessExecutor::GetOSDependendExecutableName(const std::string &name) { #if defined(_WIN32) if (itksys::SystemTools::GetFilenameLastExtension(name).empty()) { return name + ".exe"; } return name; #else auto result = itksys::SystemTools::GetFilenamePath(name); - if (ensureCorrectOSPathSeparator(result).empty()) + if (EnsureCorrectOSPathSeparator(result).empty()) { return "./" + name; } else { return name; } #endif - }; + } - std::string ProcessExecutor::ensureCorrectOSPathSeparator(const std::string &path) + std::string ProcessExecutor::EnsureCorrectOSPathSeparator(const std::string &path) { std::string ret = path; #ifdef _WIN32 const std::string curSep = "\\"; const char wrongSep = '/'; #else const std::string curSep = "/"; const char wrongSep = '\\'; #endif std::string::size_type pos = ret.find_first_of(wrongSep); while (pos != std::string::npos) { ret.replace(pos, 1, curSep); pos = ret.find_first_of(wrongSep); } return ret; - }; + } - int ProcessExecutor::getExitValue() { return this->_exitValue; }; + int ProcessExecutor::GetExitValue() { return this->m_ExitValue; }; - bool ProcessExecutor::execute(const std::string &executionPath, const ArgumentListType &argumentList) + bool ProcessExecutor::Execute(const std::string &executionPath, const ArgumentListType &argumentList) { - // convert to char* array with terminating null element; - const char **pArguments = new const char *[argumentList.size() + 1]; - pArguments[argumentList.size()] = nullptr; + std::vector pArguments_(argumentList.size() + 1); for (ArgumentListType::size_type index = 0; index < argumentList.size(); ++index) { - pArguments[index] = argumentList[index].c_str(); + pArguments_[index] = argumentList[index].c_str(); } + pArguments_.push_back(nullptr); //terminating null element as required by ITK bool normalExit = false; try { itksysProcess *processID = itksysProcess_New(); - itksysProcess_SetCommand(processID, pArguments); + itksysProcess_SetCommand(processID, pArguments_.data()); itksysProcess_SetWorkingDirectory(processID, executionPath.c_str()); if (this->m_SharedOutputPipes) { itksysProcess_SetPipeShared(processID, itksysProcess_Pipe_STDOUT, 1); itksysProcess_SetPipeShared(processID, itksysProcess_Pipe_STDERR, 1); } itksysProcess_Execute(processID); char *rawOutput = nullptr; int outputLength = 0; while (true) { int dataStatus = itksysProcess_WaitForData(processID, &rawOutput, &outputLength, nullptr); if (dataStatus == itksysProcess_Pipe_STDOUT) { std::string data(rawOutput, outputLength); this->InvokeEvent(ExternalProcessStdOutEvent(data)); } else if (dataStatus == itksysProcess_Pipe_STDERR) { std::string data(rawOutput, outputLength); this->InvokeEvent(ExternalProcessStdErrEvent(data)); } else { break; } } itksysProcess_WaitForExit(processID, nullptr); auto state = static_cast(itksysProcess_GetState(processID)); normalExit = (state == itksysProcess_State_Exited); - this->_exitValue = itksysProcess_GetExitValue(processID); + this->m_ExitValue = itksysProcess_GetExitValue(processID); } catch (...) { - delete[] pArguments; throw; } - - delete[] pArguments; - return normalExit; }; - bool ProcessExecutor::execute(const std::string &executionPath, + bool ProcessExecutor::Execute(const std::string &executionPath, const std::string &executableName, ArgumentListType argumentList) { - std::string executableName_OS = getOSDependendExecutableName(executableName); + std::string executableName_OS = GetOSDependendExecutableName(executableName); argumentList.insert(argumentList.begin(), executableName_OS); - return execute(executionPath, argumentList); - }; + return Execute(executionPath, argumentList); + } ProcessExecutor::ProcessExecutor() { - this->_exitValue = 0; + this->m_ExitValue = 0; this->m_SharedOutputPipes = false; - }; + } ProcessExecutor::~ProcessExecutor() = default; } // namespace mitk diff --git a/Modules/Segmentation/Interactions/mitkProcessExecutor.h b/Modules/Segmentation/Interactions/mitkProcessExecutor.h index 3911fb81b4..79856889b4 100644 --- a/Modules/Segmentation/Interactions/mitkProcessExecutor.h +++ b/Modules/Segmentation/Interactions/mitkProcessExecutor.h @@ -1,104 +1,110 @@ /*============================================================================ 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. ============================================================================*/ // Class is adapted from MatchPoint ProcessExecutor #ifndef __MITK_PROCESS_EXECUTOR_H #define __MITK_PROCESS_EXECUTOR_H +#include #include #include namespace mitk { class ExternalProcessOutputEvent : public itk::AnyEvent { public: typedef ExternalProcessOutputEvent Self; typedef itk::AnyEvent Superclass; explicit ExternalProcessOutputEvent(const std::string &output = "") : m_Output(output) {} ~ExternalProcessOutputEvent() override {} const char *GetEventName() const override { return "ExternalProcessOutputEvent"; } bool CheckEvent(const ::itk::EventObject *e) const override { return dynamic_cast(e); } itk::EventObject *MakeObject() const override { return new Self(m_Output); } std::string GetOutput() const { return m_Output; } private: std::string m_Output; }; #define mitkProcessExecutorEventMacro(classname) \ class classname : public ExternalProcessOutputEvent \ { \ public: \ typedef classname Self; \ typedef ExternalProcessOutputEvent Superclass; \ \ explicit classname(const std::string &output) : Superclass(output) {} \ ~classname() override {} \ \ virtual const char *GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \ virtual ::itk::EventObject *MakeObject() const { return new Self(this->GetOutput()); } \ }; mitkProcessExecutorEventMacro(ExternalProcessStdOutEvent); mitkProcessExecutorEventMacro(ExternalProcessStdErrEvent); - /*! Helper class that allows to execute an application with arguments. - * You may register an observer for an ExternalProcessOutputEvent, ExternalProcessStdOutEvent or + /** + * @brief You may register an observer for an ExternalProcessOutputEvent, ExternalProcessStdOutEvent or * ExternalProcessStdErrEvent in order to get notified of any output. * @remark The events will only be invoked if the pipes are NOT(!) shared. By default the pipes are not shared. + * */ - class /*MITKSEGMENTATION_EXPORT*/ ProcessExecutor : public itk::Object + class MITKSEGMENTATION_EXPORT ProcessExecutor : public itk::Object { public: using Self = ProcessExecutor; using Superclass = ::itk::Object; using Pointer = ::itk::SmartPointer; using ConstPointer = ::itk::SmartPointer; itkTypeMacro(ProcessExecutor, ::itk::Object); itkFactorylessNewMacro(Self); itkSetMacro(SharedOutputPipes, bool); itkGetConstMacro(SharedOutputPipes, bool); using ArgumentListType = std::vector; - bool execute(const std::string &executionPath, const std::string &executableName, ArgumentListType argumentList); + bool Execute(const std::string &executionPath, const std::string &executableName, ArgumentListType argumentList); - /**Executes the process. This version assumes that the executable name is the first argument in the argument list - * and has already been converted to its OS dependent name via the static convert function of this class.*/ - bool execute(const std::string &executionPath, const ArgumentListType &argumentList); + /** + * @brief Executes the process. This version assumes that the executable name is the first argument in the argument + * list and has already been converted to its OS dependent name via the static convert function of this class. + */ + bool Execute(const std::string &executionPath, const ArgumentListType &argumentList); - int getExitValue(); - static std::string ensureCorrectOSPathSeparator(const std::string &); + int GetExitValue(); + static std::string EnsureCorrectOSPathSeparator(const std::string &); - static std::string getOSDependendExecutableName(const std::string &name); + static std::string GetOSDependendExecutableName(const std::string &name); protected: ProcessExecutor(); ~ProcessExecutor() override; - int _exitValue; + int m_ExitValue; - /*! specifies if the child process should share the output pipes (true) or not (false). + /** + * @brief Specifies if the child process should share the output pipes (true) or not (false). * If pipes are not shared the output will be passed by invoking ExternalProcessOutputEvents - * @remark The events will only be invoked if the pipes are NOT(!) shared.*/ + * @remark The events will only be invoked if the pipes are NOT(!) shared. + */ bool m_SharedOutputPipes; }; } // namespace mitk #endif diff --git a/Modules/Segmentation/Interactions/mitknnUnetTool.cpp b/Modules/Segmentation/Interactions/mitknnUnetTool.cpp index 9d74944dc4..c0fdd2de85 100644 --- a/Modules/Segmentation/Interactions/mitknnUnetTool.cpp +++ b/Modules/Segmentation/Interactions/mitknnUnetTool.cpp @@ -1,323 +1,320 @@ /*============================================================================ 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 "mitknnUnetTool.h" #include "mitkIOUtil.h" -#include "mitkImage.h" -#include "mitkLabelSetImage.h" #include "mitkProcessExecutor.h" #include #include #include #include #include #include #include namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, nnUNetTool, "nnUNet tool"); } mitk::nnUNetTool::nnUNetTool() { - this->SetMitkTempDir(mitk::IOUtil::CreateTemporaryDirectory("mitk-XXXXXX")); + this->SetMitkTempDir(IOUtil::CreateTemporaryDirectory("mitk-XXXXXX")); } mitk::nnUNetTool::~nnUNetTool() { itksys::SystemTools::RemoveADirectory(this->GetMitkTempDir()); } void mitk::nnUNetTool::Activated() { Superclass::Activated(); } void mitk::nnUNetTool::UpdateCleanUp() { // This overriden method is intentionally left out for setting later upon demand // in the `RenderOutputBuffer` method. } void mitk::nnUNetTool::RenderOutputBuffer() { - if (this->outputBuffer != nullptr) + if (this->m_OutputBuffer != nullptr) { - Superclass::SetNodeProperties(this->outputBuffer); + Superclass::SetNodeProperties(this->m_OutputBuffer); this->ClearOutputBuffer(); try { if (nullptr != this->GetPreviewSegmentationNode()) { this->GetPreviewSegmentationNode()->SetVisibility(!this->GetSelectedLabels().empty()); } if (this->GetSelectedLabels().empty()) { this->ResetPreviewNode(); } } catch (const mitk::Exception &e) { MITK_INFO << e.GetDescription(); } } } -void mitk::nnUNetTool::SetNodeProperties(mitk::LabelSetImage::Pointer segmentation) +void mitk::nnUNetTool::SetNodeProperties(LabelSetImage::Pointer segmentation) { // This overriden method doesn't set node properties. Intentionally left out for setting later upon demand // in the `RenderOutputBuffer` method. - this->outputBuffer = segmentation; + this->m_OutputBuffer = segmentation; } mitk::LabelSetImage::Pointer mitk::nnUNetTool::GetOutputBuffer() { - return this->outputBuffer; + return this->m_OutputBuffer; } void mitk::nnUNetTool::ClearOutputBuffer() { - this->outputBuffer = nullptr; + this->m_OutputBuffer = nullptr; } us::ModuleResource mitk::nnUNetTool::GetIconResource() const { us::Module *module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("Watershed_48x48.png"); return resource; } const char **mitk::nnUNetTool::GetXPM() const { return nullptr; } const char *mitk::nnUNetTool::GetName() const { return "nnUNet"; } 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 mitk::LabelSetImage::Pointer mitk::nnUNetTool::ComputeMLPreview(const Image *inputAtTimeStep, TimeStepType /*timeStep*/) { - mitk::Image::Pointer _inputAtTimeStep = inputAtTimeStep->Clone(); + Image::Pointer _inputAtTimeStep = inputAtTimeStep->Clone(); std::string inDir, outDir, inputImagePath, outputImagePath, scriptPath; std::string templateFilename = "XXXXXX_000_0000.nii.gz"; - mitk::ProcessExecutor::Pointer spExec = mitk::ProcessExecutor::New(); + ProcessExecutor::Pointer spExec = ProcessExecutor::New(); itk::CStyleCommand::Pointer spCommand = itk::CStyleCommand::New(); spCommand->SetCallback(&onPythonProcessEvent); - spExec->AddObserver(mitk::ExternalProcessOutputEvent(), spCommand); - mitk::ProcessExecutor::ArgumentListType args; + spExec->AddObserver(ExternalProcessOutputEvent(), spCommand); + ProcessExecutor::ArgumentListType args; - inDir = mitk::IOUtil::CreateTemporaryDirectory("nnunet-in-XXXXXX", this->GetMitkTempDir()); + inDir = IOUtil::CreateTemporaryDirectory("nnunet-in-XXXXXX", this->GetMitkTempDir()); std::ofstream tmpStream; inputImagePath = - mitk::IOUtil::CreateTemporaryFile(tmpStream, templateFilename, inDir + mitk::IOUtil::GetDirectorySeparator()); + IOUtil::CreateTemporaryFile(tmpStream, templateFilename, inDir + IOUtil::GetDirectorySeparator()); tmpStream.close(); - std::size_t found = inputImagePath.find_last_of(mitk::IOUtil::GetDirectorySeparator()); + 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("_")); if (this->GetNoPip()) { - scriptPath = this->GetnnUNetDirectory() + mitk::IOUtil::GetDirectorySeparator() + "nnunet" + - mitk::IOUtil::GetDirectorySeparator() + "inference" + mitk::IOUtil::GetDirectorySeparator() + + scriptPath = this->GetnnUNetDirectory() + IOUtil::GetDirectorySeparator() + "nnunet" + + IOUtil::GetDirectorySeparator() + "inference" + IOUtil::GetDirectorySeparator() + "predict_simple.py"; } try { - mitk::IOUtil::Save(_inputAtTimeStep.GetPointer(), inputImagePath); + IOUtil::Save(_inputAtTimeStep.GetPointer(), inputImagePath); if (this->GetMultiModal()) { - for (size_t i = 0; i < this->otherModalPaths.size(); ++i) + for (size_t i = 0; i < this->m_OtherModalPaths.size(); ++i) { - std::string inModalFile = this->otherModalPaths[i]; + std::string inModalFile = this->m_OtherModalPaths[i]; std::string outModalFile = - inDir + mitk::IOUtil::GetDirectorySeparator() + token + "_000_000" + std::to_string(i + 1) + ".nii.gz"; + inDir + IOUtil::GetDirectorySeparator() + token + "_000_000" + std::to_string(i + 1) + ".nii.gz"; std::ifstream src(inModalFile, std::ios::binary); std::ofstream dst(outModalFile, std::ios::binary); dst << src.rdbuf(); dst.close(); src.close(); } } } catch (const mitk::Exception &e) { /* Can't throw mitk exception to the caller. Refer: T28691 */ MITK_ERROR << e.GetDescription(); return nullptr; } // Code calls external process std::string command = "nnUNet_predict"; if (this->GetNoPip()) { -#if defined(__APPLE__) || defined(MACOSX) || defined(linux) || defined(__linux__) - command = "python3"; -#elif defined(_WIN32) +#ifdef _WIN32 command = "python"; +#else + command = "python3"; #endif } - - for (mitk::ModelParams &modelparam : m_ParamQ) + for (ModelParams &modelparam : m_ParamQ) { - outDir = mitk::IOUtil::CreateTemporaryDirectory("nnunet-out-XXXXXX", this->GetMitkTempDir()); - outputImagePath = outDir + mitk::IOUtil::GetDirectorySeparator() + token + "_000.nii.gz"; + outDir = IOUtil::CreateTemporaryDirectory("nnunet-out-XXXXXX", this->GetMitkTempDir()); + outputImagePath = outDir + IOUtil::GetDirectorySeparator() + token + "_000.nii.gz"; modelparam.outputDir = outDir; args.clear(); if (this->GetNoPip()) { args.push_back(scriptPath); } args.push_back("-i"); args.push_back(inDir); args.push_back("-o"); args.push_back(outDir); args.push_back("-t"); args.push_back(modelparam.task); if (modelparam.model.find("cascade") != std::string::npos) { args.push_back("-ctr"); } else { args.push_back("-tr"); } args.push_back(modelparam.trainer); args.push_back("-m"); args.push_back(modelparam.model); args.push_back("-p"); args.push_back(modelparam.planId); if (!modelparam.folds.empty()) { args.push_back("-f"); for (auto fold : modelparam.folds) { args.push_back(fold); } } // args.push_back("--all_in_gpu"); // args.push_back(this->GetAllInGPU() ? std::string("True") : std::string("False")); // args.push_back("--num_threads_preprocessing"); // args.push_back(std::to_string(this->GetPreprocessingThreads())); args.push_back("--num_threads_nifti_save"); args.push_back("1"); // fixing to 1 if (!this->GetMirror()) { args.push_back("--disable_tta"); } if (!this->GetMixedPrecision()) { args.push_back("--disable_mixed_precision"); } if (this->GetEnsemble() && !this->GetPostProcessingJsonDirectory().empty()) { args.push_back("--save_npz"); } try { - std::string resultsFolderEnv = "RESULTS_FOLDER="+this->GetModelDirectory(); + std::string resultsFolderEnv = "RESULTS_FOLDER=" + this->GetModelDirectory(); itksys::SystemTools::PutEnv(resultsFolderEnv.c_str()); - std::string cudaEnv = "CUDA_VISIBLE_DEVICES="+std::to_string(this->GetGpuId()); + std::string cudaEnv = "CUDA_VISIBLE_DEVICES=" + std::to_string(this->GetGpuId()); itksys::SystemTools::PutEnv(cudaEnv.c_str()); - spExec->execute(this->GetPythonPath(), command, args); + spExec->Execute(this->GetPythonPath(), command, args); } catch (const mitk::Exception &e) { /* Can't throw mitk exception to the caller. Refer: T28691 */ MITK_ERROR << e.GetDescription(); return nullptr; } } if (this->GetEnsemble() && !this->GetPostProcessingJsonDirectory().empty()) { args.clear(); command = "nnUNet_ensemble"; - outDir = mitk::IOUtil::CreateTemporaryDirectory("nnunet-ensemble-out-XXXXXX", this->GetMitkTempDir()); - outputImagePath = outDir + mitk::IOUtil::GetDirectorySeparator() + token + "_000.nii.gz"; + outDir = IOUtil::CreateTemporaryDirectory("nnunet-ensemble-out-XXXXXX", this->GetMitkTempDir()); + outputImagePath = outDir + IOUtil::GetDirectorySeparator() + token + "_000.nii.gz"; args.push_back("-f"); - for (mitk::ModelParams &modelparam : m_ParamQ) + for (ModelParams &modelparam : m_ParamQ) { args.push_back(modelparam.outputDir); } args.push_back("-o"); args.push_back(outDir); args.push_back("-pp"); args.push_back(this->GetPostProcessingJsonDirectory()); - spExec->execute(this->GetPythonPath(), command, args); + spExec->Execute(this->GetPythonPath(), command, args); } try { - mitk::LabelSetImage::Pointer resultImage = mitk::LabelSetImage::New(); - mitk::Image::Pointer outputImage = mitk::IOUtil::Load(outputImagePath); + LabelSetImage::Pointer resultImage = LabelSetImage::New(); + Image::Pointer outputImage = IOUtil::Load(outputImagePath); resultImage->InitializeByLabeledImage(outputImage); resultImage->SetGeometry(_inputAtTimeStep->GetGeometry()); return resultImage; } - catch (const mitk::Exception &e) + catch (const Exception &e) { /* Can't throw mitk exception to the caller. Refer: T28691 */ MITK_ERROR << e.GetDescription(); return nullptr; } } diff --git a/Modules/Segmentation/Interactions/mitknnUnetTool.h b/Modules/Segmentation/Interactions/mitknnUnetTool.h index 02fc1eb489..519f3ea016 100644 --- a/Modules/Segmentation/Interactions/mitknnUnetTool.h +++ b/Modules/Segmentation/Interactions/mitknnUnetTool.h @@ -1,192 +1,191 @@ /*============================================================================ 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 mitknnUnetTool_h_Included #define mitknnUnetTool_h_Included #include "mitkAutoMLSegmentationWithPreviewTool.h" #include "mitkCommon.h" #include #include -namespace us //remove? +namespace us { class ModuleResource; } namespace mitk { /** * @brief nnUNet parameter request object holding all model parameters for input. * Also holds output temporary directory path. */ struct ModelParams { std::string task; std::vector folds; std::string model; std::string trainer; std::string planId; std::string outputDir; }; /** \brief nnUNet segmentation tool. \ingroup Interaction \ingroup ToolManagerEtAl \warning Only to be instantiated by mitk::ToolManager. */ class MITKSEGMENTATION_EXPORT nnUNetTool : public AutoMLSegmentationWithPreviewTool { public: mitkClassMacro(nnUNetTool, AutoMLSegmentationWithPreviewTool); itkFactorylessNewMacro(Self); itkCloneMacro(Self); const char **GetXPM() const override; const char *GetName() const override; us::ModuleResource GetIconResource() const override; void Activated() override; itkSetMacro(nnUNetDirectory, std::string); itkGetConstMacro(nnUNetDirectory, std::string); itkSetMacro(ModelDirectory, std::string); itkGetConstMacro(ModelDirectory, std::string); itkSetMacro(PythonPath, std::string); itkGetConstMacro(PythonPath, std::string); itkSetMacro(MitkTempDir, std::string); itkGetConstMacro(MitkTempDir, std::string); itkSetMacro(PostProcessingJsonDirectory, std::string); itkGetConstMacro(PostProcessingJsonDirectory, std::string); /* itkSetMacro(UseGPU, bool); itkGetConstMacro(UseGPU, bool); itkBooleanMacro(UseGPU); itkSetMacro(AllInGPU, bool); itkGetConstMacro(AllInGPU, bool); itkBooleanMacro(AllInGPU); */ itkSetMacro(MixedPrecision, bool); itkGetConstMacro(MixedPrecision, bool); itkBooleanMacro(MixedPrecision); itkSetMacro(Mirror, bool); itkGetConstMacro(Mirror, bool); itkBooleanMacro(Mirror); itkSetMacro(MultiModal, bool); itkGetConstMacro(MultiModal, bool); itkBooleanMacro(MultiModal); itkSetMacro(NoPip, bool); itkGetConstMacro(NoPip, bool); itkBooleanMacro(NoPip); itkSetMacro(Ensemble, bool); itkGetConstMacro(Ensemble, bool); itkBooleanMacro(Ensemble); itkSetMacro(GpuId, unsigned int); itkGetConstMacro(GpuId, unsigned int); /** * @brief vector of ModelParams. * Size > 1 only for ensemble prediction. */ - std::vector m_ParamQ; + std::vector m_ParamQ; /** * @brief Holds paths to other input image modalities. * */ - std::vector otherModalPaths; + std::vector m_OtherModalPaths; /** * @brief Renders the output LabelSetImage. * To called in the main thread. */ void RenderOutputBuffer(); /** * @brief Get the Output Buffer object * - * @return mitk::LabelSetImage::Pointer + * @return LabelSetImage::Pointer */ - mitk::LabelSetImage::Pointer GetOutputBuffer(); + LabelSetImage::Pointer GetOutputBuffer(); /** * @brief Sets the outputBuffer to nullptr * */ void ClearOutputBuffer(); protected: /** * @brief Construct a new nnUNet Tool object and temp directory. * */ nnUNetTool(); /** * @brief Destroy the nnUNet Tool object and deletes the temp directory. * */ ~nnUNetTool(); /** * @brief Overriden method from the tool manager to execute the segmentation * Implementation: * 1. Saves the inputAtTimeStep in a temporary directory. * 2. Copies other modalities, renames and saves in the temporary directory, if required. * 3. Sets RESULTS_FOLDER and CUDA_VISIBLE_DEVICES variables in the environment. * 3. Iterates through the parameter queue (m_ParamQ) and executes "nnUNet_predict" 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 returns. * * @param inputAtTimeStep * @param timeStep * @return LabelSetImage::Pointer */ LabelSetImage::Pointer ComputeMLPreview(const Image *inputAtTimeStep, TimeStepType timeStep) override; void UpdateCleanUp() override; - void SetNodeProperties(mitk::LabelSetImage::Pointer) override; + void SetNodeProperties(LabelSetImage::Pointer) override; private: std::string m_MitkTempDir; std::string m_nnUNetDirectory; std::string m_ModelDirectory; std::string m_PythonPath; std::string m_PostProcessingJsonDirectory; //bool m_UseGPU; kept for future //bool m_AllInGPU; bool m_MixedPrecision; bool m_Mirror; bool m_NoPip; bool m_MultiModal; bool m_Ensemble = false; - mitk::LabelSetImage::Pointer outputBuffer; + LabelSetImage::Pointer m_OutputBuffer; unsigned int m_GpuId; }; } // namespace mitk - -#endif \ No newline at end of file +#endif diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.cpp b/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.cpp index ecf51e1a6e..e85bf4f487 100644 --- a/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.cpp @@ -1,48 +1,44 @@ /*============================================================================ 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.s ============================================================================*/ #include "QmitknnUNetGPU.h" - #include -#include -#include -#include QmitkGPULoader::QmitkGPULoader() { QProcess process; process.start("nvidia-smi --query-gpu=name,memory.free --format=csv"); process.waitForFinished(-1); QStringList infoStringList; while (process.canReadLine()) { QString line = process.readLine(); if (!line.startsWith("name")) { infoStringList << line; } } foreach (QString infoString, infoStringList) { QmitkGPUSpec spec; QStringList gpuDetails; gpuDetails = infoString.split(","); spec.name = gpuDetails.at(0); - //spec.id = id; + // spec.id = id; spec.memoryFree = gpuDetails.at(1).split(" ")[0].toInt(); - this->gpus.push_back(spec); + this->m_Gpus.push_back(spec); } } int QmitkGPULoader::GetGPUCount() { - return static_cast(gpus.size()); + return static_cast(m_Gpus.size()); } diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.h b/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.h index 52cac71e5b..8ec712499f 100644 --- a/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.h +++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetGPU.h @@ -1,58 +1,58 @@ /*============================================================================ 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.s ============================================================================*/ #ifndef QmitknnUNetToolGPU_h_Included #define QmitknnUNetToolGPU_h_Included -#include -#include +#include +#include #include /** * @brief Struct to store GPU info. - * + * */ struct QmitkGPUSpec { QString name; int memoryFree; unsigned int id; }; /** * @brief Class to load and save GPU information - * for further validation + * for further validation */ class QmitkGPULoader : public QObject { Q_OBJECT private: - std::vector gpus; + std::vector m_Gpus; public: /** * @brief Construct a new Qmitk GPU Loader object. * Parses GPU info using `nvidia-smi` command and saves it as QmitkGPUSpec objects. */ QmitkGPULoader(); ~QmitkGPULoader() = default; /** * @brief Returns the number of GPUs parsed and saved as QmitkGPUSpec objects. - * - * @return int + * + * @return int */ int GetGPUCount(); }; #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitknnUNetToolGUI.cpp index c9e15afdcd..8e3add1bdb 100644 --- a/Modules/SegmentationUI/Qmitk/QmitknnUNetToolGUI.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetToolGUI.cpp @@ -1,256 +1,256 @@ /*============================================================================ 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 "QmitknnUNetToolGUI.h" #include "mitknnUnetTool.h" #include #include #include #include #include #include MITK_TOOL_GUI_MACRO(MITKSEGMENTATIONUI_EXPORT, QmitknnUNetToolGUI, "") QmitknnUNetToolGUI::QmitknnUNetToolGUI() : QmitkAutoMLSegmentationToolGUIBase() { // Nvidia-smi command returning zero doesn't alway mean 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::stringstream stream; stream << "WARNING: No GPUs were detected on your machine. The nnUNet plugin might not work."; QMessageBox *messageBox = new QMessageBox(QMessageBox::Critical, nullptr, stream.str().c_str()); messageBox->exec(); delete messageBox; MITK_WARN << stream.str(); } m_SegmentationThread = new QThread(this); m_Worker = new nnUNetSegmentationWorker; m_Worker->moveToThread(m_SegmentationThread); } QmitknnUNetToolGUI::~QmitknnUNetToolGUI() { this->m_SegmentationThread->quit(); this->m_SegmentationThread->wait(); } void QmitknnUNetToolGUI::ConnectNewTool(mitk::AutoSegmentationWithPreviewTool *newTool) { Superclass::ConnectNewTool(newTool); newTool->IsTimePointChangeAwareOff(); } void QmitknnUNetToolGUI::InitializeUI(QBoxLayout *mainLayout) { m_Controls.setupUi(this); -#if defined(__APPLE__) || defined(MACOSX) || defined(linux) || defined(__linux__) +#ifndef _WIN32 m_Controls.pythonEnvComboBox->addItem("/usr/bin"); #endif m_Controls.pythonEnvComboBox->addItem("Select"); AutoParsePythonPaths(); - connect(m_Controls.previewButton, SIGNAL(clicked()), this, SLOT(OnSettingsAccept())); + connect(m_Controls.previewButton, SIGNAL(clicked()), this, SLOT(OnSettingsAccepted())); connect(m_Controls.modeldirectoryBox, SIGNAL(directoryChanged(const QString &)), this, SLOT(OnDirectoryChanged(const QString &))); connect( m_Controls.modelBox, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnModelChanged(const QString &))); connect(m_Controls.taskBox, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnTaskChanged(const QString &))); connect( m_Controls.trainerBox, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnTrainerChanged(const QString &))); connect(m_Controls.nopipBox, SIGNAL(stateChanged(int)), this, SLOT(OnCheckBoxChanged(int))); connect(m_Controls.multiModalBox, SIGNAL(stateChanged(int)), this, SLOT(OnCheckBoxChanged(int))); connect(m_Controls.multiModalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnModalitiesNumberChanged(int))); connect(m_Controls.pythonEnvComboBox, #if QT_VERSION >= 0x050F00 // 5.15 SIGNAL(textActivated(const QString &)), #elif QT_VERSION >= 0x050C00 // 5.12 SIGNAL(activated(const QString &)), #endif this, SLOT(OnPythonChanged(const QString &))); connect(this, &QmitknnUNetToolGUI::Operate, m_Worker, &nnUNetSegmentationWorker::DoWork); connect(m_Worker, &nnUNetSegmentationWorker::Finished, this, &QmitknnUNetToolGUI::SegmentationResultHandler); connect(m_Worker, &nnUNetSegmentationWorker::Failed, this, &QmitknnUNetToolGUI::SegmentationProcessFailed); connect(m_SegmentationThread, &QThread::finished, m_Worker, &QObject::deleteLater); m_Controls.codedirectoryBox->setVisible(false); m_Controls.nnUnetdirLabel->setVisible(false); m_Controls.multiModalSpinBox->setVisible(false); m_Controls.multiModalSpinLabel->setVisible(false); m_Controls.statusLabel->setTextFormat(Qt::RichText); m_Controls.statusLabel->setText("STATUS: No Tasks Running. " + QString::number(m_GpuLoader.GetGPUCount()) + " GPUs were detected."); if (m_GpuLoader.GetGPUCount() != 0) { m_Controls.gpuSpinBox->setMaximum(m_GpuLoader.GetGPUCount() - 1); } mainLayout->addLayout(m_Controls.verticalLayout); Superclass::InitializeUI(mainLayout); m_UI_ROWS = m_Controls.advancedSettingsLayout->rowCount(); // Must do. Row count is correct only here. } -void QmitknnUNetToolGUI::OnSettingsAccept() +void QmitknnUNetToolGUI::OnSettingsAccepted() { auto tool = this->GetConnectedToolAs(); if (nullptr != tool) { try { QString modelName = m_Controls.modelBox->currentText(); QString taskName = m_Controls.taskBox->currentText(); bool isNoPip = m_Controls.nopipBox->isChecked(); QString pythonPathTextItem = m_Controls.pythonEnvComboBox->currentText(); QString pythonPath = pythonPathTextItem.mid(pythonPathTextItem.indexOf(" ") + 1); -#if defined(__APPLE__) || defined(MACOSX) || defined(linux) || defined(__linux__) - if (!(pythonPath.endsWith("bin", Qt::CaseInsensitive) || pythonPath.endsWith("bin/", Qt::CaseInsensitive))) - { - pythonPath += QDir::separator() + QString("bin"); - } -#elif defined(_WIN32) +#ifdef _WIN32 if (!isNoPip && !(pythonPath.endsWith("Scripts", Qt::CaseInsensitive) || pythonPath.endsWith("Scripts/", Qt::CaseInsensitive))) { pythonPath += QDir::separator() + QString("Scripts"); } +#else + if (!(pythonPath.endsWith("bin", Qt::CaseInsensitive) || pythonPath.endsWith("bin/", Qt::CaseInsensitive))) + { + pythonPath += QDir::separator() + QString("bin"); + } #endif std::string nnUNetDirectory; if (isNoPip) { nnUNetDirectory = m_Controls.codedirectoryBox->directory().toStdString(); } else if (!IsNNUNetInstalled(pythonPath)) { throw std::runtime_error("nnUNet is not detected in the selected python environment. Please select a valid " "python environment or install nnUNet."); } QString trainerPlanner = m_Controls.trainerBox->currentText(); QString splitterString = "__"; tool->EnsembleOff(); if (modelName.startsWith("ensemble", Qt::CaseInsensitive)) { QString ppJsonFile = QDir::cleanPath(m_ModelDirectory + QDir::separator() + modelName + QDir::separator() + taskName + QDir::separator() + trainerPlanner + QDir::separator() + "postprocessing.json"); if (QFile(ppJsonFile).exists()) { tool->EnsembleOn(); tool->SetPostProcessingJsonDirectory(ppJsonFile.toStdString()); splitterString = "--"; } } QStringList trainerSplitParts = trainerPlanner.split(splitterString, QString::SplitBehavior::SkipEmptyParts); std::vector requestQ; if (tool->GetEnsemble()) { foreach (QString modelSet, trainerSplitParts) { modelSet.remove("ensemble_", Qt::CaseInsensitive); QStringList splitParts = modelSet.split("__", QString::SplitBehavior::SkipEmptyParts); QString modelName = splitParts.first(); QString trainer = splitParts.at(1); QString planId = splitParts.at(2); auto testfold = std::vector(1, "1"); mitk::ModelParams modelObject = MapToRequest(modelName, taskName, trainer, planId, testfold); requestQ.push_back(modelObject); } } else { QString trainer = trainerSplitParts.first(); QString planId = trainerSplitParts.last(); std::vector fetchedFolds = FetchSelectedFoldsFromUI(); mitk::ModelParams modelObject = MapToRequest(modelName, taskName, trainer, planId, fetchedFolds); requestQ.push_back(modelObject); } tool->m_ParamQ.clear(); tool->m_ParamQ = requestQ; tool->SetnnUNetDirectory(nnUNetDirectory); tool->SetPythonPath(pythonPath.toStdString()); tool->SetModelDirectory(m_ModelDirectory.left(m_ModelDirectory.lastIndexOf(QDir::separator())).toStdString()); // checkboxes tool->SetMirror(m_Controls.mirrorBox->isChecked()); tool->SetMixedPrecision(m_Controls.mixedPrecisionBox->isChecked()); tool->SetNoPip(isNoPip); tool->SetMultiModal(m_Controls.multiModalBox->isChecked()); // Spinboxes tool->SetGpuId(static_cast(m_Controls.gpuSpinBox->value())); // Multi-Modal tool->MultiModalOff(); if (m_Controls.multiModalBox->isChecked()) { - tool->otherModalPaths.clear(); - tool->otherModalPaths = FetchMultiModalPathsFromUI(); + tool->m_OtherModalPaths.clear(); + tool->m_OtherModalPaths = FetchMultiModalPathsFromUI(); tool->MultiModalOn(); } if (!m_SegmentationThread->isRunning()) { - MITK_INFO << "Starting thread..."; + MITK_DEBUG << "Starting thread..."; m_SegmentationThread->start(); } m_Controls.statusLabel->setText("STATUS: Starting Segmentation task... This might take a while."); emit Operate(tool); } catch (const std::exception &e) { this->setCursor(Qt::ArrowCursor); std::stringstream stream; stream << "Error while processing parameters for nnUNet segmentation. Reason: " << e.what(); QMessageBox *messageBox = new QMessageBox(QMessageBox::Critical, nullptr, stream.str().c_str()); messageBox->exec(); delete messageBox; MITK_ERROR << stream.str(); return; } catch (...) { this->setCursor(Qt::ArrowCursor); std::stringstream stream; stream << "Unkown error occured while generation nnUNet segmentation."; QMessageBox *messageBox = new QMessageBox(QMessageBox::Critical, nullptr, stream.str().c_str()); messageBox->exec(); delete messageBox; MITK_ERROR << stream.str(); return; } } } std::vector QmitknnUNetToolGUI::FetchMultiModalPathsFromUI() { std::vector paths; if (m_Controls.multiModalBox->isChecked() && !m_ModalPaths.empty()) { for (auto modality : m_ModalPaths) { paths.push_back(modality->currentPath().toStdString()); } } return paths; } bool QmitknnUNetToolGUI::IsNNUNetInstalled(const QString &text) { return QFile::exists(text + QDir::separator() + QString("nnUNet_predict")); -} \ No newline at end of file +} diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitknnUNetToolGUI.h index 0ddca92d47..b7528f2f60 100644 --- a/Modules/SegmentationUI/Qmitk/QmitknnUNetToolGUI.h +++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetToolGUI.h @@ -1,188 +1,189 @@ /*============================================================================ 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.s ============================================================================*/ #ifndef QmitknnUNetToolGUI_h_Included #define QmitknnUNetToolGUI_h_Included #include "QmitkAutoMLSegmentationToolGUIBase.h" #include "QmitknnUNetGPU.h" #include "QmitknnUNetWorker.h" #include "mitknnUnetTool.h" #include "ui_QmitknnUNetToolGUIControls.h" #include #include #include #include class MITKSEGMENTATIONUI_EXPORT QmitknnUNetToolGUI : public QmitkAutoMLSegmentationToolGUIBase { Q_OBJECT public: mitkClassMacro(QmitknnUNetToolGUI, QmitkAutoMLSegmentationToolGUIBase); itkFactorylessNewMacro(Self); itkCloneMacro(Self); protected slots: /** * @brief Qt slot * */ - void OnSettingsAccept(); + void OnSettingsAccepted(); /** * @brief Qt slot * */ void OnDirectoryChanged(const QString &); /** * @brief Qt slot * */ void OnModelChanged(const QString &); /** * @brief Qt slot * */ void OnTaskChanged(const QString &); /** * @brief Qt slot * */ void OnTrainerChanged(const QString &); /** * @brief Qt slot * */ void OnPythonChanged(const QString &); /** * @brief Qt slot * */ void OnCheckBoxChanged(int); /** - * @brief Qthread slot to captured failures from thread worker and + * @brief Qthread slot to capture failures from thread worker and * shows error message * */ void SegmentationProcessFailed(); /** * @brief Qthread to capture sucessfull nnUNet segmentation. * Further, renders the LabelSet image */ void SegmentationResultHandler(mitk::nnUNetTool *); /** * @brief Qt Slot * */ void OnModalitiesNumberChanged(int); signals: /** * @brief signal for starting the segmentation which is caught by a worker thread. */ void Operate(mitk::nnUNetTool *); protected: QmitknnUNetToolGUI(); ~QmitknnUNetToolGUI(); void ConnectNewTool(mitk::AutoSegmentationWithPreviewTool *newTool) override; void InitializeUI(QBoxLayout *mainLayout) override; void EnableWidgets(bool enabled) override; private: /** * @brief Searches and parses paths of python virtual enviroments * from predefined lookout locations */ void AutoParsePythonPaths(); /** * @brief Clears all combo boxes * Any new combo box added in the future can be featured here for clearance. * */ void ClearAllComboBoxes(); /** * @brief Checks if nnUNet_predict command is valid in the selected python virtual environment. * * @return bool */ bool IsNNUNetInstalled(const QString &); /** * @brief Mapper function to map QString entries from UI to ModelParam attributes. * * @return mitk::ModelParams */ - mitk::ModelParams MapToRequest(QString &, QString &, QString &, QString &, std::vector &); + mitk::ModelParams MapToRequest( + const QString &, const QString &, const QString &, const QString &, const std::vector &); /** * @brief Returns checked fold names from the ctk-Checkable-ComboBox. * * @return std::vector */ std::vector FetchSelectedFoldsFromUI(); /** * @brief Returns all paths from the dynamically generated ctk-path-line-edit boxes. * * @return std::vector */ std::vector FetchMultiModalPathsFromUI(); /** * @brief Template function to fetch all folders inside a given path. * The type can be any of stl or Qt containers which supports push_back call. * * @tparam T * @return T */ template static T FetchFoldersFromDir(const QString &); /** * @brief Stores path of the model director (RESULTS_FOLDER appended by "nnUNet"). * */ QString m_ModelDirectory; Ui_QmitknnUNetToolGUIControls m_Controls; QThread *m_SegmentationThread; nnUNetSegmentationWorker *m_Worker; QmitkGPULoader m_GpuLoader; /** * @brief Stores all dynamically added ctk-path-line-edit UI elements. * */ std::vector m_ModalPaths; /** * @brief Stores row count of the "advancedSettingsLayout" layout element. This value helps dynamically add * ctk-path-line-edit UI elements at the right place. Forced to initialize in the InitializeUI method since there is * no guarantee of retrieving exact row count anywhere else. * */ int m_UI_ROWS; }; #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetToolSlots.cpp b/Modules/SegmentationUI/Qmitk/QmitknnUNetToolSlots.cpp index 7c3b20d1e6..9759631894 100644 --- a/Modules/SegmentationUI/Qmitk/QmitknnUNetToolSlots.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetToolSlots.cpp @@ -1,245 +1,253 @@ #include "QmitknnUNetToolGUI.h" #include #include #include #include #include #include #include void QmitknnUNetToolGUI::EnableWidgets(bool enabled) { Superclass::EnableWidgets(enabled); m_Controls.previewButton->setEnabled(false); } void QmitknnUNetToolGUI::ClearAllComboBoxes() { m_Controls.modelBox->clear(); m_Controls.taskBox->clear(); m_Controls.foldBox->clear(); m_Controls.trainerBox->clear(); } template T QmitknnUNetToolGUI::FetchFoldersFromDir(const QString &path) { T folders; for (QDirIterator it(path, QDir::AllDirs, QDirIterator::NoIteratorFlags); it.hasNext();) { it.next(); if (!it.fileName().startsWith('.')) { folders.push_back(it.fileName()); } } return folders; } void QmitknnUNetToolGUI::OnDirectoryChanged(const QString &resultsFolder) { m_Controls.previewButton->setEnabled(false); this->ClearAllComboBoxes(); m_ModelDirectory = resultsFolder + QDir::separator() + "nnUNet"; auto models = FetchFoldersFromDir(m_ModelDirectory); QStringList validlist; // valid list of models supported by nnUNet validlist << "2d" << "3d_lowres" << "3d_fullres" << "3d_cascade_fullres" << "ensembles"; std::for_each(models.begin(), models.end(), [this, validlist](QString model) { if (validlist.contains(model, Qt::CaseInsensitive)) m_Controls.modelBox->addItem(model); }); } void QmitknnUNetToolGUI::OnModelChanged(const QString &text) { QString updatedPath(QDir::cleanPath(m_ModelDirectory + QDir::separator() + text)); m_Controls.taskBox->clear(); auto datasets = FetchFoldersFromDir(updatedPath); std::for_each(datasets.begin(), datasets.end(), [this](QString dataset) { m_Controls.taskBox->addItem(dataset); }); } void QmitknnUNetToolGUI::OnTaskChanged(const QString &text) { QString updatedPath = QDir::cleanPath(m_ModelDirectory + QDir::separator() + m_Controls.modelBox->currentText() + QDir::separator() + text); m_Controls.trainerBox->clear(); auto trainers = FetchFoldersFromDir(updatedPath); std::for_each(trainers.begin(), trainers.end(), [this](QString trainer) { m_Controls.trainerBox->addItem(trainer); }); } void QmitknnUNetToolGUI::OnTrainerChanged(const QString &trainerSelected) { m_Controls.foldBox->clear(); if (m_Controls.modelBox->currentText() != "ensembles") { QString updatedPath(QDir::cleanPath(m_ModelDirectory + QDir::separator() + m_Controls.modelBox->currentText() + QDir::separator() + m_Controls.taskBox->currentText() + QDir::separator() + trainerSelected)); auto folds = FetchFoldersFromDir(updatedPath); std::for_each(folds.begin(), folds.end(), [this](QString fold) { if (fold.startsWith("fold_", Qt::CaseInsensitive)) // imposed by nnUNet m_Controls.foldBox->addItem(fold); }); if (m_Controls.foldBox->count() != 0) { m_Controls.previewButton->setEnabled(true); } } else { m_Controls.previewButton->setEnabled(true); } } void QmitknnUNetToolGUI::OnPythonChanged(const QString &pyEnv) { if (pyEnv == QString("Select")) { QString path = QFileDialog::getExistingDirectory(m_Controls.pythonEnvComboBox->parentWidget(), "Python Path", "dir"); if (!path.isEmpty()) { m_Controls.pythonEnvComboBox->insertItem(0, path); m_Controls.pythonEnvComboBox->setCurrentIndex(0); } } } void QmitknnUNetToolGUI::OnCheckBoxChanged(int state) { bool visibility = false; if (state == Qt::Checked) { visibility = true; } ctkCheckBox *box = qobject_cast(sender()); if (box != nullptr) { if (box->objectName() == QString("nopipBox")) { m_Controls.codedirectoryBox->setVisible(visibility); m_Controls.nnUnetdirLabel->setVisible(visibility); } else if (box->objectName() == QString("multiModalBox")) { m_Controls.multiModalSpinLabel->setVisible(visibility); m_Controls.multiModalSpinBox->setVisible(visibility); + if (!visibility) + { + OnModalitiesNumberChanged(0); + m_Controls.multiModalSpinBox->setValue(0); + } } } } void QmitknnUNetToolGUI::OnModalitiesNumberChanged(int num) { - if (num > (int)this->m_ModalPaths.size()) + while (num > static_cast(this->m_ModalPaths.size())) { ctkPathLineEdit *multiModalPath = new ctkPathLineEdit(this); multiModalPath->setObjectName(QString("multiModalPath" + QString::number(m_ModalPaths.size() + 1))); m_Controls.advancedSettingsLayout->addWidget(multiModalPath, this->m_UI_ROWS + m_ModalPaths.size() + 1, 1, 1, 3); m_ModalPaths.push_back(multiModalPath); } - else if (num < (int)this->m_ModalPaths.size() && !m_ModalPaths.empty()) + while (num < static_cast(this->m_ModalPaths.size()) && !m_ModalPaths.empty()) { ctkPathLineEdit *child = m_ModalPaths.back(); delete child; // delete the layout item m_ModalPaths.pop_back(); } m_Controls.advancedSettingsLayout->update(); } void QmitknnUNetToolGUI::AutoParsePythonPaths() { QString homeDir = QDir::homePath(); std::vector searchDirs; -#if defined(__APPLE__) || defined(MACOSX) || defined(linux) || defined(__linux__) +#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"); -#elif defined(_WIN32) || defined(_WIN64) - searchDirs.push_back(QString("C:") + QDir::separator() + QString("ProgramData") + QDir::separator() + - QString("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); } std::vector QmitknnUNetToolGUI::FetchSelectedFoldsFromUI() { std::vector folds; if (!(m_Controls.foldBox->allChecked() || m_Controls.foldBox->noneChecked())) { QModelIndexList foldList = m_Controls.foldBox->checkedIndexes(); foreach (QModelIndex index, foldList) { QString foldQString = m_Controls.foldBox->itemText(index.row()).split("_", QString::SplitBehavior::SkipEmptyParts).last(); folds.push_back(foldQString.toStdString()); } } return folds; } -mitk::ModelParams QmitknnUNetToolGUI::MapToRequest( - QString &modelName, QString &taskName, QString &trainer, QString &planId, std::vector &folds) +mitk::ModelParams QmitknnUNetToolGUI::MapToRequest(const QString &modelName, + const QString &taskName, + const QString &trainer, + const QString &planId, + const std::vector &folds) { mitk::ModelParams requestObject; requestObject.model = modelName.toStdString(); requestObject.trainer = trainer.toStdString(); requestObject.planId = planId.toStdString(); requestObject.task = taskName.toStdString(); requestObject.folds = folds; return requestObject; } void QmitknnUNetToolGUI::SegmentationProcessFailed() { m_Controls.statusLabel->setText( "STATUS: Error in the segmentation process. No resulting segmentation can be loaded."); this->setCursor(Qt::ArrowCursor); std::stringstream stream; stream << "Error in the segmentation process. No resulting segmentation can be loaded."; QMessageBox *messageBox = new QMessageBox(QMessageBox::Critical, nullptr, stream.str().c_str()); messageBox->exec(); delete messageBox; MITK_ERROR << stream.str(); } void QmitknnUNetToolGUI::SegmentationResultHandler(mitk::nnUNetTool *tool) { MITK_INFO << "Finished slot"; tool->RenderOutputBuffer(); this->SetLabelSetPreview(tool->GetMLPreview()); tool->IsTimePointChangeAwareOn(); m_Controls.statusLabel->setText("STATUS: Segmentation task finished successfully."); } diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetWorker.cpp b/Modules/SegmentationUI/Qmitk/QmitknnUNetWorker.cpp index 05803646ce..a765effeb2 100644 --- a/Modules/SegmentationUI/Qmitk/QmitknnUNetWorker.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetWorker.cpp @@ -1,24 +1,24 @@ #include "QmitknnUNetWorker.h" #include "mitkRenderingManager.h" #include void nnUNetSegmentationWorker::DoWork(mitk::nnUNetTool *tool) { - MITK_INFO << "in nnUNet Worker"; + MITK_DEBUG << "in nnUNet Worker"; try { QMutexLocker locker(&mutex); tool->UpdatePreview(); if (tool->GetOutputBuffer() == nullptr) { mitkThrow() << "An error occured while calling nnUNet process."; } emit Finished(tool); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); emit Failed(); } } diff --git a/Modules/SegmentationUI/Qmitk/QmitknnUNetWorker.h b/Modules/SegmentationUI/Qmitk/QmitknnUNetWorker.h index f5657d9755..b820975ec6 100644 --- a/Modules/SegmentationUI/Qmitk/QmitknnUNetWorker.h +++ b/Modules/SegmentationUI/Qmitk/QmitknnUNetWorker.h @@ -1,47 +1,46 @@ /*============================================================================ 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.s ============================================================================*/ #ifndef QmitknnUNetWorker_h #define QmitknnUNetWorker_h #include #include #include /** * @class nnUNetSegmentationWorker * @brief Class to execute some functions (mainly segmentation) from the nnUNet Tool in a seperate thread */ class nnUNetSegmentationWorker : public QObject { Q_OBJECT public slots: /** * @brief execute segmentation with the correct segmentation tool */ void DoWork(mitk::nnUNetTool *); signals: /** * @brief the signal emitted when a segmentation process finished successful */ void Finished(mitk::nnUNetTool *); /** * @brief the signal emitted when a segmentation process failed */ void Failed(); private: QMutex mutex; }; - #endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp index edc95b0b91..91cfe486e2 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,907 +1,907 @@ /*============================================================================ 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 #include "mitkProperties.h" #include "mitkSegTool2D.h" #include "mitkStatusBar.h" #include "QmitkNewSegmentationDialog.h" #include #include #include #include "QmitkSegmentationView.h" #include #include "mitkVtkResliceInterpolationProperty.h" #include "mitkApplicationCursor.h" #include "mitkSegmentationObjectFactory.h" #include "mitkPluginActivator.h" #include "mitkCameraController.h" #include "mitkLabelSetImage.h" #include "mitkImageTimeSelector.h" #include "mitkNodePredicateSubGeometry.h" #include #include "usModuleResource.h" #include "usModuleResourceStream.h" //micro service to get the ToolManager instance #include "mitkToolManagerProvider.h" #include #include const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; QmitkSegmentationView::QmitkSegmentationView() : m_Parent(nullptr) , m_Controls(nullptr) , m_RenderWindowPart(nullptr) , m_MouseCursorSet(false) , m_DataSelectionChanged(false) { mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); m_IsNotAHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); m_IsOfTypeImagePredicate = mitk::NodePredicateAnd::New(validImages, m_IsNotAHelperObject); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New(isBinaryPredicate); mitk::NodePredicateAnd::Pointer isABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isBinaryPredicate); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isNotBinaryPredicate); auto isMLImageType = mitk::TNodePredicateDataType::New(); mitk::NodePredicateAnd::Pointer isAMLImagePredicate = mitk::NodePredicateAnd::New(isMLImageType, m_IsNotAHelperObject); mitk::NodePredicateAnd::Pointer isNotAMLImagePredicate = mitk::NodePredicateAnd::New(mitk::NodePredicateNot::New(isMLImageType), m_IsNotAHelperObject); m_IsASegmentationImagePredicate = mitk::NodePredicateOr::New(isABinaryImagePredicate, isAMLImagePredicate); m_IsAPatientImagePredicate = mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, isNotAMLImagePredicate); } QmitkSegmentationView::~QmitkSegmentationView() { if (m_Controls) { SetToolSelectionBoxesEnabled(false); // deactivate all tools mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); // removing all observers for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_WorkingDataObserverTags.clear(); mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); SetToolManagerSelection(nullptr, nullptr); } delete m_Controls; } void QmitkSegmentationView::NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType* nodes) { if (!nodes) return; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); if (!toolManager) return; for (mitk::ToolManager::DataVectorType::iterator iter = nodes->begin(); iter != nodes->end(); ++iter) { this->FireNodeSelected( *iter ); // only last iteration meaningful, multiple generated objects are not taken into account here } } void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; } if (m_Parent) { m_Parent->setEnabled(true); } // tell the interpolation about tool manager, data storage and render window part if (m_Controls) { mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_Controls->m_SlicesInterpolator->SetDataStorage(this->GetDataStorage()); QList controllers; controllers.push_back(renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls->m_SlicesInterpolator->Initialize(toolManager, controllers); } } void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_RenderWindowPart = nullptr; if (m_Parent) { m_Parent->setEnabled(false); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (m_Controls != nullptr) { bool slimView = prefs->GetBool("slim view", false); m_Controls->m_ManualToolSelectionBox2D->SetShowNames(!slimView); m_Controls->m_ManualToolSelectionBox3D->SetShowNames(!slimView); m_Controls->btnNewSegmentation->setToolButtonStyle(slimView ? Qt::ToolButtonIconOnly : Qt::ToolButtonTextOnly); } auto autoSelectionEnabled = prefs->GetBool("auto selection", true); m_Controls->patImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); m_Controls->segImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); this->ForceDisplayPreferencesUponAllImages(); } void QmitkSegmentationView::CreateNewSegmentation() { mitk::DataNode::Pointer node = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::ConstPointer referenceImage = dynamic_cast(node->GetData()); if (referenceImage.IsNotNull()) { if (referenceImage->GetDimension() > 1) { // ask about the name and organ type of the new segmentation QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog(m_Parent); // needs a QWidget as parent, "this" is not QWidget QStringList organColors = mitk::OrganNamesHandling::GetDefaultOrganColorString();; dialog->SetSuggestionList(organColors); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { // user clicked cancel or pressed Esc or something similar return; } const auto currentTimePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); unsigned int imageTimeStep = 0; if (referenceImage->GetTimeGeometry()->IsValidTimePoint(currentTimePoint)) { imageTimeStep = referenceImage->GetTimeGeometry()->TimePointToTimeStep(currentTimePoint); } auto segTemplateImage = referenceImage; if (referenceImage->GetDimension() > 3) { auto result = QMessageBox::question(m_Parent, tr("Create a static or dynamic segmentation?"), tr("The patient image has multiple time steps.\n\nDo you want to create a static segmentation that is identical for all time steps or do you want to create a dynamic segmentation to segment individual time steps?"), tr("Create static segmentation"), tr("Create dynamic segmentation"), QString(), 0,0); if (result == 0) { auto selector = mitk::ImageTimeSelector::New(); selector->SetInput(referenceImage); selector->SetTimeNr(0); selector->Update(); const auto refTimeGeometry = referenceImage->GetTimeGeometry(); auto newTimeGeometry = mitk::ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(refTimeGeometry->GetMinimumTimePoint()); newTimeGeometry->SetStepDuration(refTimeGeometry->GetMaximumTimePoint() - refTimeGeometry->GetMinimumTimePoint()); mitk::Image::Pointer newImage = selector->GetOutput(); newTimeGeometry->SetTimeStepGeometry(referenceImage->GetGeometry(imageTimeStep), 0); newImage->SetTimeGeometry(newTimeGeometry); segTemplateImage = newImage; } } // ask the user about an organ type and name, add this information to the image's (!) propertylist // create a new image of the same dimensions and smallest possible pixel type mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::Tool* firstTool = toolManager->GetToolById(0); if (firstTool) { try { std::string newNodeName = dialog->GetSegmentationName().toStdString(); if (newNodeName.empty()) { newNodeName = "no_name"; } mitk::DataNode::Pointer emptySegmentation = firstTool->CreateEmptySegmentationNode(segTemplateImage, newNodeName, dialog->GetColor()); // initialize showVolume to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty("showVolume", mitk::BoolProperty::New(false)); if (!emptySegmentation) { return; // could be aborted by user } mitk::OrganNamesHandling::UpdateOrganList(organColors, dialog->GetSegmentationName(), dialog->GetColor()); // escape ';' here (replace by '\;'), see longer comment above QString stringForStorage = organColors.replaceInStrings(";", "\\;").join(";"); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->Put("Organ-Color-List", stringForStorage); this->GetPreferences()->Flush(); if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)) { mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); this->GetDataStorage()->Add(emptySegmentation, node); // add as a child, because the segmentation "derives" from the original m_Controls->segImageSelector->SetCurrentSelectedNode(emptySegmentation); mitk::RenderingManager::GetInstance()->InitializeViews(referenceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime()->SetPos(imageTimeStep); } catch (const std::bad_alloc&) { QMessageBox::warning(nullptr, tr("Create new segmentation"), tr("Could not allocate memory for new segmentation")); } } } else { QMessageBox::information(nullptr, tr("Segmentation"), tr("Segmentation is currently not supported for 2D images")); } } } else { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a patient image is selected..."; } } void QmitkSegmentationView::OnVisiblePropertyChanged() { this->CheckRenderingState(); } void QmitkSegmentationView::NodeAdded(const mitk::DataNode *node) { if (!m_IsASegmentationImagePredicate->CheckNode(node)) { return; } itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnVisiblePropertyChanged); m_WorkingDataObserverTags.insert(std::pair(const_cast(node), node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); ApplyDisplayOptions(const_cast(node)); } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { if (m_IsASegmentationImagePredicate->CheckNode(node)) { //First of all remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations(node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; if ((mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) && m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) { this->SetToolManagerSelection(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0), nullptr); this->UpdateWarningLabel(tr("Select or create a segmentation")); } mitk::Image* image = dynamic_cast(node->GetData()); mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); } mitk::DataNode* tempNode = const_cast(node); //Remove observer if one was registered auto finding = m_WorkingDataObserverTags.find(tempNode); if (finding != m_WorkingDataObserverTags.end()) { node->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[tempNode]); m_WorkingDataObserverTags.erase(tempNode); } } void QmitkSegmentationView::OnPatientSelectionChanged(QList nodes) { if(! nodes.empty()) { this->UpdateWarningLabel(""); auto node = nodes.first(); auto segPredicate = mitk::NodePredicateAnd::New(m_IsASegmentationImagePredicate.GetPointer(), mitk::NodePredicateSubGeometry::New(node->GetData()->GetGeometry())); m_Controls->segImageSelector->SetNodePredicate(segPredicate); mitk::DataNode* segNode = m_Controls->segImageSelector->GetSelectedNode(); this->SetToolManagerSelection(node, segNode); if (segNode) { //Doing this we can assure that the segmentation is always visible if the segmentation and the patient image are //loaded separately int layer(10); node->GetIntProperty("layer", layer); layer++; segNode->SetProperty("layer", mitk::IntProperty::New(layer)); this->CheckRenderingState(); } else { this->SetToolSelectionBoxesEnabled( false ); this->UpdateWarningLabel(tr("Select or create a segmentation")); } } else { m_Controls->segImageSelector->SetNodePredicate(m_IsASegmentationImagePredicate); this->UpdateWarningLabel(tr("Please select an image!")); this->SetToolSelectionBoxesEnabled( false ); } } void QmitkSegmentationView::OnSegmentationSelectionChanged(QList nodes) { if (nodes.empty()) { this->UpdateWarningLabel(tr("Select or create a segmentation")); this->SetToolSelectionBoxesEnabled( false ); return; } auto refNode = m_Controls->patImageSelector->GetSelectedNode(); auto segNode = nodes.front(); if (!refNode) { this->UpdateWarningLabel(tr("Please select the matching patient image!")); this->SetToolSelectionBoxesEnabled(false); this->SetToolManagerSelection(nullptr, segNode); return; } this->CheckRenderingState(); if ( m_Controls->lblSegmentationWarnings->isVisible()) // "this->CheckRenderingState()" caused a warning. we do not need to go any further return; this->SetToolManagerSelection(refNode, segNode); if (segNode) { //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are //loaded separately int layer(10); refNode->GetIntProperty("layer", layer); layer++; segNode->SetProperty("layer", mitk::IntProperty::New(layer)); } else { this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("Select or create a segmentation")); } mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); if (!renderWindowPart || !segNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer())) { this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); this->SetToolSelectionBoxesEnabled( false ); } } void QmitkSegmentationView::OnShowMarkerNodes (bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetTools().size(); for(unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetToolById(i)); if (manualSegmentationTool) { if(state == true) { manualSegmentationTool->SetShowMarkerNodes( true ); } else { manualSegmentationTool->SetShowMarkerNodes( false ); } } } } void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode *node) { QmitkRenderWindow* selectedRenderWindow = nullptr; auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); auto* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); auto* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); auto* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); auto* _3DRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, _3DRenderWindow->GetRenderer())) { selectedRenderWindow = _3DRenderWindow; } // make node visible if (selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t+1).c_str())-1; { ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); context->ungetService(ppmRef); } selectedRenderWindow->GetRenderer()->GetCameraController()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList &nodes) { if (nodes.size() != 0) { std::string markerName = "Position"; unsigned int numberOfNodes = nodes.size(); std::string nodeName = nodes.at(0)->GetName(); if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) { this->OnContourMarkerSelected(nodes.at(0)); return; } } } void QmitkSegmentationView::OnTabWidgetChanged(int id) { //always disable tools on tab changed mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); //2D Tab ID = 0 //3D Tab ID = 1 if (id == 0) { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); //Deactivate possible active tool //TODO Remove possible visible interpolations -> Maybe changes in SlicesInterpolator } else { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox2D->hide(); m_Controls->m_ManualToolSelectionBox3D->show(); //Deactivate possible active tool } } void QmitkSegmentationView::SetToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData) { // called as a result of new BlueBerry selections // tells the ToolManager for manual segmentation about new selections // updates GUI information about what the user should select mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); toolManager->SetReferenceData(const_cast(referenceData)); toolManager->SetWorkingData(const_cast(workingData)); m_Controls->btnNewSegmentation->setEnabled(referenceData != nullptr); } void QmitkSegmentationView::ForceDisplayPreferencesUponAllImages() { if (!m_Parent) { return; } // check all images and segmentations in DataStorage: // (items in brackets are implicitly done by previous steps) // 1. // if a reference image is selected, // show the reference image // and hide all other images (orignal and segmentation), // (and hide all segmentations of the other original images) // and show all the reference's segmentations // if no reference image is selected, do do nothing // // 2. // if a segmentation is selected, // show it // (and hide all all its siblings (childs of the same parent, incl, nullptr parent)) // if no segmentation is selected, do nothing if (!m_Controls) { return; // might happen on initialization (preferences loaded) } mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::DataNode::Pointer referenceData = toolManager->GetReferenceData(0); mitk::DataNode::Pointer workingData = toolManager->GetWorkingData(0); // 1. if (referenceData.IsNotNull()) { // iterate all images mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_IsASegmentationImagePredicate); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); // set visibility node->SetVisibility(node == referenceData); } } // 2. if (workingData.IsNotNull()) workingData->SetVisibility(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (!node) { return; } mitk::BoolProperty::Pointer drawOutline = mitk::BoolProperty::New(GetPreferences()->GetBool("draw outline", true)); mitk::LabelSetImage* labelSetImage = dynamic_cast(node->GetData()); if (nullptr != labelSetImage) { // node is actually a multi label segmentation, // but its outline property can be set in the 'single label' segmentation preference page as well node->SetProperty("labelset.contour.active", drawOutline); //node->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); // force render window update to show outline node->GetData()->Modified(); } else { // node is a 'single label' segmentation bool isBinary = false; node->GetBoolProperty("binary", isBinary); if (isBinary) { node->SetProperty("outline binary", drawOutline); node->SetProperty("outline width", mitk::FloatProperty::New(2.0)); //node->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); // force render window update to show outline node->GetData()->Modified(); } } } void QmitkSegmentationView::CheckRenderingState() { mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); mitk::DataNode* workingNode = m_Controls->segImageSelector->GetSelectedNode(); if (!workingNode) { this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("Select or create a segmentation")); return; } bool selectedNodeIsVisible = renderWindowPart && workingNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); if (!selectedNodeIsVisible) { this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); return; } /* * Here we check whether the geometry of the selected segmentation image if aligned with the worldgeometry * At the moment it is not supported to use a geometry different from the selected image for reslicing. * For further information see Bug 16063 */ const mitk::BaseGeometry* worldGeo = renderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (workingNode && worldGeo) { const mitk::BaseGeometry* workingNodeGeo = workingNode->GetData()->GetGeometry(); const mitk::BaseGeometry* worldGeo = renderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (mitk::Equal(*workingNodeGeo->GetBoundingBox(), *worldGeo->GetBoundingBox(), mitk::eps, true)) { this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), workingNode); this->SetToolSelectionBoxesEnabled(true); this->UpdateWarningLabel(""); return; } } this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), nullptr); this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); } void QmitkSegmentationView::UpdateWarningLabel(QString text) { if (text.size() == 0) m_Controls->lblSegmentationWarnings->hide(); else m_Controls->lblSegmentationWarnings->show(); m_Controls->lblSegmentationWarnings->setText("" + text + ""); } void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls = new Ui::QmitkSegmentationControls; m_Controls->setupUi(parent); m_Controls->patImageSelector->SetDataStorage(GetDataStorage()); m_Controls->patImageSelector->SetNodePredicate(m_IsAPatientImagePredicate); m_Controls->patImageSelector->SetSelectionIsOptional(false); m_Controls->patImageSelector->SetInvalidInfo("Select an image."); m_Controls->patImageSelector->SetPopUpTitel("Select an image."); m_Controls->patImageSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); UpdateWarningLabel(tr("Please select an image")); if (m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) { UpdateWarningLabel(tr("Select or create a new segmentation")); } m_Controls->segImageSelector->SetDataStorage(GetDataStorage()); m_Controls->segImageSelector->SetNodePredicate(m_IsASegmentationImagePredicate); m_Controls->segImageSelector->SetSelectionIsOptional(false); m_Controls->segImageSelector->SetInvalidInfo("Select a segmentation."); m_Controls->segImageSelector->SetPopUpTitel("Select a segmentation."); m_Controls->segImageSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected."); if (m_Controls->segImageSelector->GetSelectedNode().IsNotNull()) { UpdateWarningLabel(""); } mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(toolManager); toolManager->SetDataStorage(*(GetDataStorage())); toolManager->InitializeTools(); QString segTools2D = tr("Add Subtract Paint Wipe 'Region Growing' Fill Erase 'Live Wire' '2D Fast Marching'"); QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Fast Marching 3D' 'Region Growing 3D' Watershed Picking"); -#if defined(_WIN32) || defined(linux) || defined(__linux__) - segTools3D.append(tr(" nnUNet")); // plugin not enabled for MacOS +#ifndef __APPLE__ + segTools3D.append(" nnUNet"); // plugin not enabled for MacOS #endif std::regex extSegTool2DRegEx("SegTool2D$"); std::regex extSegTool3DRegEx("SegTool3D$"); auto tools = toolManager->GetTools(); for (const auto &tool : tools) { if (std::regex_search(tool->GetNameOfClass(), extSegTool2DRegEx)) { segTools2D.append(QString(" '%1'").arg(tool->GetName())); } else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx)) { segTools3D.append(QString(" '%1'").arg(tool->GetName())); } } // all part of open source MITK m_Controls->m_ManualToolSelectionBox2D->setEnabled(true); m_Controls->m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox2D->SetToolGUIArea(m_Controls->m_ManualToolGUIContainer2D); m_Controls->m_ManualToolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); m_Controls->m_ManualToolSelectionBox2D->SetLayoutColumns(3); m_Controls->m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); connect(m_Controls->m_ManualToolSelectionBox2D, &QmitkToolSelectionBox::ToolSelected, this, &QmitkSegmentationView::OnManualTool2DSelected); //setup 3D Tools m_Controls->m_ManualToolSelectionBox3D->setEnabled(true); m_Controls->m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox3D->SetToolGUIArea(m_Controls->m_ManualToolGUIContainer3D); //specify tools to be added to 3D Tool area m_Controls->m_ManualToolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); m_Controls->m_ManualToolSelectionBox3D->SetLayoutColumns(3); m_Controls->m_ManualToolSelectionBox3D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); // update the list of segmentations toolManager->NewNodeObjectsGenerated += mitk::MessageDelegate1(this, &QmitkSegmentationView::NewNodeObjectsGenerated); // create signal/slot connections connect(m_Controls->patImageSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnPatientSelectionChanged); connect(m_Controls->segImageSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnSegmentationSelectionChanged); connect(m_Controls->btnNewSegmentation, &QToolButton::clicked, this, &QmitkSegmentationView::CreateNewSegmentation); connect(m_Controls->tabWidgetSegmentationTools, &QTabWidget::currentChanged, this, &QmitkSegmentationView::OnTabWidgetChanged); connect(m_Controls->m_SlicesInterpolator, &QmitkSlicesInterpolator::SignalShowMarkerNodes, this, &QmitkSegmentationView::OnShowMarkerNodes); // set callback function for already existing nodes (images & segmentations) mitk::DataStorage::SetOfObjects::ConstPointer allImages = GetDataStorage()->GetSubset(m_IsOfTypeImagePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnVisiblePropertyChanged); m_WorkingDataObserverTags.insert(std::pair(node, node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); } itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::CheckRenderingState); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), m_Controls->segImageSelector->GetSelectedNode()); m_RenderWindowPart = this->GetRenderWindowPart(); if (nullptr != m_RenderWindowPart) this->RenderWindowPartActivated(m_RenderWindowPart); //Should be done last, if everything else is configured because it triggers the autoselection of data. m_Controls->patImageSelector->SetAutoSelectNewNodes(true); m_Controls->segImageSelector->SetAutoSelectNewNodes(true); } void QmitkSegmentationView::SetFocus() { m_Controls->btnNewSegmentation->setFocus(); } void QmitkSegmentationView::OnManualTool2DSelected(int id) { if (id >= 0) { std::string text = "Active Tool: \""; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); text += toolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = toolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } else { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); } } void QmitkSegmentationView::ResetMouseCursor() { if ( m_MouseCursorSet ) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkSegmentationView::SetMouseCursor( const us::ModuleResource& resource, int hotspotX, int hotspotY ) { // Remove previously set mouse cursor if (m_MouseCursorSet) this->ResetMouseCursor(); if (resource) { us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } } void QmitkSegmentationView::SetToolSelectionBoxesEnabled(bool status) { if (status) { m_Controls->m_ManualToolSelectionBox2D->RecreateButtons(); m_Controls->m_ManualToolSelectionBox3D->RecreateButtons(); } m_Controls->m_ManualToolSelectionBox2D->setEnabled(status); m_Controls->m_ManualToolSelectionBox3D->setEnabled(status); m_Controls->m_SlicesInterpolator->setEnabled(status); }