diff --git a/Modules/DiffusionImaging/DiffusionCore/CMakeLists.txt b/Modules/DiffusionImaging/DiffusionCore/CMakeLists.txt index c97e48209b..1b9cedf87a 100644 --- a/Modules/DiffusionImaging/DiffusionCore/CMakeLists.txt +++ b/Modules/DiffusionImaging/DiffusionCore/CMakeLists.txt @@ -1,22 +1,26 @@ # With apple gcc 4.2.1 the following waring leads to an build error if boost is enabled if(APPLE) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=empty-body" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) endif() MITK_CREATE_MODULE( SUBPROJECTS MITK-DTI INCLUDE_DIRS include/ include/Algorithms include/Algorithms/Reconstruction include/Algorithms/Registration include/Algorithms/Reconstruction/MultishellProcessing include/Algorithms/Reconstruction/FittingFunctions include/DicomImport include/IODataStructures/DiffusionWeightedImages include/IODataStructures/Properties include/IODataStructures/OdfImages include/IODataStructures/TensorImages include/IODataStructures include/Rendering ${CMAKE_CURRENT_BINARY_DIR} DEPENDS MitkMapperExt MitkPlanarFigure MitkImageExtraction MitkSceneSerializationBase MitkDICOMReader MitkMatchPointRegistration PACKAGE_DEPENDS PUBLIC ITK|ITKTestKernel+ITKRegistrationCommon+ITKMetricsv4+ITKRegistrationMethodsv4+ITKDistanceMap+ITKLabelVoting+ITKVTK PUBLIC VTK|vtkFiltersProgrammable ) if(MSVC) mitkFunctionCheckCAndCXXCompilerFlags("/wd4005" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) endif() add_subdirectory(Testing) add_subdirectory(cmdapps) -add_subdirectory(cmdapps_python) add_subdirectory(autoload/IO) + +if(MITK_USE_Python) +MITK_INSTALL(FILES PythonRequirements.txt) +add_subdirectory(cmdapps_python) +endif() diff --git a/Modules/DiffusionImaging/DiffusionCore/PythonRequirements.txt b/Modules/DiffusionImaging/DiffusionCore/PythonRequirements.txt new file mode 100644 index 0000000000..e96d8eff85 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/PythonRequirements.txt @@ -0,0 +1,5 @@ +numpy +SimpleITK +dipy +sklearn +https://github.com/MIC-DKFZ/batchgenerators/archive/master.zip diff --git a/Modules/DiffusionImaging/DiffusionCore/cmdapps_python/BrainExtraction.cpp b/Modules/DiffusionImaging/DiffusionCore/cmdapps_python/BrainExtraction.cpp index d49a587597..3c33c6fe99 100644 --- a/Modules/DiffusionImaging/DiffusionCore/cmdapps_python/BrainExtraction.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/cmdapps_python/BrainExtraction.cpp @@ -1,162 +1,191 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include "mitkCommandLineParser.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include + typedef mitk::DiffusionPropertyHelper DPH; typedef itksys::SystemTools ist; -std::string GetPythonFile(std::string filename) +std::string GetPythonFile(std::string filename, std::string exec_dir) { std::string out = ""; - for (auto dir : mitk::bet::relative_search_dirs) + { + if ( ist::FileExists( exec_dir + dir + filename) ) + { + out = exec_dir + dir + filename; + return out; + } if ( ist::FileExists( ist::GetCurrentWorkingDirectory() + dir + filename) ) { out = ist::GetCurrentWorkingDirectory() + dir + filename; return out; } + } for (auto dir : mitk::bet::absolute_search_dirs) + { if ( ist::FileExists( dir + filename) ) { out = dir + filename; return out; } + } return out; } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("BrainExtraction"); parser.setCategory("Preprocessing Tools"); parser.setDescription("Performs brain extraction using a deep learning model"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "i", mitkCommandLineParser::InputFile, "Input:", "input image", us::Any(), false); parser.addArgument("", "o", mitkCommandLineParser::OutputFile, "Output:", "output root", us::Any(), false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // mandatory arguments std::string i = us::any_cast(parsedArgs["i"]); std::string o = us::any_cast(parsedArgs["o"]); + std::string exec_dir = ist::GetFilenamePath(argv[0]); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images"}, {}); mitk::Image::Pointer mitk_image = mitk::IOUtil::Load(i, &functor); bool missing_file = false; std::string missing_file_string = ""; - if ( GetPythonFile("run_mitk.py").empty() ) + if ( GetPythonFile("run_mitk.py", exec_dir).empty() ) { missing_file_string += "Brain extraction script file missing: run_mitk.py\n\n"; missing_file = true; } - if ( GetPythonFile("model_final.model").empty() ) + if ( GetPythonFile("model_final.model", exec_dir).empty() ) { missing_file_string += "Brain extraction model file missing: model_final.model\n\n"; missing_file = true; } - if ( GetPythonFile("basic_config_just_like_braintumor.py").empty() ) + if ( GetPythonFile("basic_config_just_like_braintumor.py", exec_dir).empty() ) { missing_file_string += "Config file missing: basic_config_just_like_braintumor.py\n\n"; missing_file = true; } if (missing_file) { mitkThrow() << missing_file_string; } us::ModuleContext* context = us::GetModuleContext(); us::ServiceReference m_PythonServiceRef = context->GetServiceReference(); mitk::IPythonService* m_PythonService = dynamic_cast ( context->GetService(m_PythonServiceRef) ); mitk::IPythonService::ForceLoadModule(); // load essential modules m_PythonService->Execute("import SimpleITK as sitk"); m_PythonService->Execute("import SimpleITK._SimpleITK as _SimpleITK"); m_PythonService->Execute("import numpy"); // extend python search path std::string pythonpath = ""; for (auto dir : mitk::bet::relative_search_dirs) pythonpath += "','" + ist::GetCurrentWorkingDirectory() + dir; + for (auto dir : mitk::bet::relative_search_dirs) + pythonpath += "','" + exec_dir + dir; for (auto dir : mitk::bet::absolute_search_dirs) pythonpath += "','" + dir; m_PythonService->Execute("paths=['"+pythonpath+"']"); // set input files (model and config) - m_PythonService->Execute("model_file=\""+GetPythonFile("model_final.model")+"\""); - m_PythonService->Execute("config_file=\""+GetPythonFile("basic_config_just_like_braintumor.py")+"\""); + m_PythonService->Execute("model_file=\""+GetPythonFile("model_final.model", exec_dir)+"\""); + m_PythonService->Execute("config_file=\""+GetPythonFile("basic_config_just_like_braintumor.py", exec_dir)+"\""); // copy input image to python m_PythonService->CopyToPythonAsSimpleItkImage( mitk_image, "in_image"); // run segmentation script - m_PythonService->ExecuteScript( GetPythonFile("run_mitk.py") ); + m_PythonService->ExecuteScript( GetPythonFile("run_mitk.py", exec_dir) ); // clean up after running script (better way than deleting individual variables?) if(m_PythonService->DoesVariableExist("in_image")) m_PythonService->Execute("del in_image"); // check for errors if(!m_PythonService->GetVariable("error_string").empty()) mitkThrow() << m_PythonService->GetVariable("error_string"); - { - mitk::Image::Pointer image = m_PythonService->CopySimpleItkImageFromPython("brain_mask"); - mitk::IOUtil::Save(image, o + "_BrainMask.nii.gz"); - } + // get output images and add to datastorage + std::string output_variables = m_PythonService->GetVariable("output_variables"); + std::vector outputs; + boost::split(outputs, output_variables, boost::is_any_of(",")); - { - mitk::Image::Pointer image = m_PythonService->CopySimpleItkImageFromPython("brain_extracted"); + std::string output_types = m_PythonService->GetVariable("output_types"); + std::vector types; + boost::split(types, output_types, boost::is_any_of(",")); - if(mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(mitk_image)) + for (unsigned int i=0; iDoesVariableExist(outputs.at(i))) { - mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, image, true); - mitk::DiffusionPropertyHelper::InitializeImage(image); - mitk::IOUtil::Save(image, "application/vnd.mitk.nii.gz", o + "_SkullStripped.nii.gz"); + mitk::Image::Pointer image = m_PythonService->CopySimpleItkImageFromPython(outputs.at(i)); + + if(types.at(i)=="input" && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(mitk_image)) + { + mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, image, true); + mitk::DiffusionPropertyHelper::InitializeImage(image); + } + + mitk::DataNode::Pointer corrected_node = mitk::DataNode::New(); + corrected_node->SetData( image ); + std::string name = o + "_"; + name += outputs.at(i); + + if(types.at(i)=="input" && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(mitk_image)) + mitk::IOUtil::Save(image, "application/vnd.mitk.nii.gz", name+".nii.gz"); + else + mitk::IOUtil::Save(image, name+".nii.gz"); } - else - mitk::IOUtil::Save(image, o + "_SkullStripped.nii.gz"); } + MITK_INFO << "Finished brain extraction"; return EXIT_SUCCESS; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/CMakeLists.txt b/Plugins/org.mitk.gui.qt.diffusionimaging.python/CMakeLists.txt index f1bb5a1b28..2099cf1457 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.python/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/CMakeLists.txt @@ -1,23 +1,17 @@ if(MITK_USE_Python) # The project name must correspond to the directory name of your plug-in # and must not contain periods. project(org_mitk_gui_qt_diffusionimaging_python) mitk_create_plugin( EXPORT_DIRECTIVE DIFFUSIONIMAGING_PREPROCESSING_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDS MitkDiffusionCore MitkPython PACKAGE_DEPENDS Qt5|Network BetData ) #set(_install_DESTINATION "BetData") MITK_INSTALL(DIRECTORY ${BetData_DIR}/) -#if(WIN32) -# file(COPY ${BetData_DIR}/ DESTINATION ${CMAKE_BINARY_DIR}/bin/${build_type}/ FILES_MATCHING PATTERN "*") -#else() -# file(COPY ${BetData_DIR}/ DESTINATION ${CMAKE_BINARY_DIR}/bin FILES_MATCHING PATTERN "*") -#endif() - endif() diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.cpp index 7fa78c5d3c..1b53fc2130 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionView.cpp @@ -1,259 +1,262 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk #include "QmitkBrainExtractionView.h" // MITK #include // Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include typedef itksys::SystemTools ist; const std::string QmitkBrainExtractionView::VIEW_ID = "org.mitk.views.brainextraction"; QmitkBrainExtractionView::QmitkBrainExtractionView() : QmitkAbstractView() , m_Controls( 0 ) , m_DiffusionImage( nullptr ) { } // Destructor QmitkBrainExtractionView::~QmitkBrainExtractionView() { } void QmitkBrainExtractionView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkBrainExtractionViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGUI()) ); connect( m_Controls->m_StartButton, SIGNAL(clicked()), this, SLOT(StartBrainExtraction()) ); this->m_Parent = parent; m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); mitk::NodePredicateDimension::Pointer dimPred = mitk::NodePredicateDimension::New(3); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); m_Controls->m_ImageBox->SetPredicate(isImagePredicate); UpdateGUI(); } } void QmitkBrainExtractionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& ) { } void QmitkBrainExtractionView::UpdateGUI() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) m_Controls->m_StartButton->setEnabled(true); else m_Controls->m_StartButton->setEnabled(false); } void QmitkBrainExtractionView::SetFocus() { UpdateGUI(); m_Controls->m_StartButton->setFocus(); } std::string QmitkBrainExtractionView::GetPythonFile(std::string filename) { std::string out = ""; - QString exec_dir = QCoreApplication::applicationDirPath(); + std::string exec_dir = QCoreApplication::applicationDirPath().toStdString(); for (auto dir : mitk::bet::relative_search_dirs) { if ( ist::FileExists( ist::GetCurrentWorkingDirectory() + dir + filename) ) { out = ist::GetCurrentWorkingDirectory() + dir + filename; return out; } - if ( ist::FileExists( exec_dir.toStdString() + dir + filename) ) + if ( ist::FileExists( exec_dir + dir + filename) ) { - out = exec_dir.toStdString() + dir + filename; + out = exec_dir + dir + filename; return out; } } for (auto dir : mitk::bet::absolute_search_dirs) { if ( ist::FileExists( dir + filename) ) { out = dir + filename; return out; } } return out; } void QmitkBrainExtractionView::StartBrainExtraction() { mitk::DataNode::Pointer node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer mitk_image = dynamic_cast(node->GetData()); bool missing_file = false; std::string missing_file_string = ""; if ( GetPythonFile("run_mitk.py").empty() ) { missing_file_string += "Brain extraction script file missing: run_mitk.py\n\n"; missing_file = true; } if ( GetPythonFile("model_final.model").empty() ) { missing_file_string += "Brain extraction model file missing: model_final.model\n\n"; missing_file = true; } if ( GetPythonFile("basic_config_just_like_braintumor.py").empty() ) { missing_file_string += "Config file missing: basic_config_just_like_braintumor.py\n\n"; missing_file = true; } if (missing_file) { QMessageBox::warning(nullptr, "Error", (missing_file_string).c_str(), QMessageBox::Ok); return; } try { us::ModuleContext* context = us::GetModuleContext(); us::ServiceReference m_PythonServiceRef = context->GetServiceReference(); mitk::IPythonService* m_PythonService = dynamic_cast ( context->GetService(m_PythonServiceRef) ); mitk::IPythonService::ForceLoadModule(); // load essential modules m_PythonService->Execute("import SimpleITK as sitk"); m_PythonService->Execute("import SimpleITK._SimpleITK as _SimpleITK"); m_PythonService->Execute("import numpy"); // extend python search path + std::string exec_dir = QCoreApplication::applicationDirPath().toStdString(); std::string pythonpath = ""; for (auto dir : mitk::bet::relative_search_dirs) pythonpath += "','" + ist::GetCurrentWorkingDirectory() + dir; + for (auto dir : mitk::bet::relative_search_dirs) + pythonpath += "','" + exec_dir + dir; for (auto dir : mitk::bet::absolute_search_dirs) pythonpath += "','" + dir; m_PythonService->Execute("paths=['"+pythonpath+"']"); // set input files (model and config) m_PythonService->Execute("model_file=\""+GetPythonFile("model_final.model")+"\""); m_PythonService->Execute("config_file=\""+GetPythonFile("basic_config_just_like_braintumor.py")+"\""); // copy input image to python m_PythonService->CopyToPythonAsSimpleItkImage( mitk_image, "in_image"); // run segmentation script m_PythonService->ExecuteScript( GetPythonFile("run_mitk.py") ); // clean up after running script (better way than deleting individual variables?) if(m_PythonService->DoesVariableExist("in_image")) m_PythonService->Execute("del in_image"); // check for errors if(!m_PythonService->GetVariable("error_string").empty()) { QMessageBox::warning(nullptr, "Error", QString(m_PythonService->GetVariable("error_string").c_str()), QMessageBox::Ok); return; } // get output images and add to datastorage std::string output_variables = m_PythonService->GetVariable("output_variables"); std::vector outputs; boost::split(outputs, output_variables, boost::is_any_of(",")); std::string output_types = m_PythonService->GetVariable("output_types"); std::vector types; boost::split(types, output_types, boost::is_any_of(",")); for (unsigned int i=0; iDoesVariableExist(outputs.at(i))) { mitk::Image::Pointer image = m_PythonService->CopySimpleItkImageFromPython(outputs.at(i)); if(types.at(i)=="input" && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(mitk_image)) { mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, image, true); mitk::DiffusionPropertyHelper::InitializeImage(image); } mitk::DataNode::Pointer corrected_node = mitk::DataNode::New(); corrected_node->SetData( image ); std::string name = node->GetName(); name += "_"; name += outputs.at(i); corrected_node->SetName(name); GetDataStorage()->Add(corrected_node, node); m_PythonService->Execute("del " + outputs.at(i)); mitk::RenderingManager::GetInstance()->InitializeViews( corrected_node->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } } catch(...) { QMessageBox::warning(nullptr, "Error", "File could not be processed.\nIs pytorch installed on your system?\nDoes your script use the correct input and output variable names (in: in_image & model, out: brain_mask & brain_extracted)?", QMessageBox::Ok); } }