diff --git a/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp index e6c5ca2c3c..724437c145 100644 --- a/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp +++ b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.cpp @@ -1,199 +1,255 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkTotalSegmentatorTool.h" #include "mitkIOUtil.h" #include +#include // us #include #include #include #include #include namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, TotalSegmentatorTool, "Total Segmentator"); } -mitk::TotalSegmentatorTool::TotalSegmentatorTool() -{ - this->SetMitkTempDir(IOUtil::CreateTemporaryDirectory("mitk-XXXXXX")); -} - mitk::TotalSegmentatorTool::~TotalSegmentatorTool() { itksys::SystemTools::RemoveADirectory(this->GetMitkTempDir()); } void mitk::TotalSegmentatorTool::Activated() { Superclass::Activated(); this->SetLabelTransferMode(LabelTransferMode::AllLabels); } const char **mitk::TotalSegmentatorTool::GetXPM() const { return nullptr; } us::ModuleResource mitk::TotalSegmentatorTool::GetIconResource() const { us::Module *module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("AI.svg"); return resource; } const char *mitk::TotalSegmentatorTool::GetName() const { return "Total Segmentator"; } namespace { void onPythonProcessEvent(itk::Object * /*pCaller*/, const itk::EventObject &e, void *) { std::string testCOUT; std::string testCERR; const auto *pEvent = dynamic_cast(&e); if (pEvent) { testCOUT = testCOUT + pEvent->GetOutput(); MITK_INFO << testCOUT; } const auto *pErrEvent = dynamic_cast(&e); if (pErrEvent) { testCERR = testCERR + pErrEvent->GetOutput(); MITK_ERROR << testCERR; } } } // namespace void mitk::TotalSegmentatorTool::DoUpdatePreview(const Image *inputAtTimeStep, const Image * /*oldSegAtTimeStep*/, LabelSetImage *previewImage, TimeStepType timeStep) { - std::string inDir, outDir, inputImagePath, outputImagePath, scriptPath; + if (!m_IsMitkTempDirAvailable) // create temp directory if not done already + { + this->SetMitkTempDir(IOUtil::CreateTemporaryDirectory("mitk-XXXXXX")); + m_IsMitkTempDirAvailable = true; + } + this->ParseLabelNames(this->GetLabelMapPath()); ProcessExecutor::Pointer spExec = ProcessExecutor::New(); itk::CStyleCommand::Pointer spCommand = itk::CStyleCommand::New(); spCommand->SetCallback(&onPythonProcessEvent); spExec->AddObserver(ExternalProcessOutputEvent(), spCommand); - + + std::string inDir, outDir, inputImagePath, outputImagePath, scriptPath; inDir = IOUtil::CreateTemporaryDirectory("totalseg-in-XXXXXX", this->GetMitkTempDir()); std::ofstream tmpStream; inputImagePath = IOUtil::CreateTemporaryFile(tmpStream, m_TEMPLATE_FILENAME, inDir + IOUtil::GetDirectorySeparator()); tmpStream.close(); std::size_t found = inputImagePath.find_last_of(IOUtil::GetDirectorySeparator()); std::string fileName = inputImagePath.substr(found + 1); std::string token = fileName.substr(0, fileName.find("_")); outDir = IOUtil::CreateTemporaryDirectory("totalseg-out-XXXXXX", this->GetMitkTempDir()); outputImagePath = outDir + IOUtil::GetDirectorySeparator() + token + "_000.nii.gz"; ProcessExecutor::ArgumentListType args; IOUtil::Save(inputAtTimeStep, inputImagePath); std::string *outArg = &outputImagePath; bool isSubTask = false; if (this->GetSubTask() != m_DEFAULT_TOTAL_TASK) { isSubTask = true; outputImagePath = outDir + IOUtil::GetDirectorySeparator() + this->GetSubTask() + ".nii.gz"; outArg = &outDir; } this->run_totalsegmentator( - spExec, inputImagePath, *outArg, this->GetFast(), !isSubTask, this->GetGpuId(), m_DEFAULT_TOTAL_TASK); + spExec, inputImagePath, *outArg, this->GetFast(), !isSubTask, this->GetGpuId(), m_DEFAULT_TOTAL_TASK); if (isSubTask) { this->run_totalsegmentator( spExec, inputImagePath, *outArg, !isSubTask, !isSubTask, this->GetGpuId(), this->GetSubTask()); } Image::Pointer outputImage = IOUtil::Load(outputImagePath); auto outputBuffer = mitk::LabelSetImage::New(); outputBuffer->InitializeByLabeledImage(outputImage); outputBuffer->SetGeometry(inputAtTimeStep->GetGeometry()); - + MapLabelsToSegmentation(outputBuffer, m_LabelMapTotal); TransferLabelSetImageContent(outputBuffer, previewImage, timeStep); } void mitk::TotalSegmentatorTool::run_totalsegmentator(ProcessExecutor::Pointer spExec, const std::string &inputImagePath, const std::string &outputImagePath, bool isFast, bool isMultiLabel, unsigned int gpuId, const std::string &subTask) { ProcessExecutor::ArgumentListType args; std::string command = "TotalSegmentator"; #ifdef _WIN32 command = "python"; #else command = "TotalSegmentator"; #endif args.clear(); #ifdef _WIN32 args.push_back("TotalSegmentator"); #endif args.push_back("-i"); args.push_back(inputImagePath); args.push_back("-o"); args.push_back(outputImagePath); if (subTask != m_DEFAULT_TOTAL_TASK) { args.push_back("-ta"); args.push_back(subTask); } if (isMultiLabel) { args.push_back("--ml"); } if (isFast) { args.push_back("--fast"); } try { std::string cudaEnv = "CUDA_VISIBLE_DEVICES=" + std::to_string(gpuId); itksys::SystemTools::PutEnv(cudaEnv.c_str()); for (auto &arg : args) MITK_INFO << arg; MITK_INFO << this->GetPythonPath(); spExec->Execute(this->GetPythonPath(), command, args); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); return; } } + +void mitk::TotalSegmentatorTool::ParseLabelNames(const std::string &fileName) +{ + std::fstream newfile; + newfile.open(fileName, ios::in); + std::stringstream buffer; + if (newfile.is_open()) + { + int line = 0; + std::string temp; + while (std::getline(newfile, temp)) + { + if (line > 1 && line < 106) + { + buffer << temp; + } + ++line; + } + } + std::string key, val; + while (std::getline(std::getline(buffer, key, ':'), val, ',')) + { + m_LabelMapTotal[std::stoi(key)] = val; + } +} + +void mitk::TotalSegmentatorTool::MapLabelsToSegmentation(mitk::LabelSetImage::Pointer outputBuffer, + std::map &labelMap) +{ + for (auto const &[key, val] : labelMap) + { + mitk::Label *labelptr = outputBuffer->GetLabel(key, 0); + if (nullptr != labelptr) + { + MITK_INFO << "Replacing label with name: " << labelptr->GetName() << " as " << val; + labelptr->SetName(val); + } + else + { + MITK_INFO << "nullptr found for " << val; + } + } +} + +std::string mitk::TotalSegmentatorTool::GetLabelMapPath() +{ + std::string pythonFileName; + std::filesystem::path pathToLabelMap(this->GetPythonPath()); +#ifdef _WIN32 + pathToLabelMap = pathToLabelMap.parent_path(); + pythonFileName = pathToLabelMap.string() + "/Lib/site-packages/totalsegmentator/map_to_binary.py"; +#endif + return pythonFileName; +} diff --git a/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.h b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.h index aae1dc304c..56b73a040d 100644 --- a/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.h +++ b/Modules/Segmentation/Interactions/mitkTotalSegmentatorTool.h @@ -1,87 +1,96 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKTOTALSEGMENTATORTOOL_H #define MITKTOTALSEGMENTATORTOOL_H #include "mitkSegWithPreviewTool.h" #include #include "mitkProcessExecutor.h" namespace us { class ModuleResource; } namespace mitk { class MITKSEGMENTATION_EXPORT TotalSegmentatorTool : public SegWithPreviewTool { public: mitkClassMacro(TotalSegmentatorTool, SegWithPreviewTool); itkFactorylessNewMacro(Self); itkCloneMacro(Self); const char *GetName() const override; const char **GetXPM() const override; us::ModuleResource GetIconResource() const override; void Activated() override; itkSetMacro(MitkTempDir, std::string); itkGetConstMacro(MitkTempDir, std::string); itkSetMacro(SubTask, std::string); itkGetConstMacro(SubTask, std::string); itkSetMacro(PythonPath, std::string); itkGetConstMacro(PythonPath, std::string); itkSetMacro(GpuId, unsigned int); itkGetConstMacro(GpuId, unsigned int); itkSetMacro(Fast, bool); itkGetConstMacro(Fast, bool); itkBooleanMacro(Fast); + itkSetMacro(IsMitkTempDirAvailable, bool); + itkGetConstMacro(IsMitkTempDirAvailable, bool); + itkBooleanMacro(IsMitkTempDirAvailable); + protected: - TotalSegmentatorTool(); + TotalSegmentatorTool() = default; ~TotalSegmentatorTool(); /** * @brief Overriden method from the tool manager to execute the segmentation * Implementation: * 1. Saves the inputAtTimeStep in a temporary directory. * 3. Sets CUDA_VISIBLE_DEVICES variables in the environment. * 3. Executes "TotalSegmentator" command with the parameters * 4. Expects an output image to be saved in the temporary directory by the python proces. Loads it as * LabelSetImage and sets to previewImage. * * @param inputAtTimeStep * @param oldSegAtTimeStep * @param previewImage * @param timeStep */ void DoUpdatePreview(const Image* inputAtTimeStep, const Image* oldSegAtTimeStep, LabelSetImage* previewImage, TimeStepType timeStep) override; private: void run_totalsegmentator(ProcessExecutor::Pointer,const std::string &, const std::string &, bool, bool, unsigned int, const std::string &); + void MapLabelsToSegmentation(mitk::LabelSetImage::Pointer, std::map&); + void ParseLabelNames(const std::string &); + std::string GetLabelMapPath(); std::string m_MitkTempDir; std::string m_PythonPath; std::string m_SubTask = "total"; unsigned int m_GpuId; + std::map m_LabelMapTotal; bool m_Fast; + bool m_IsMitkTempDirAvailable = false; const std::string m_TEMPLATE_FILENAME = "XXXXXX_000_0000.nii.gz"; const std::string m_DEFAULT_TOTAL_TASK = "total"; }; // class } // namespace #endif