diff --git a/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp index 0677b28dbb..c96f615e0c 100644 --- a/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp +++ b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp @@ -1,394 +1,379 @@ /*============================================================================ 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 "DeepLearningSegmentationTool.h" #include #include #include #include #include #include mitk::DeepLearningSegmentationTool::DeepLearningSegmentationTool(std::string toolName, std::string iconName, std::string pythonFolder, std::string inputImageVarName, std::string pythonFileName, std::string outputImageVarName, ImageType imageType, bool multilabel) { m_ToolName = toolName; m_IconName = iconName; m_PythonProjectPath = "Modules/DeepLearningSegmentation/"+pythonFolder; m_InputImageVarName = inputImageVarName; m_PythonFileName = pythonFileName; m_OutputImageVarName = outputImageVarName; m_ImageType = imageType; m_MultilabelSegmentation = multilabel; m_SegmentationRunning = false; } mitk::DeepLearningSegmentationTool::~DeepLearningSegmentationTool() { } us::ModuleResource mitk::DeepLearningSegmentationTool::GetIconResource() const { auto moduleContext = us::GetModuleContext(); auto module = moduleContext->GetModule(); auto resource = module->GetResource(m_IconName); return resource; } const char *mitk::DeepLearningSegmentationTool::GetName() const { return m_ToolName.c_str(); } -//bool mitk::DeepLearningSegmentationTool::CanHandle(mitk::BaseData *referenceData) const -//{ -// if (referenceData == nullptr) -// return false; -// -// auto *image = dynamic_cast(referenceData); -// if (image == nullptr) -// return false; -// -// if (image->GetDimension() != 3) -// return false; -// -// return true; -//} - const char **mitk::DeepLearningSegmentationTool::GetXPM() const { return nullptr; } void mitk::DeepLearningSegmentationTool::Activated() { Superclass::Activated(); } void mitk::DeepLearningSegmentationTool::Deactivated() { Superclass::Deactivated(); } mitk::LabelSetImage::Pointer mitk::DeepLearningSegmentationTool::DoSegmentation(std::string networkPath) { m_SegmentationRunning = true; //get the input Image mitk::Image::Pointer input; try { input = GetInputImage(); } catch(mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow(); } //Get the python microservice mitk::IPythonService::ForceLoadModule(); us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); // set path to the Python code which should be executed try { std::vector pathVector; pathVector.push_back(m_PythonProjectPath); m_PythonService->AddRelativeSearchDirs(pathVector); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error in setting the path to the Python code which should be executed"; m_SegmentationRunning = false; return nullptr; } // set the path to the trained network try { std::string pathCommand = "network_path = '" + networkPath+"'"; m_PythonService->Execute(pathCommand); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error in setting the network path"; m_SegmentationRunning = false; return nullptr; } //set the input image try { if (m_ImageType==DeepLearningSegmentationTool::SimpleITKImage) { m_PythonService->CopyToPythonAsSimpleItkImage(input, m_InputImageVarName); } else if (m_ImageType==DeepLearningSegmentationTool::MITKImage) { m_PythonService->CopyMITKImageToPython(input, m_InputImageVarName); } else { mitkThrow() << "Unknown image type"; } } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error setting the input image"; m_SegmentationRunning = false; return nullptr; } // execute Segmentation try { std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( m_PythonFileName.c_str(), m_PythonProjectPath.c_str()); m_PythonService->ExecuteScript(fileName); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error in executing python code"; m_SegmentationRunning = false; return nullptr; } // get result try { mitk::Image::Pointer outputImage; if (m_ImageType == DeepLearningSegmentationTool::SimpleITKImage) { outputImage = m_PythonService->CopySimpleItkImageFromPython(m_OutputImageVarName); } else if (m_ImageType == DeepLearningSegmentationTool::MITKImage) { outputImage = m_PythonService->CopyMITKImageFromPython(m_OutputImageVarName); } else { mitkThrow() << "Unknown image type"; } mitk::LabelSetImage::Pointer resultImage = mitk::LabelSetImage::New(); resultImage->InitializeByLabeledImage(outputImage); resultImage->SetGeometry(input->GetGeometry()); m_SegmentationRunning = false; outputImage->SetGeometry(input->GetGeometry()); return resultImage; } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error in getting the result"; m_SegmentationRunning = false; return nullptr; } } else { mitkThrow() << "No service reference found"; } m_SegmentationRunning = false; return nullptr; } std::vector mitk::DeepLearningSegmentationTool::DoMultilabelSegmentation(std::string networkPath) { std::vector result; m_SegmentationRunning = true; // get the input Image mitk::Image::Pointer input; try { input = GetInputImage(); } catch (mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow(); } // Get the python microservice mitk::IPythonService::ForceLoadModule(); us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); // set path to the Python code which should be executed try { std::vector pathVector; pathVector.push_back(m_PythonProjectPath); m_PythonService->AddRelativeSearchDirs(pathVector); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error in setting the path to the Python code which should be executed"; m_SegmentationRunning = false; return result; } // set the path to the trained network try { std::string pathCommand = "network_path = '" + networkPath + "'"; m_PythonService->Execute(pathCommand); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error in setting the network path"; m_SegmentationRunning = false; return result; } // set the input image try { if (m_ImageType == DeepLearningSegmentationTool::SimpleITKImage) { m_PythonService->CopyToPythonAsSimpleItkImage(input, m_InputImageVarName); } else if (m_ImageType == DeepLearningSegmentationTool::MITKImage) { m_PythonService->CopyMITKImageToPython(input, m_InputImageVarName); } else { mitkThrow() << "Unknown image type"; } } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error setting the input image"; m_SegmentationRunning = false; return result; } // execute Segmentation try { std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile(m_PythonFileName.c_str(), m_PythonProjectPath.c_str()); m_PythonService->ExecuteScript(fileName); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error in executing python code"; m_SegmentationRunning = false; return result; } // get result try { std::vector outputImages; //if (m_ImageType == DeepLearningSegmentationTool::SimpleITKImage) //{ // outputImage = m_PythonService->CopySimpleItkImageFromPython(m_OutputImageVarName); //} if (m_ImageType == DeepLearningSegmentationTool::MITKImage) { outputImages = m_PythonService->CopyListOfMITKImagesFromPython(m_OutputImageVarName); } else { mitkThrow() << "Unknown image type"; } for (mitk::Image::Pointer image : outputImages) { mitk::LabelSetImage::Pointer resultImage = mitk::LabelSetImage::New(); resultImage->InitializeByLabeledImage(image); resultImage->SetGeometry(input->GetGeometry()); m_SegmentationRunning = false; resultImage->SetGeometry(input->GetGeometry()); result.push_back(resultImage); } return result; } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); mitkThrow() << "Error in getting the result"; m_SegmentationRunning = false; return result; } } else { mitkThrow() << "No service reference found"; } m_SegmentationRunning = false; return result; } mitk::DataStorage *mitk::DeepLearningSegmentationTool::GetDataStorage() { return m_ToolManager->GetDataStorage(); m_ToolManager->GetReferenceData(0); } mitk::DataNode *mitk::DeepLearningSegmentationTool::GetReferenceData() { return m_ToolManager->GetReferenceData(0); } mitk::Image::Pointer mitk::DeepLearningSegmentationTool::GetInputImage() { mitk::DataNode::Pointer referenceData = m_ToolManager->GetReferenceData(0); mitk::Image::Pointer input = dynamic_cast(referenceData->GetData()); if (input.IsNull()) { mitkThrow(); } //unsigned int timestep = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime()->GetPos(); //mitk::Image::ConstPointer input = Get3DImage(input, timestep); if (input.IsNull()) { mitkThrow(); } return input; } bool mitk::DeepLearningSegmentationTool::IsSegmentationRunning() { return m_SegmentationRunning; } bool mitk::DeepLearningSegmentationTool::IsMultilabelSegmentation() { return m_MultilabelSegmentation; } diff --git a/Modules/Python/test/mitkPythonTest.cpp b/Modules/Python/test/mitkPythonTest.cpp index 924f700786..516d0a40aa 100644 --- a/Modules/Python/test/mitkPythonTest.cpp +++ b/Modules/Python/test/mitkPythonTest.cpp @@ -1,580 +1,581 @@ /*============================================================================ 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 #include #include #include #include #include #include #include #include class mitkPythonTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPythonTestSuite); MITK_TEST(TestEvaluateOperationWithResult); MITK_TEST(TestExecuteStatement); MITK_TEST(TestSettingVariable); MITK_TEST(TestSettingVariableAndUseIt); MITK_TEST(TestRunningScript); MITK_TEST(TestRunningScriptCallOtherScript); MITK_TEST(TestRunningScriptCallOtherScriptInSubfolder); MITK_TEST(TestGetVariableStack); MITK_TEST(TestGetVariable); MITK_TEST(TestDoesVariableExist_True); MITK_TEST(TestDoesVariableExist_False); MITK_TEST(TestAddObserver); MITK_TEST(TestRemoveObserver); MITK_TEST(TestNotifyObserver); MITK_TEST(TestCopyImageSimpleITK); MITK_TEST(TestCopyImageMITK); CPPUNIT_TEST_SUITE_END(); public: void setUp() { mitk::IPythonService::ForceLoadModule(); } void TestEvaluateOperationWithResult() { std::string result = ""; us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); result = m_PythonService->Execute("5+5", mitk::IPythonService::EVAL_COMMAND); try { std::string result = m_PythonService->Execute("5+5", mitk::IPythonService::EVAL_COMMAND); CPPUNIT_ASSERT_MESSAGE("Testing if running python code 5+5 results in 10", result == "10"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in Python Execution"); } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestExecuteStatement() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { std::string result = m_PythonService->Execute("print('Hello')"); //std::string result = "None"; CPPUNIT_ASSERT_MESSAGE("Testing if executing a statement works", result == "None"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in Python Execution"); } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestSettingVariable() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { std::string result = m_PythonService->Execute("number = 5"); CPPUNIT_ASSERT_MESSAGE("Testing if initializing a variable works", result == "None"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in Python Execution"); } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestSettingVariableAndUseIt() { std::string result = ""; us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { result = m_PythonService->Execute("number = 5"); result = m_PythonService->Execute("number+5", mitk::IPythonService::EVAL_COMMAND); CPPUNIT_ASSERT_MESSAGE("Testing if initializing a variable and using it works", result == "10"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in Python Execution"); } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestRunningScript() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { std::string pythonFileName = "hello.py"; std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( pythonFileName.c_str(), "Modules/Python/test/hello_world_project"); m_PythonService->ExecuteScript(fileName); } catch(const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in Python Execution for Script"); return; } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestRunningScriptCallOtherScript() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { try { std::string path = "Modules/Python/test/hello_world_project"; std::vector pathVector; pathVector.push_back(path); m_PythonService->AddRelativeSearchDirs(pathVector); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in setting the search directory"); return; } std::string pythonFileName = "call_hello.py"; std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( pythonFileName.c_str(), "Modules/Python/test/hello_world_project"); m_PythonService->ExecuteScript(fileName); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in Python Execution for Script"); return; } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestRunningScriptCallOtherScriptInSubfolder() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { try { std::string path = "Modules/Python/test/hello_world_project"; std::vector pathVector; pathVector.push_back(path); m_PythonService->AddRelativeSearchDirs(pathVector); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in setting the search directory"); return; } std::string pythonFileName = "call_hello_in_subfolder.py"; std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( pythonFileName.c_str(), "Modules/Python/test/hello_world_project"); m_PythonService->ExecuteScript(fileName); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in Python Execution for Script"); return; } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestGetVariableStack() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { auto list = m_PythonService->GetVariableStack(); if (!(list.size() > 0)) { CPPUNIT_FAIL("Failed to get variable stack"); } //for (mitk::PythonVariable var : list) //{ // MITK_INFO << var.m_Name << ", " << var.m_Value << ", " << var.m_Type; //} } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in getting variable stack"); return; } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestGetVariable() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { m_PythonService->Execute("variable_to_get ='Get this variable'"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in setting the variable"); return; } try { std::string variableToGet = m_PythonService->GetVariable("variable_to_get"); CPPUNIT_ASSERT_MESSAGE("Testing if getting a variable as string representation works", variableToGet == "'Get this variable'"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in getting a variable as string representation"); return; } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestDoesVariableExist_True() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { m_PythonService->Execute("existingVariable ='This variable exists'"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in setting the variable"); return; } try { bool variableExists = m_PythonService->DoesVariableExist("existingVariable"); CPPUNIT_ASSERT_MESSAGE("Testing if an existing variable is recognized", variableExists == true); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in checking if a variable exists"); return; } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestDoesVariableExist_False() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); try { bool variableExists = m_PythonService->DoesVariableExist("nonExistingVariable"); CPPUNIT_ASSERT_MESSAGE("Testing if an not existing variable is not recognized", variableExists == false); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in checking if a variable exists"); return; } } else { CPPUNIT_FAIL("No Service Reference found"); } } void TestAddObserver() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); int numberBeforeAdding = m_PythonService->GetNumberOfObserver(); auto observer = new PythonObserverMock; m_PythonService->AddPythonCommandObserver(observer); int numberAfterAdding = m_PythonService->GetNumberOfObserver(); CPPUNIT_ASSERT_MESSAGE("Testing if a new command observer can be added", numberAfterAdding == numberBeforeAdding+1); } } void TestRemoveObserver() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); int numberBeforeAdding = m_PythonService->GetNumberOfObserver(); auto observer = new PythonObserverMock; m_PythonService->AddPythonCommandObserver(observer); int numberAfterAdding = m_PythonService->GetNumberOfObserver(); CPPUNIT_ASSERT_MESSAGE("Testing if a new command observer can be added", numberAfterAdding == numberBeforeAdding + 1); m_PythonService->RemovePythonCommandObserver(observer); int numberAfterRemoving = m_PythonService->GetNumberOfObserver(); CPPUNIT_ASSERT_MESSAGE("Testing if a command observer can be removed", numberAfterRemoving == numberBeforeAdding); } } void TestNotifyObserver() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); auto observer = new PythonObserverMock; m_PythonService->AddPythonCommandObserver(observer); std::string command = "number = 5"; try { m_PythonService->Execute(command); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in Python Execution"); } CPPUNIT_ASSERT_MESSAGE("Testing if a command observer is notified", observer->m_Updated == true); } } void TestCopyImageSimpleITK() { us::ModuleContext *context = us::GetModuleContext(); std::string filter = "(Name=PythonService)"; auto m_PythonServiceRefs = context->GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); mitk::Image::Pointer image_in = mitk::IOUtil::Load(GetTestDataFilePath("Pic3D.nrrd")); mitk::Image::Pointer image_out; try { m_PythonService->CopyToPythonAsSimpleItkImage(image_in, "image"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in copying Image to Python"); } try { image_out = m_PythonService->CopySimpleItkImageFromPython("image"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in copying Image to Python"); } - MITK_INFO << "Equal: " <GetServiceReferences(filter); if (!m_PythonServiceRefs.empty()) { mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); mitk::Image::Pointer image_in = mitk::IOUtil::Load(GetTestDataFilePath("Pic3D.nrrd")); mitk::Image::Pointer image_out; try { m_PythonService->CopyMITKImageToPython(image_in, "mitkimage"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in copying Image to Python"); } try { image_out = m_PythonService->CopyMITKImageFromPython(/*image_in,*/"mitkimage"); } catch (const mitk::Exception &e) { MITK_ERROR << e.GetDescription(); CPPUNIT_FAIL("Error in copying Image to Python"); } if (image_out ==nullptr) { MITK_INFO << "ups"; } CPPUNIT_ASSERT_MESSAGE("copy an image to python and back should result in equal image", mitk::Equal(*image_in, *image_out, mitk::eps, true)); } } }; MITK_TEST_SUITE_REGISTRATION(mitkPython) diff --git a/Modules/PythonService/mitkPythonService.cpp b/Modules/PythonService/mitkPythonService.cpp index fcbb641068..07880a9c3f 100644 --- a/Modules/PythonService/mitkPythonService.cpp +++ b/Modules/PythonService/mitkPythonService.cpp @@ -1,594 +1,616 @@ /*============================================================================ 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 "mitkPythonService.h" //#include #include //#include //#include #ifdef _DEBUG #undef _DEBUG #include #define _DEBUG #else #include #endif //#ifdef _MSC_VER //# pragma warning(push) //# pragma warning(disable: 5208) //#endif //#include //#ifdef _MSC_VER //# pragma warning(pop) //#endif #include "PythonPath.h" #include #include #include #include //#include //#include #include #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include #include #ifndef WIN32 #include #endif #include"swigpyrun.h" typedef itksys::SystemTools ist; mitk::PythonService::PythonService() : m_ItkWrappingAvailable(true), m_OpenCVWrappingAvailable(false), m_VtkWrappingAvailable(false), m_ErrorOccured(false) { if (!Py_IsInitialized()) { Py_Initialize(); } PyGILState_STATE gState = PyGILState_Ensure(); std::string programPath = mitk::IOUtil::GetProgramPath(); std::replace(programPath.begin(), programPath.end(), '\\', '/'); programPath.append("/"); MITK_INFO << programPath; std::string pythonCommand; pythonCommand.append("import SimpleITK as sitk\n"); pythonCommand.append("import SimpleITK._SimpleITK as _SimpleITK\n"); pythonCommand.append("import numpy\n"); pythonCommand.append("import site, sys\n"); pythonCommand.append("sys.path.append('')\n"); pythonCommand.append("sys.path.append('" + programPath + "')\n"); pythonCommand.append("sys.path.append('" + std::string(SWIG_MITK_WRAPPING) + "')\n"); pythonCommand.append("sys.path.append('" +std::string(EXTERNAL_DIST_PACKAGES) + "')\n"); pythonCommand.append("\nsite.addsitedir('"+std::string(EXTERNAL_SITE_PACKAGES)+"')"); if (PyRun_SimpleString(pythonCommand.c_str()) == -1) { MITK_ERROR << "Something went wrong in setting the path in Python"; } PyObject *main = PyImport_AddModule("__main__"); m_GlobalDictionary = PyModule_GetDict(main); m_LocalDictionary = m_GlobalDictionary; m_ThreadState = PyEval_SaveThread(); } mitk::PythonService::~PythonService() { - //if (Py_IsInitialized()) - //{ - // PyGILState_Ensure(); - // Py_FinalizeEx(); - //} } void mitk::PythonService::AddRelativeSearchDirs(std::vector< std::string > dirs) { for (auto dir : dirs) { try { std::string path = std::string(MITK_ROOT) + dir; std::string pythonCommand = "import sys\nsys.path.append('" + path + "')\n"; this->Execute(pythonCommand.c_str()); } catch (const mitk::Exception) { mitkThrow() << "An error occured setting the relative project path"; } } } void mitk::PythonService::AddAbsoluteSearchDirs(std::vector< std::string > dirs) { for (auto dir : dirs) { try { std::string pythonCommand = "import sys\nsys.path.append('" + dir + "')\n"; this->Execute(pythonCommand.c_str()); } catch (const mitk::Exception) { mitkThrow() << "An error occured setting the absolute project path"; } } } std::string mitk::PythonService::Execute(const std::string &stdpythonCommand, int commandType) { if (!Py_IsInitialized()) { Py_Initialize(); } std::string result = ""; PyGILState_STATE gState = PyGILState_Ensure(); try { switch (commandType) { case IPythonService::SINGLE_LINE_COMMAND: commandType = Py_single_input; break; case IPythonService::MULTI_LINE_COMMAND: commandType = Py_file_input; break; case IPythonService::EVAL_COMMAND: commandType = Py_eval_input; break; default: commandType = Py_file_input; } PyObject* executionResult = PyRun_String(stdpythonCommand.c_str(), commandType, m_GlobalDictionary, m_LocalDictionary); this->NotifyObserver(stdpythonCommand); if (executionResult) { PyObject *objectsRepresentation = PyObject_Repr(executionResult); const char *resultChar = PyUnicode_AsUTF8(objectsRepresentation); result = std::string(resultChar); m_ThreadState = PyEval_SaveThread(); m_ErrorOccured = false; } else { m_ErrorOccured = true; mitkThrow() << "An error occured while running the Python code"; } } catch (const mitk::Exception) { PyErr_Print(); m_ThreadState = PyEval_SaveThread(); throw; } return result; } void mitk::PythonService::ExecuteScript(const std::string &pythonScript) { std::ifstream t(pythonScript.c_str()); std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); t.close(); try { this->Execute(str.c_str(), MULTI_LINE_COMMAND); } catch (const mitk::Exception) { throw; } } std::vector mitk::PythonService::GetVariableStack() { std::vector list; PyGILState_STATE gState = PyGILState_Ensure(); try { PyObject *dict = PyImport_GetModuleDict(); PyObject *object = PyDict_GetItemString(dict, "__main__"); if (!object) { mitkThrow() << "An error occured getting the Dictionary"; } PyObject *dirMain = PyObject_Dir(object); PyObject *tempObject = nullptr; if (dirMain) { std::string name, attrValue, attrType; for (int i = 0; i < PyList_Size(dirMain); i++) { tempObject = PyList_GetItem(dirMain, i); if (!tempObject) { mitkThrow() << "An error occured getting an item from the dictionary"; } PyObject *objectsRepresentation = PyObject_Repr(tempObject); const char *objectChar = PyUnicode_AsUTF8(objectsRepresentation); std::string name = std::string(objectChar); name = name.substr(1, name.size() - 2); tempObject = PyObject_GetAttrString(object, name.c_str()); if (!tempObject) { mitkThrow() << "Could not get the attribute to determine type"; } attrType = tempObject->ob_type->tp_name; PyObject *valueStringRepresentation = PyObject_Repr(tempObject); const char *valueChar = PyUnicode_AsUTF8(valueStringRepresentation); std::string attrValue = std::string(valueChar); mitk::PythonVariable var; var.m_Name = name; var.m_Value = attrValue; var.m_Type = attrType; list.push_back(var); } } m_ThreadState = PyEval_SaveThread(); } catch (const mitk::Exception) { m_ThreadState = PyEval_SaveThread(); throw; } return list; } std::string mitk::PythonService::GetVariable(const std::string& name) { std::vector allVars; try { allVars = this->GetVariableStack(); } catch (const mitk::Exception) { mitkThrow() << "Error getting the variable stack"; } for (unsigned int i = 0; i < allVars.size(); i++) { if (allVars.at(i).m_Name == name) return allVars.at(i).m_Value; } return ""; } bool mitk::PythonService::DoesVariableExist(const std::string& name) { bool varExists = false; std::vector allVars; try { allVars = this->GetVariableStack(); } catch (const mitk::Exception) { mitkThrow() << "Error getting the variable stack"; } for (unsigned int i = 0; i < allVars.size(); i++) { if (allVars.at(i).m_Name == name) { varExists = true; break; } } return varExists; } void mitk::PythonService::AddPythonCommandObserver(mitk::PythonCommandObserver *observer) { //only add observer if it isn't already in list of observers if (!(std::find(m_Observer.begin(), m_Observer.end(), observer) != m_Observer.end())) { m_Observer.push_back(observer); } } void mitk::PythonService::RemovePythonCommandObserver(mitk::PythonCommandObserver *observer) { for (std::vector::iterator iter = m_Observer.begin(); iter != m_Observer.end(); ++iter) { if (*iter == observer) { m_Observer.erase(iter); break; } } } void mitk::PythonService::NotifyObserver(const std::string &command) { for (int i = 0; i < m_Observer.size(); ++i) { m_Observer.at(i)->CommandExecuted(command); } } int mitk::PythonService::GetNumberOfObserver() { return m_Observer.size(); } bool mitk::PythonService::IsSimpleItkPythonWrappingAvailable() { return m_ItkWrappingAvailable; } bool mitk::PythonService::CopyToPythonAsSimpleItkImage(mitk::Image::Pointer image, const std::string &stdvarName) { std::string transferToPython = "import pyMITK\n" "import SimpleITK as sitk\n" "mitk_image = None\n" "geometry = None\n" +stdvarName+" = None\n" "\n" "def setup(image_from_cxx):\n" " print ('setup called with', image_from_cxx)\n" " global mitk_image\n" " mitk_image = image_from_cxx\n" "\n" - "def convert_to_sitk():\n" + "def convert_to_sitk(spacing, origin):\n" " np = pyMITK.GetArrayViewFromImage(mitk_image)\n" " global "+stdvarName+"\n" - " "+stdvarName+" = sitk.GetImageFromArray(np)\n"; + " "+stdvarName+" = sitk.GetImageFromArray(np)\n" + " npSpacingArray = numpy.array(spacing , dtype=float)\n" + " "+stdvarName+".SetSpacing(npSpacingArray)\n" + " npOriginArray = numpy.array(origin , dtype=float)\n" + " " +stdvarName +".SetOrigin(npOriginArray)\n"; this->Execute(transferToPython); mitk::Image::Pointer *img = ℑ PyGILState_STATE gState = PyGILState_Ensure(); + //necessary for transfer array from C++ to Python + import_array(); PyObject *main = PyImport_ImportModule("__main__"); if (main == NULL) { mitkThrow() << "Something went wrong getting the main module"; } swig_type_info *pTypeInfo = nullptr; pTypeInfo = SWIG_TypeQuery("_p_itk__SmartPointerT_mitk__Image_t"); int owned = 0; PyObject *pInstance = SWIG_NewPointerObj(reinterpret_cast(img), pTypeInfo, owned); if (pInstance == NULL) { mitkThrow() << "Something went wrong creating the Python instance of the image"; } + //transfer correct image spacing to Python + int spacing[3]; + image->GetGeometry()->GetSpacing().ToArray(spacing); + int nd = 1; + npy_intp dims[] = {3}; + PyObject *spacingArray = PyArray_SimpleNewFromData(1, dims, NPY_INT, (void *)spacing); + + //transfer correct image origin to Python + int origin[3]; + image->GetGeometry()->GetOrigin().ToArray(origin); + PyObject *originArray = PyArray_SimpleNewFromData(1, dims, NPY_INT, (void *)origin); PyObject *setup = PyObject_GetAttrString(main, "setup"); PyObject *result = PyObject_CallFunctionObjArgs(setup, pInstance, NULL); if (result == NULL) { mitkThrow() << "Something went wrong setting the MITK image in Python"; } PyObject *convert = PyObject_GetAttrString(main, "convert_to_sitk"); - result = PyObject_CallFunctionObjArgs(convert, NULL); + result = PyObject_CallFunctionObjArgs(convert,spacingArray, originArray, NULL); if (result == NULL) { mitkThrow() << "Something went wrong converting the MITK image to a SimpleITK image"; } m_ThreadState = PyEval_SaveThread(); return true; } mitk::Image::Pointer mitk::PythonService::CopySimpleItkImageFromPython(const std::string &stdvarName) { mitk::Image::Pointer mitkImage; std::string convertToMITKImage = "import SimpleITK as sitk\n" "import pyMITK\n" "numpy_array = sitk.GetArrayViewFromImage("+stdvarName+")\n" - "mitk_image = pyMITK.GetImageFromArray(numpy_array)\n"; + "mitk_image = pyMITK.GetImageFromArray(numpy_array)\n" + "spacing = "+stdvarName+".GetSpacing()\n" + "origin = "+stdvarName +".GetOrigin()\n"; this->Execute(convertToMITKImage); PyGILState_STATE gState = PyGILState_Ensure(); PyObject *main = PyImport_AddModule("__main__"); PyObject *globals = PyModule_GetDict(main); PyObject *pyImage = PyDict_GetItemString(globals, "mitk_image"); if (pyImage==NULL) { mitkThrow() << "Could not get image from Python"; } int res = 0; void *voidImage; swig_type_info *pTypeInfo = nullptr; pTypeInfo = SWIG_TypeQuery("_p_itk__SmartPointerT_mitk__Image_t"); res = SWIG_ConvertPtr(pyImage, &voidImage, pTypeInfo, 0); if (!SWIG_IsOK(res)) { mitkThrow() << "Could not cast image to C++ type"; } mitkImage = *(reinterpret_cast(voidImage)); + PyObject *spacing = PyDict_GetItemString(globals, "spacing"); + mitk::Vector3D spacingMITK; + for (int i = 0; i < PyTuple_GET_SIZE(spacing); i++) + { + PyObject *spacingPy = PyTuple_GetItem(spacing, i); + double elem = PyFloat_AsDouble(spacingPy); + spacingMITK[i] = elem; + } + + PyObject *origin = PyDict_GetItemString(globals, "origin"); + mitk::Point3D originMITK; + for (int i = 0; i < PyTuple_GET_SIZE(origin); i++) + { + PyObject *originPy = PyTuple_GetItem(origin, i); + double elem = PyFloat_AsDouble(originPy); + originMITK[i] = elem; + } + m_ThreadState = PyEval_SaveThread(); + mitkImage->GetGeometry()->SetSpacing(spacingMITK); + mitkImage->GetGeometry()->SetOrigin(originMITK); return mitkImage; } bool mitk::PythonService::CopyMITKImageToPython(mitk::Image::Pointer &image, const std::string &stdvarName) { std::string transferToPython = "import pyMITK\n" + stdvarName +" = None\n" "\n" "def setup(image_from_cxx):\n" " print ('setup called with', image_from_cxx)\n" " global "+stdvarName+"\n" " "+stdvarName+" = image_from_cxx\n"; this->Execute(transferToPython); mitk::Image::Pointer *img = ℑ PyGILState_STATE gState = PyGILState_Ensure(); PyObject *main = PyImport_ImportModule("__main__"); if (main == NULL) { mitkThrow() << "Something went wrong getting the main module"; } swig_type_info *pTypeInfo = nullptr; pTypeInfo = SWIG_TypeQuery("_p_itk__SmartPointerT_mitk__Image_t"); int owned = 0; PyObject *pInstance = SWIG_NewPointerObj(reinterpret_cast(img), pTypeInfo, owned); if (pInstance == NULL) { mitkThrow() << "Something went wrong creating the Python instance of the image"; } PyObject *setup = PyObject_GetAttrString(main, "setup"); PyObject *result = PyObject_CallFunctionObjArgs(setup, pInstance, NULL); if (result == NULL) { mitkThrow() << "Something went wrong setting the MITK image in Python"; } m_PythonMITKImages.push_back(image); m_ThreadState = PyEval_SaveThread(); return true; } mitk::Image::Pointer GetImageFromPyObject(PyObject *pyImage) { mitk::Image::Pointer mitkImage; int res = 0; void *voidImage; swig_type_info *pTypeInfo = nullptr; pTypeInfo = SWIG_TypeQuery("_p_itk__SmartPointerT_mitk__Image_t"); res = SWIG_ConvertPtr(pyImage, &voidImage, pTypeInfo, 0); if (!SWIG_IsOK(res)) { mitkThrow() << "Could not cast image to C++ type"; } mitkImage = *(reinterpret_cast(voidImage)); return mitkImage; } mitk::Image::Pointer mitk::PythonService::CopyMITKImageFromPython(const std::string &stdvarName) { mitk::Image::Pointer mitkImage; PyGILState_STATE gState = PyGILState_Ensure(); PyObject *main = PyImport_AddModule("__main__"); PyObject *globals = PyModule_GetDict(main); PyObject *pyImage = PyDict_GetItemString(globals, stdvarName.c_str()); if (pyImage==NULL) { mitkThrow() << "Could not get image from Python"; } - //int res = 0; - //void *voidImage; - //swig_type_info *pTypeInfo = nullptr; - //pTypeInfo = SWIG_TypeQuery("_p_itk__SmartPointerT_mitk__Image_t"); - //res = SWIG_ConvertPtr(pyImage, &voidImage, pTypeInfo, 0); - //if (!SWIG_IsOK(res)) - //{ - // mitkThrow() << "Could not cast image to C++ type"; - //} - - //mitkImage = *(reinterpret_cast(voidImage)); - mitkImage = GetImageFromPyObject(pyImage); m_ThreadState = PyEval_SaveThread(); return mitkImage; } std::vector mitk::PythonService::CopyListOfMITKImagesFromPython(const std::string &listVarName) { std::vector mitkImages; PyGILState_STATE gState = PyGILState_Ensure(); PyObject *main = PyImport_AddModule("__main__"); PyObject *globals = PyModule_GetDict(main); PyObject *pyImageList = PyDict_GetItemString(globals, listVarName.c_str()); if (pyImageList == NULL) { mitkThrow() << "Could not get image list from Python"; } for (int i = 0; i < PyList_GET_SIZE(pyImageList);i++) { PyObject *pyImage = PyList_GetItem(pyImageList, i); mitk::Image::Pointer img = GetImageFromPyObject(pyImage); mitkImages.push_back(img); } m_ThreadState = PyEval_SaveThread(); return mitkImages; } bool mitk::PythonService::CopyToPythonAsCvImage( mitk::Image* image, const std::string& stdvarName ) { mitkThrow() << "This function is not implemented"; } mitk::Image::Pointer mitk::PythonService::CopyCvImageFromPython( const std::string& stdvarName ) { mitkThrow() << "This function is not implemented"; } //ctkAbstractPythonManager *mitk::PythonService::GetPythonManager() //{ // return NULL; //} mitk::Surface::Pointer mitk::PythonService::CopyVtkPolyDataFromPython( const std::string& stdvarName ) { mitkThrow() << "This function is not implemented"; } bool mitk::PythonService::CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& stdvarName ) { mitkThrow() << "This function is not implemented"; } bool mitk::PythonService::IsOpenCvPythonWrappingAvailable() { return m_OpenCVWrappingAvailable; } bool mitk::PythonService::IsVtkPythonWrappingAvailable() { return m_VtkWrappingAvailable; } bool mitk::PythonService::PythonErrorOccured() const { return m_ErrorOccured; }