diff --git a/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox b/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox index b88bc16275..e56c5b9748 100644 --- a/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox +++ b/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox @@ -1,18 +1,19 @@ /** \page MITKModuleManualsList List of Module Manuals \li \subpage AnnotationModulePage \li \subpage ChartModule \li \subpage IGTConcepts \li \subpage NavigationGeneralModulePage \li \subpage IGTTutorialOverview \li \subpage MitkOpenCL_Overview \li \subpage LegacyGLModule \li \subpage PAModulePage \li \subpage mitkPython_Overview \li \subpage RESTModule \li \subpage GeneratingDeviceModulesPage \li \subpage USModulePage + \li \subpage DeepLearningSegmentationModule */ diff --git a/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox b/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox index ee981d8a3a..bdfada09c0 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox @@ -1,36 +1,37 @@ /** \page MITKModuleManualsListPage MITK Module Manuals Overview The modules are shared libraries that provide functionality that can be used by developers. \subpage MITKModuleManualsList List of Module Manuals \subpage MITKModuleManualsListPageAdditionalInformation Additional Information on Certain Modules \subpage MITKMigrationGuides Migration Guides */ diff --git a/Modules/DeepLearningSegmentation/CMakeLists.txt b/Modules/DeepLearningSegmentation/CMakeLists.txt new file mode 100644 index 0000000000..20590056cc --- /dev/null +++ b/Modules/DeepLearningSegmentation/CMakeLists.txt @@ -0,0 +1,3 @@ +mitk_create_module(DeepLearningSegmentation + DEPENDS MitkSegmentationUI MitkPython +) \ No newline at end of file diff --git a/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp new file mode 100644 index 0000000000..0677b28dbb --- /dev/null +++ b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp @@ -0,0 +1,394 @@ +/*============================================================================ + +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/DeepLearningSegmentation/DeepLearningSegmentationTool.h b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.h new file mode 100644 index 0000000000..13a4b7f648 --- /dev/null +++ b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.h @@ -0,0 +1,131 @@ +/*============================================================================ + +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 DeepLearningSegmentationTool_h +#define DeepLearningSegmentationTool_h + +#include +#include + +namespace us { +class ModuleResource; +} + +namespace mitk +{ + /** + * @class DeepLearningSegmentationTool + * @brief This is the base class for all Deep Learning Based Segmentations + */ + class MITKDEEPLEARNINGSEGMENTATION_EXPORT DeepLearningSegmentationTool : public mitk::AutoSegmentationTool + { + public: + enum ImageType + { + SimpleITKImage, + MITKImage + }; + /** + * @brief Getter for the icon of the module which is displayed in the Segmentation Plugin. + * @return icon of the segmentation method + */ + us::ModuleResource GetIconResource() const override; + + //bool CanHandle(mitk::BaseData *referenceData) const override; + + /** + * @brief Getter for the name of the module which is displayed in the Segmentation Plugin. + * @return name of the segmentation method + */ + const char *GetName() const override; + const char **GetXPM() const override; + + /** + * @brief Constructor + * + * @param pythonFolder the folder of the python code, should lie in "Modules/DeepLearningsegmentation" + * @param inputImageVarName the python variable name of the input image to segment + * @param pythonFileName the file name of the python script to execute. This is the entry point for the segmentation + * @param outputImageVarName the python variable name of the output image (segmentation) + */ + DeepLearningSegmentationTool(std::string toolName, + std::string iconName, + std::string pythonFolder, + std::string inputImageVarName, + std::string pythonFileName, + std::string outputImageVarName, + ImageType imageType, + bool multilabel = false); + ~DeepLearningSegmentationTool() override; + + void Activated() override; + void Deactivated() override; + + /** + * @brief Executes the segmentation by running python code + * + * @throw mitk::Exception if something went wrong during a python call, python service is not found, or no input image is found + * @param networkPath the path to the trained network for segmentation + * @return the segmentation result as label set image + */ + mitk::LabelSetImage::Pointer DoSegmentation(std::string networkPath); + /** + * @brief Executes the multilabel segmentation by running python code + * + * @throw mitk::Exception if something went wrong during a python call, python service is not found, or no input + * image is found + * @param networkPath the path to the trained network for segmentation + * @return the segmentation result as vector of label set image + */ + std::vector DoMultilabelSegmentation(std::string networkPath); + /** + * @brief Get the input image for the semgentation which is currently selected in the Segmentation Plugin + * + * @throw mitk::Exception if the input is null + * @return input image for segmentation + */ + mitk::Image::Pointer GetInputImage(); + /** + * @brief Getter for m_SegmentaionRunning, to determine, if a segmentation is currently executed + * @return m_SegmentaionRunning + */ + bool IsSegmentationRunning(); + + /** + * @brief Getter for the data storage from the tool manager + * @return data storage + */ + mitk::DataStorage* GetDataStorage(); + /** + * @brief Getter for the reference data from the tool manager + * @return reference data + */ + mitk::DataNode *GetReferenceData(); + + bool IsMultilabelSegmentation(); + + protected: + std::string m_PythonProjectPath; + std::string m_InputImageVarName; + std::string m_PythonFileName; + std::string m_OutputImageVarName; + + private: + std::string m_IconName; + std::string m_ToolName; + bool m_SegmentationRunning; + ImageType m_ImageType; + bool m_MultilabelSegmentation; + }; +} // namespace mitk + +#endif diff --git a/Modules/DeepLearningSegmentation/documentation/DeveloperManual/DeepLearningSegmentation.dox b/Modules/DeepLearningSegmentation/documentation/DeveloperManual/DeepLearningSegmentation.dox new file mode 100644 index 0000000000..881c04913a --- /dev/null +++ b/Modules/DeepLearningSegmentation/documentation/DeveloperManual/DeepLearningSegmentation.dox @@ -0,0 +1,195 @@ +/** + +\page DeepLearningSegmentationModule Deep-Learning-Segmentation Module + +\tableofcontents + +\section DLSeg_brief Description +The MITK Deep-Learning-Segmentation Module enables developers to integrate their deep learning methods which should be developed in python in MITK. +The following guide should give an overview of the steps which have to be done to integrate a new deep learning method in MITK. + +\subsection DLSeg_MITKPrerequisites MITK Prerequisites +To use the Deep-Learning-Segmentation Module you need to build MITK with Python enabled (MITK_USE_PYTHON3 on in CMake configurations). Furthermore, SWIG has to be enabled (MITK_USE_SWIG). + +\subsection DLSeg_TypicalWorkflow A typical deep learning workflow +This guide assumes a certain workflow for the segmentation. This includes: + +
    +
  1. There is an entry script which starts the segmentation process. From this script, all required variables (image to segment, path to the trained network,...) have to be passed to the called methods, if needed. +
  2. The image for segmentation is a MITK or SimpleITK image. +
  3. The segmentation itself is also a MITK or SimpleITK image. +
  4. The trained network is passed as a string. +
  5. There are no more parameters required for segmentation. +
+ +\note segmentations with slightly different workflow could also be intergrated. For this, some methods have to be overwritten. A procedure for segmentations with additional parameters (point 5 above not fulfilled) is described later on. + +In the following sections, a tool called "My Segmentation" is integrated. The names in the code examples have to be adopted to the method you want to integrate. +The deep learning interface consists of two parts: The module MITKDeepLearningSegmentation, where the algorithm itself is implemented and the plugin org.mitk.gui.qt.deeplearningsegmentation, where the GUI interaction is implemented. + +\section DLSeg_Module Implementation in the module + +In the first step, all required parts in the module folder DeepLearningSegmentation are implemented. For this, the following steps are necessary: + +
    +
  1. Create a folder which contains the python code for segmentation. This folder might be called "my_seg_tool_algorithm" for instance. It contains the whole python repository which is needed for segmentation. + \warning There shouldn't be any larger files in the folder like results from experiments or the trained network. This would increase the size of the MITK repository too much and can lead to problems when pushing. +
  2. Put the icon of the tool as svg file in the resource folder. +
  3. Create a tool class. For this, you need to create a header file (MySegTool3D.h) and a cpp file (MySegTool3D.cpp). A typical structure for this files is shown in the following section. The files should be named with the syntax SegTool3D. +
  4. Edit the files.cmake file. You need to add the following files: +
      +
    • Add the cpp file MySegTool3D.cpp to the CPP_FILES +
    • Add the svg file to the RESOURCE_FILES +
    +
+ +\subsection DLSeg_ToolClass Typical structure of the tool class + +The header file of the tool class typically has the following structure: + +\code{.h} +#ifndef MySegTool3DGUI_h +#define MySegTool3DGUI_h +#include +#include"DeepLearningSegmentationGUI.h" +#include"MySegTool3D.h" +namespace Ui { +class MySegTool3DGUI; +} +class DEEPLEARNINGSEGMENTATION_EXPORT MySegTool3DGUI : public DeepLearningSegmentationGUI{ + Q_OBJECT +public: + mitkClassMacro(MySegTool3DGUI, QmitkToolGUI) + itkFactorylessNewMacro(Self) +protected slots: + void OnNewToolAssociated(mitk::Tool *); +}; +#endif // MySegTool3DGUI_h + +\endcode + +The cpp file of the tool class typically has the following structure: + +\code{.cpp} +#include "MySegTool3D.h" +namespace mitk{ + MITK_TOOL_MACRO(MITKDEEPLEARNINGSEGMENTATION_EXPORT, MySegTool3D, "My Segmentation tool"); +} + +mitk::MySegTool3D::MySegTool3D() + : DeepLearningSegmentationTool("My Segmentation", "icon_seg.svg", "my_seg_tool_algorithm", "input_image", "segment.py", "output_image", DeepLearningSegmentationTool::MITKImage, false){ +} + +mitk::MySegTool3D::~MySegTool3D() { +} +\endcode + +In the tool class, only some macros are defined and the implementation of the construcor with some arguments is necessary. +This arguments are: + +
    +
  • The name of the tool, which should be displayed in the workbench (e.g. "My Segmentation") +
  • The file name of the icon, which should be visible in the workbench (e.g. "icon_seg.svg") +
  • The name of the folder, in which the python code for execution lies (e.g. "my_seg_tool_algorithm"). This folder has to be in the module folder of the MITKDeepLearningSegmentation moudle. +
  • The variable name of the input image on python side (e.g. "input_image") +
  • The file name of the python script that is the entry point for the segmentation (e.g. "segment.py") +
  • The variable name of the output segmentation on python side (e.g. "output_image") +
  • The type of the images on python side (e.g. "DeepLearningSegmentationTool::MITKImage") +
  • (Optional) a boolean if the segmentation has multiple segments. The default value is false, which means a segmentation with only one segment. +
+ +\section DLSeg_Plugin Implementation in the plugin + +In the second step, the necesarry parts in the plugin folder org.mitk.gui.qt.deeplearningsegmentation are implemented. Therefore, you should execute the following steps: + +
    +
  1. Create a tool GUI class. For this, you need to create a header file (MySegTool3DGUI.h) and a cpp file (MySegTool3DGUI.cpp). A typical structure for this files is shown in the following section. The files should be named with the syntax SegTool3DGUI. +
  2. Edit the files.cmake file. You need to add the following files: +
      +
    • Add the cpp file MySegTool3DGUI.cpp to the INTERNAL_CPP_FILES +
    • Add src/internal/MySegTool3DGUI.h to the MOC_H_FILES +
    +
+ +\subsection DLSeg_ToolGUIClass Typical structure of the tool GUI class + +The header file of the tool GUI class typically has the following structure: + +\code{.h} +#ifndef MySegTool3DGUI_h +#define MySegTool3DGUI_h +#include +#include"DeepLearningSegmentationGUI.h" +#include"MySegTool3D.h" +namespace Ui { +class MySegTool3DGUI; +} +class DEEPLEARNINGSEGMENTATION_EXPORT MySegTool3DGUI : public DeepLearningSegmentationGUI{ + Q_OBJECT +public: + mitkClassMacro(MySegTool3DGUI, QmitkToolGUI) + itkFactorylessNewMacro(Self) +protected slots: + void OnNewToolAssociated(mitk::Tool *); +}; +#endif // MySegTool3DGUI_h + +\endcode + +The cpp file of the tool GUI class typically has the following structure: + +\code{.cpp} +#include "MySegTool3DGUI.h" +MITK_TOOL_GUI_MACRO(DEEPLEARNINGSEGMENTATION_EXPORT, MySegTool3DGUI, "") +void MySegTool3DGUI::OnNewToolAssociated(mitk::Tool* tool) { + m_SegTool = dynamic_cast(tool); +} +\endcode + +In the tool GUI class, some macros are defined as well. Furthermore, the method OnNewToolAssociated has to be implemented. This is necessary to associate the tool GUI class with the according tool class. + +If your segmentation algoithm fulfills all points from a typical deep learning workflow, you are done with integration. If modification is needed, methods have to be overwritten. The following section explains with an example how to add an additional parameter. + +\section DLSeg_AdditionalParameter Add an additional parameter + +This section describes how to add an additional parameter for your segmentation. The process is explained with a threshold parameter of the type double. You have to execute the following steps: + +
    +
  1. Implement a method for setting the parameter on the python side in the tool class. A method for setting the threshold might look like this: +\code{.cpp} +void mitk::MySegTool3D::SetThreshold(double threshold){ + mitk::IPythonService::ForceLoadModule(); + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto pythonServiceRefs = context->GetServiceReferences(filter); + if (!pythonServiceRefs.empty()){ + mitk::IPythonService *pythonService = + dynamic_cast( context->GetService( pythonServiceRefs.front())); + pythonService->Execute("threshold = " + std::to_string(threshold)); + } +} +\endcode +
  2. Overwrite the method SetUpUI() for adding a new GUI element. In the code below a GUI element is created first, then it is added to the GUI and then the SetUpUI() of the base class is called. m_ThresholdSpinBox is a member variable in order to access the value of the threshold later on. +\code{.cpp} +void mitk::MySegTool3D::SetThreshold(double threshold){ + mitk::IPythonService::ForceLoadModule(); + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto pythonServiceRefs = context->GetServiceReferences(filter); + if (!pythonServiceRefs.empty()){ + mitk::IPythonService *pythonService = + dynamic_cast( context->GetService( pythonServiceRefs.front())); + pythonService->Execute("threshold = " + std::to_string(threshold)); + } +} +\endcode +
  3. Overwrite the method OnDoSegmentation() in the tool GUI class. This is shown in the code below. First, the method from step 1 is called. Casting to the concrete type is neccessary in order to be able to access the method. The value of the GUI element is set in the method. Afterwards, the OnDoSegmentation() method of the base class is called to execute the segmentation itself. +\code{.cpp} +void MySegTool3DGUI::OnDoSegmentation() { + dynamic_cast(m_SegTool)->SetThreshold(m_ThresholdSpinBox->value()); + DeepLearningSegmentationGUI::OnDoSegmentation(); +} +\endcode +
+ +*/ diff --git a/Modules/DeepLearningSegmentation/files.cmake b/Modules/DeepLearningSegmentation/files.cmake new file mode 100644 index 0000000000..b46dd2c52a --- /dev/null +++ b/Modules/DeepLearningSegmentation/files.cmake @@ -0,0 +1,6 @@ +set(CPP_FILES +DeepLearningSegmentationTool.cpp +) + +set(RESOURCE_FILES +) diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index e9a5d07801..cb8587cb34 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,85 +1,88 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(MITK_MODULES Core CommandLine CoreCmdApps AppUtil LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOM DICOMQI DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction SceneSerialization Gizmo GraphAlgorithms Multilabel Chart ImageStatistics ContourModel SurfaceInterpolation Segmentation QtWidgets QtWidgetsExt ImageStatisticsUI SegmentationUI MatchPointRegistration MatchPointRegistrationUI Classification OpenIGTLink IGTBase IGT CameraCalibration OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI PhotoacousticsHardware PhotoacousticsAlgorithms PhotoacousticsLib US USUI DICOMUI Remeshing Python QtPython + PythonService + QtPythonService Persistence OpenIGTLinkUI IGTUI RT RTUI IOExt XNAT TubeGraph BiophotonicsHardware BoundingShape RenderWindowManager RenderWindowManagerUI SemanticRelations SemanticRelationsUI CEST BasicImageProcessing ModelFit ModelFitUI Pharmacokinetics PharmacokineticsUI DICOMPM REST RESTService DICOMweb + DeepLearningSegmentation ) if(MITK_ENABLE_PIC_READER) list(APPEND MITK_MODULES IpPicSupportIO) endif() diff --git a/Modules/Python/CMakeLists.txt b/Modules/Python/CMakeLists.txt index 14a48964fa..24b0fec937 100644 --- a/Modules/Python/CMakeLists.txt +++ b/Modules/Python/CMakeLists.txt @@ -1,13 +1,18 @@ if(MITK_USE_Python3) set(OpenCV_DEP ) if(MITK_USE_OpenCV) set(OpenCV_DEP OpenCV) endif() mitk_create_module( DEPENDS MitkCore PACKAGE_DEPENDS PUBLIC Python3|Python ) - add_subdirectory(autoload/PythonService) + if(BUILD_TESTING) + add_subdirectory(test) + endif() endif() + + + diff --git a/Modules/Python/documentation/mitkPython.dox b/Modules/Python/documentation/mitkPython.dox index ce19e8112b..b25d78554c 100644 --- a/Modules/Python/documentation/mitkPython.dox +++ b/Modules/Python/documentation/mitkPython.dox @@ -1,47 +1,47 @@ /** \page mitkPython_Overview Python Module \section python_sec1 Brief description The MITK Python Module provides a service class to interactively run python code (passed as C++ strings) and evaluate the results. Furthermore the service class offers means to convert an MITK Image to an ITK/OpenCV image in their wrapped python environment. Thus, one can process MITK images with Python Code from the OpenCV and ITK wrapping system. Furthermore one can convert an mitk::Surface to a vtkPolyData in its Python environment.
Under the hood, the MITK build system takes care that the wrapping build process for SimpleITK/VTK/OpenCV is correctly initiated and all paths are correctly set within MITK code. To use the features of the different toolkits make sure they are enabled during the superbuild process. \section python_sec2 Build Instructions -Have a look at \ref python_sec3 on how to build MITK-Python with Qt5. +Have a look at \ref python_ssec3 on how to build MITK-Python with Qt5. The following CMake build options are available:
  • MITK_USE_Python3
\subsection python_ssec1 MITK_USE_Python3 MITK_USE_Python3 enables the python wrapping in MITK. When the option is activated the build of the additional dependency SimpleITK is also enabled. The default behaviour is to use the python runtime from the system is used. Only Python 3.x is supported. The user can also specify it's own runtime by modifying the variables added by the FindPythonLib.cmake script. Note: A Python runtime with numpy is needed to use the MITK Python wrapping. When using this options all additional libraries installed in the python runtime will be available within the MITK-Python console. \section python_sec3 Suported Data Types The following data types in MITK are supported in the MITK Python Wrapping:
  • Image
  • Surface
\subsection python_ssec4 Image Mitk Images can be transferred to python. The images are copied in-memory and transferred as a numpy array to Python and vice versa. The MITK python wrapping creates a SimpleITK image using the numpy array with the properties of the MITK Image. Two dimensional images can also be transferred as an OpenCV image to python. \subsection python_ssec5 Surface Surfaces within mitk can be transferred as a vtkPolyData Object to Python. The surfaces are fully memory mapped. When changing a python wrapped surface the original object is also modified on the C++ side of MITK. */ diff --git a/Modules/Python/mitkIPythonService.cpp b/Modules/Python/mitkIPythonService.cpp index e52b7bb25e..2d2f0b1c2f 100644 --- a/Modules/Python/mitkIPythonService.cpp +++ b/Modules/Python/mitkIPythonService.cpp @@ -1,25 +1,25 @@ /*============================================================================ 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 "mitkIPythonService.h" mitk::IPythonService::~IPythonService() { } std::string mitk::IPythonService::ForceLoadModule() { std::string ret = "Load python module"; - MITK_INFO << ret; + MITK_DEBUG << ret; return ret; } diff --git a/Modules/Python/mitkIPythonService.h b/Modules/Python/mitkIPythonService.h index eb9c4d1dad..27fd7d3652 100644 --- a/Modules/Python/mitkIPythonService.h +++ b/Modules/Python/mitkIPythonService.h @@ -1,153 +1,169 @@ /*============================================================================ 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 mitkIPythonService_h #define mitkIPythonService_h // mitk #include #include "mitkImage.h" //for microservices #include #include "mitkSurface.h" #include -class ctkAbstractPythonManager; +//class ctkAbstractPythonManager; namespace mitk { /// /// describes a python variable (data container) /// \see IPythonService::GetVariableStack() /// struct PythonVariable { std::string m_Name; std::string m_Type; std::string m_Value; }; /// /// a PythonCommandObserver gets informed as soon as a python command was issued /// \see IPythonService::AddPythonCommandObserver() /// class PythonCommandObserver { public: virtual void CommandExecuted(const std::string& pythonCommand) = 0; }; /// /// The central service for issuing Python Code /// The class also enables to transfer mitk images to python as itk::Image and vice versa /// \see IPythonService::GetVariableStack() /// class MITKPYTHON_EXPORT IPythonService { public: /// /// Constant representing a single line command /// \see IPythonService::Execute() static const int SINGLE_LINE_COMMAND = 0; /// /// Constant representing a command in which the commands are seperated by new lines, i.e. "\\n" /// \see IPythonService::Execute() static const int MULTI_LINE_COMMAND = 1; /// /// Constant representing a single line command x which is run as "eval(x)" /// \see IPythonService::Execute() static const int EVAL_COMMAND = 2; - + /// /// /// Executes a python command. /// \return A variant containing the return value as string of the python code (if any) - virtual std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ) = 0; + virtual std::string Execute( const std::string& pythonCommand, int commandType= MULTI_LINE_COMMAND) = 0; /// /// Executes a python script. - virtual void ExecuteScript( const std::string& pathToPythonScript ) = 0; + virtual void ExecuteScript(const std::string &pathToPythonScript) = 0; /// /// \return true if the last call to Execute...() resulted in an error, false otherwise virtual bool PythonErrorOccured() const = 0; /// /// \return The list of variables in the __main__ namespace - virtual std::vector GetVariableStack() const = 0; + virtual std::vector GetVariableStack() = 0; /// /// \return true if a variable with this name is defined in the __main__ namespace, false otherwise - virtual bool DoesVariableExist(const std::string& name) const = 0; + virtual bool DoesVariableExist(const std::string& name) = 0; /// /// \return value of variable with this name as string, empty string if variable does not exist - virtual std::string GetVariable(const std::string& name) const = 0; + virtual std::string GetVariable(const std::string& name) = 0; /// /// adds a command observer which is informed after a command was issued with "Execute" virtual void AddPythonCommandObserver( PythonCommandObserver* observer ) = 0; /// /// removes a specific command observer virtual void RemovePythonCommandObserver( PythonCommandObserver* observer ) = 0; /// /// notify all observer. this should only be used if it can be garantueed that the /// current python interpreter instance got another command from anywhere else /// the the Execute() method of this service, e.g. the shell widget uses this function /// since it does not use Execute() virtual void NotifyObserver( const std::string& command ) = 0; - + /// + /// \return the number of registered Observers + virtual int GetNumberOfObserver() = 0; /// /// \return true, if itk wrapping is available, false otherwise virtual bool IsSimpleItkPythonWrappingAvailable() = 0; /// /// copies an mitk image as itk image into the python interpreter process /// the image will be available as "varName" in python if everythin worked /// \return true if image was copied, else false - virtual bool CopyToPythonAsSimpleItkImage( mitk::Image* image, const std::string& varName ) = 0; + virtual bool CopyToPythonAsSimpleItkImage( mitk::Image::Pointer image, const std::string& varName ) = 0; /// /// copies an itk image from the python process that is named "varName" /// \return the image or 0 if copying was not possible virtual mitk::Image::Pointer CopySimpleItkImageFromPython( const std::string& varName ) = 0; - + /// + /// copies an mitk image into the python interpreter process + /// the image will be available as "varName" in python if everythin worked + /// \return true if image was copied, else false + virtual bool CopyMITKImageToPython(mitk::Image::Pointer &image, const std::string &varName) = 0; + /// + /// copies an mitk image from the python process that is named "varName" + /// \return the image or 0 if copying was not possible + virtual mitk::Image::Pointer CopyMITKImageFromPython(const std::string &varName) = 0; + /// + /// copies an list of mitk images from the python process that is named "listVarName" + /// \return the image or 0 if copying was not possible + virtual std::vector CopyListOfMITKImagesFromPython(const std::string &listVarName) = 0; /// /// \return true, if OpenCv wrapping is available, false otherwise virtual bool IsOpenCvPythonWrappingAvailable() = 0; /// /// \see CopyToPythonAsItkImage() virtual bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ) = 0; /// /// \see CopyCvImageFromPython() virtual mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ) = 0; /// /// \return true, if vtk wrapping is available, false otherwise virtual bool IsVtkPythonWrappingAvailable() = 0; /// /// \see CopyToPythonAsItkImage() virtual bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ) = 0; /// /// \see CopyCvImageFromPython() virtual mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ) = 0; /// \return the ctk abstract python manager instance - virtual ctkAbstractPythonManager* GetPythonManager() = 0; + //virtual ctkAbstractPythonManager* GetPythonManager() = 0; /// /// nothing to do here virtual ~IPythonService(); // leer in mitkIPythonService.cpp implementieren // force us module loading by linking static std::string ForceLoadModule(); virtual void AddRelativeSearchDirs(std::vector< std::string > dirs) = 0; - virtual void AddAbsoluteSearchDirs(std::vector< std::string > dirs) = 0; + virtual void AddAbsoluteSearchDirs(std::vector dirs) = 0; + + protected: }; } MITK_DECLARE_SERVICE_INTERFACE(mitk::IPythonService, "org.mitk.services.IPythonService") #endif diff --git a/Modules/Python/test/CMakeLists.txt b/Modules/Python/test/CMakeLists.txt new file mode 100644 index 0000000000..153cd81e2e --- /dev/null +++ b/Modules/Python/test/CMakeLists.txt @@ -0,0 +1 @@ +MITK_CREATE_MODULE_TESTS() diff --git a/Modules/Python/test/files.cmake b/Modules/Python/test/files.cmake new file mode 100644 index 0000000000..0fc8d40dcb --- /dev/null +++ b/Modules/Python/test/files.cmake @@ -0,0 +1,11 @@ +set(MODULE_TESTS + mitkPythonTest.cpp + mitkQtPythonTest.cpp +) + +SET(CPP_FILES + mitkPythonObserverMock.cpp +) +SET(H_FILES + mitkPythonObserverMock.h +) \ No newline at end of file diff --git a/Modules/Python/test/hello_world_project/__init__.py b/Modules/Python/test/hello_world_project/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Modules/Python/test/hello_world_project/call_hello.py b/Modules/Python/test/hello_world_project/call_hello.py new file mode 100644 index 0000000000..02da366bd0 --- /dev/null +++ b/Modules/Python/test/hello_world_project/call_hello.py @@ -0,0 +1,6 @@ +from hello_to_call import HelloToCall + +if __name__ == "__main__": + hi = HelloToCall() + hi.text = "Hello from another script!" + hi.print_text() diff --git a/Modules/Python/test/hello_world_project/call_hello_in_subfolder.py b/Modules/Python/test/hello_world_project/call_hello_in_subfolder.py new file mode 100644 index 0000000000..391ac82dc6 --- /dev/null +++ b/Modules/Python/test/hello_world_project/call_hello_in_subfolder.py @@ -0,0 +1,5 @@ +from hello_subfolder.hello import HelloToCallInFolder +if __name__ == "__main__": + hi = HelloToCallInFolder() + hi.text = "Hello from outside the subfolder!" + hi.print_text() diff --git a/Modules/Python/test/hello_world_project/hello.py b/Modules/Python/test/hello_world_project/hello.py new file mode 100644 index 0000000000..43baad3a57 --- /dev/null +++ b/Modules/Python/test/hello_world_project/hello.py @@ -0,0 +1,10 @@ +class HelloWorld: + def __init__(self): + self.text = "Hello World!" + + def print_text(self): + print(self.text) + +if __name__ == "__main__": + hi = HelloWorld() + hi.print_text() diff --git a/Modules/Python/test/hello_world_project/hello_subfolder/__init__.py b/Modules/Python/test/hello_world_project/hello_subfolder/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Modules/Python/test/hello_world_project/hello_subfolder/hello.py b/Modules/Python/test/hello_world_project/hello_subfolder/hello.py new file mode 100644 index 0000000000..124fcc5e55 --- /dev/null +++ b/Modules/Python/test/hello_world_project/hello_subfolder/hello.py @@ -0,0 +1,10 @@ +class HelloToCallInFolder: + def __init__(self): + self.text = "Hello World!" + + def print_text(self): + print(self.text) + +if __name__ == "__main__": + hi = HelloWorld() + hi.print_text() diff --git a/Modules/Python/test/hello_world_project/hello_to_call.py b/Modules/Python/test/hello_world_project/hello_to_call.py new file mode 100644 index 0000000000..dc484f591a --- /dev/null +++ b/Modules/Python/test/hello_world_project/hello_to_call.py @@ -0,0 +1,6 @@ +class HelloToCall: + def __init__(self): + self.text = "Hello World!" + + def print_text(self): + print(self.text) diff --git a/Modules/Python/test/mitkPythonObserverMock.cpp b/Modules/Python/test/mitkPythonObserverMock.cpp new file mode 100644 index 0000000000..1636f45c22 --- /dev/null +++ b/Modules/Python/test/mitkPythonObserverMock.cpp @@ -0,0 +1,12 @@ +#include "mitkPythonObserverMock.h" + +PythonObserverMock::PythonObserverMock() + : m_Updated(false) +{ +} + +void PythonObserverMock::CommandExecuted(const std::string &pythonCommand) +{ + MITK_DEBUG << "received Command " << pythonCommand; + m_Updated = true; +} diff --git a/Modules/Python/mitkIPythonService.cpp b/Modules/Python/test/mitkPythonObserverMock.h similarity index 57% copy from Modules/Python/mitkIPythonService.cpp copy to Modules/Python/test/mitkPythonObserverMock.h index e52b7bb25e..7edccc0f74 100644 --- a/Modules/Python/mitkIPythonService.cpp +++ b/Modules/Python/test/mitkPythonObserverMock.h @@ -1,25 +1,24 @@ /*============================================================================ 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 mitkPythonObserverMock_h +#define mitkPythonObserverMock_h +#include -#include "mitkIPythonService.h" - -mitk::IPythonService::~IPythonService() -{ -} - -std::string mitk::IPythonService::ForceLoadModule() +class PythonObserverMock : public mitk::PythonCommandObserver { - std::string ret = "Load python module"; - MITK_INFO << ret; - return ret; -} +public: + PythonObserverMock(); + void CommandExecuted(const std::string &pythonCommand) override; + bool m_Updated; +}; +#endif \ No newline at end of file diff --git a/Modules/Python/test/mitkPythonTest.cpp b/Modules/Python/test/mitkPythonTest.cpp new file mode 100644 index 0000000000..ed3f260c77 --- /dev/null +++ b/Modules/Python/test/mitkPythonTest.cpp @@ -0,0 +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"); + } + m_PythonService->NotifyObserver(command); + 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/Python/test/mitkQtPythonTest.cpp b/Modules/Python/test/mitkQtPythonTest.cpp new file mode 100644 index 0000000000..a0a4492555 --- /dev/null +++ b/Modules/Python/test/mitkQtPythonTest.cpp @@ -0,0 +1,404 @@ +/*============================================================================ + +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 + +//#include + +class mitkQtPythonTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkQtPythonTestSuite); + MITK_TEST(TestEvaluateOperationWithResult); + MITK_TEST(TestExecuteStatement); + MITK_TEST(TestSettingVariable); + MITK_TEST(TestSettingVariableAndUseIt); + MITK_TEST(TestRunningScript); + 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(TestCopyImageToPython); + MITK_TEST(TestCopyImageFromPython); + CPPUNIT_TEST_SUITE_END(); + +public: + + void setUp() + { + mitk::IPythonService::ForceLoadModule(); + } + + void TestEvaluateOperationWithResult() + { + std::string result = ""; + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=QtPythonService)"; + 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=QtPythonService)"; + 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 == ""); + } + 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=QtPythonService)"; + 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 == ""); + } + 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=QtPythonService)"; + 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=QtPythonService)"; + 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 TestGetVariableStack() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=QtPythonService)"; + 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=QtPythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + m_PythonService->Execute("variable_to_get ='Get this variable'"); + + 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"); + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestDoesVariableExist_True() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=QtPythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + m_PythonService->Execute("existingVariable ='This variable exists'"); + + bool variableExists = m_PythonService->DoesVariableExist("existingVariable"); + CPPUNIT_ASSERT_MESSAGE("Testing if an existing variable is recognized", variableExists == true); + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestDoesVariableExist_False() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=QtPythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + bool variableExists = m_PythonService->DoesVariableExist("nonExistingVariable"); + CPPUNIT_ASSERT_MESSAGE("Testing if an not existing variable is not recognized", variableExists == false); + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestAddObserver() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=QtPythonService)"; + 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=QtPythonService)"; + 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=QtPythonService)"; + 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"); + } + m_PythonService->NotifyObserver(command); + CPPUNIT_ASSERT_MESSAGE("Testing if a command observer is notified", observer->m_Updated == true); + } + } + + void TestCopyImageToPython() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=QtPythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + mitk::Image::Pointer img = mitk::IOUtil::Load(GetTestDataFilePath("Pic3D.nrrd")); + m_PythonService->CopyToPythonAsSimpleItkImage(img, "input"); + } + } + + void TestCopyImageFromPython() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=QtPythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + std::string imgPath = GetTestDataFilePath("Pic3D.nrrd"); + std::string pythonCommand = "image_nrrd = sitk.ReadImage('" + imgPath + "')"; + m_PythonService->Execute(pythonCommand); + mitk::Image::Pointer img = m_PythonService->CopySimpleItkImageFromPython("image_nrrd"); + } + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkQtPython) diff --git a/Modules/Python/autoload/PythonService/CMakeLists.txt b/Modules/PythonService/CMakeLists.txt similarity index 58% copy from Modules/Python/autoload/PythonService/CMakeLists.txt copy to Modules/PythonService/CMakeLists.txt index 57455c3863..a151217919 100644 --- a/Modules/Python/autoload/PythonService/CMakeLists.txt +++ b/Modules/PythonService/CMakeLists.txt @@ -1,15 +1,12 @@ mitkFunctionCheckCompilerFlags("-Wno-cpp" CMAKE_CXX_FLAGS) mitk_create_module(PythonService - INCLUDE_DIRS - PRIVATE src/PythonService - DEPENDS PUBLIC MitkPython - PACKAGE_DEPENDS - PUBLIC Qt5|Widgets CTK|CTKScriptingPythonCore+CTKScriptingPythonWidgets - AUTOLOAD_WITH MitkPython + DEPENDS MitkPython + AUTOLOAD_WITH MitkPython ) if(TARGET ${MODULE_TARGET}) target_link_libraries(${MODULE_TARGET} PUBLIC Python3::NumPy) configure_file(PythonPath.h.in "${CMAKE_CURRENT_BINARY_DIR}/PythonPath.h" @ONLY) endif() + diff --git a/Modules/Python/autoload/PythonService/PythonPath.h.in b/Modules/PythonService/PythonPath.h.in similarity index 86% copy from Modules/Python/autoload/PythonService/PythonPath.h.in copy to Modules/PythonService/PythonPath.h.in index 28581baec4..de85cc242d 100644 --- a/Modules/Python/autoload/PythonService/PythonPath.h.in +++ b/Modules/PythonService/PythonPath.h.in @@ -1,16 +1,18 @@ #ifdef _DEBUG #define PYTHON_PATH_BUILD_TYPE "/Debug" +#define SWIG_MITK_WRAPPING "@MITK_BINARY_DIR@/lib/Debug" #else #define PYTHON_PATH_BUILD_TYPE "/Release" +#define SWIG_MITK_WRAPPING "@MITK_BINARY_DIR@/lib/Release" #endif #define PYTHON_LIBRARY "@PYTHON_LIBRARY@" #ifdef WIN32 //Todo: windows system python #define EXTERNAL_SITE_PACKAGES "@MITK_EXTERNAL_PROJECT_PREFIX@/lib/python@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@/site-packages" #define EXTERNAL_DIST_PACKAGES "@MITK_EXTERNAL_PROJECT_PREFIX@/lib/python@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@/dist-packages" #else #define EXTERNAL_SITE_PACKAGES "@MITK_EXTERNAL_PROJECT_PREFIX@/lib/python@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@/site-packages" #define EXTERNAL_DIST_PACKAGES "@MITK_EXTERNAL_PROJECT_PREFIX@/lib/python@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@/dist-packages" #endif diff --git a/Modules/Python/autoload/PythonService/files.cmake b/Modules/PythonService/files.cmake similarity index 100% rename from Modules/Python/autoload/PythonService/files.cmake rename to Modules/PythonService/files.cmake diff --git a/Modules/Python/autoload/PythonService/mitkPythonActivator.cpp b/Modules/PythonService/mitkPythonActivator.cpp similarity index 97% copy from Modules/Python/autoload/PythonService/mitkPythonActivator.cpp copy to Modules/PythonService/mitkPythonActivator.cpp index d58ba5cf27..da88d0f24c 100644 --- a/Modules/Python/autoload/PythonService/mitkPythonActivator.cpp +++ b/Modules/PythonService/mitkPythonActivator.cpp @@ -1,63 +1,64 @@ /*============================================================================ 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 mitkPythonActivator_h #define mitkPythonActivator_h // Microservices #include #include "usModuleContext.h" #include "mitkPythonService.h" #include namespace mitk { /// /// installs the PythonService /// runs all initial commands (setting env paths etc) /// class PythonActivator : public us::ModuleActivator { public: void Load(us::ModuleContext* context) override { MITK_DEBUG << "PythonActivator::Load"; // Registering PythonService as MicroService m_PythonService = itk::SmartPointer(new PythonService()); us::ServiceProperties _PythonServiceProps; _PythonServiceProps["Name"] = std::string("PythonService"); + _PythonServiceProps["service.ranking"] = int(0); m_PythonServiceRegistration = context->RegisterService(m_PythonService.GetPointer(), _PythonServiceProps); } void Unload(us::ModuleContext*) override { MITK_DEBUG("PythonActivator") << "PythonActivator::Unload"; MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); m_PythonServiceRegistration.Unregister(); m_PythonService->Delete(); MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); } ~PythonActivator() override { } private: itk::SmartPointer m_PythonService; us::ServiceRegistration m_PythonServiceRegistration; }; } US_EXPORT_MODULE_ACTIVATOR(mitk::PythonActivator) #endif diff --git a/Modules/PythonService/mitkPythonService.cpp b/Modules/PythonService/mitkPythonService.cpp new file mode 100644 index 0000000000..35e059fb7c --- /dev/null +++ b/Modules/PythonService/mitkPythonService.cpp @@ -0,0 +1,593 @@ +/*============================================================================ + +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(true), + m_VtkWrappingAvailable(true), + 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); + 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 NULL; +} + +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" + " np = pyMITK.GetArrayViewFromImage(mitk_image)\n" + " global "+stdvarName+"\n" + " "+stdvarName+" = sitk.GetImageFromArray(np)\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"; + } + PyObject *convert = PyObject_GetAttrString(main, "convert_to_sitk"); + result = PyObject_CallFunctionObjArgs(convert, 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"; + 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)); + + m_ThreadState = PyEval_SaveThread(); + 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 ) +{ + return NULL; +} + + +mitk::Image::Pointer mitk::PythonService::CopyCvImageFromPython( const std::string& stdvarName ) +{ + return NULL; +} + +//ctkAbstractPythonManager *mitk::PythonService::GetPythonManager() +//{ +// return NULL; +//} + +mitk::Surface::Pointer mitk::PythonService::CopyVtkPolyDataFromPython( const std::string& stdvarName ) +{ + return NULL; +} + +bool mitk::PythonService::CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& stdvarName ) +{ + return NULL; +} + +bool mitk::PythonService::IsOpenCvPythonWrappingAvailable() +{ + return NULL; +} + +bool mitk::PythonService::IsVtkPythonWrappingAvailable() +{ + return NULL; +} + +bool mitk::PythonService::PythonErrorOccured() const +{ + return m_ErrorOccured; +} + diff --git a/Modules/Python/autoload/PythonService/mitkPythonService.h b/Modules/PythonService/mitkPythonService.h similarity index 69% copy from Modules/Python/autoload/PythonService/mitkPythonService.h copy to Modules/PythonService/mitkPythonService.h index 31338dd8e1..9f990f94b6 100644 --- a/Modules/Python/autoload/PythonService/mitkPythonService.h +++ b/Modules/PythonService/mitkPythonService.h @@ -1,107 +1,132 @@ /*============================================================================ 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 mitkPythonService_h #define mitkPythonService_h -#include +//#include #include "mitkIPythonService.h" #include #include "mitkSurface.h" +#ifdef _DEBUG + #undef _DEBUG + #include + #define _DEBUG +#else + #include +#endif + namespace mitk { /// /// implementation of the IPythonService using ctkabstractpythonmanager /// \see IPythonService class PythonService: public itk::LightObject, public mitk::IPythonService { public: /// /// instantiate python manager here PythonService(); /// /// empty implementation... ~PythonService() override; /// /// \see IPythonService::Execute() - std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ) override; + std::string Execute(const std::string &pythonCommand, + int commandType = Py_file_input) override; /// /// \see IPythonService::ExecuteScript() void ExecuteScript(const std::string &pathToPythonScript) override; /// /// \see IPythonService::PythonErrorOccured() bool PythonErrorOccured() const override; /// /// \see IPythonService::GetVariableStack() - std::vector GetVariableStack() const override; + std::vector GetVariableStack() override; /// /// \see IPythonService::DoesVariableExist() - bool DoesVariableExist(const std::string& name) const override; + bool DoesVariableExist(const std::string& name) override; /// /// \see IPythonService::GetVariable() - std::string GetVariable(const std::string& name) const override; + std::string GetVariable(const std::string& name) override; /// /// \see IPythonService::AddPythonCommandObserver() void AddPythonCommandObserver( PythonCommandObserver* observer ) override; /// /// \see IPythonService::RemovePythonCommandObserver() void RemovePythonCommandObserver( PythonCommandObserver* observer ) override; /// /// \see IPythonService::NotifyObserver() void NotifyObserver( const std::string& command ) override; /// + /// \see IPythonService::GetNumberOfObserver() + int GetNumberOfObserver() override; + /// /// \see IPythonService::IsItkPythonWrappingAvailable() bool IsSimpleItkPythonWrappingAvailable() override; /// /// \see IPythonService::CopyToPythonAsItkImage() - bool CopyToPythonAsSimpleItkImage( mitk::Image* image, const std::string& varName ) override; + bool CopyToPythonAsSimpleItkImage( mitk::Image::Pointer image, const std::string& varName ) override; /// /// \see IPythonService::CopyItkImageFromPython() mitk::Image::Pointer CopySimpleItkImageFromPython( const std::string& varName ) override; /// + /// \see IPythonService::CopyMITKImageToPython() + bool CopyMITKImageToPython(mitk::Image::Pointer &image, const std::string &varName) override; + /// + /// \see IPythonService::CopyMITKImageFromPython() + mitk::Image::Pointer CopyMITKImageFromPython(const std::string &varName) override; + /// + /// \see IPythonService::CopyListOfMITKImagesFromPython() + std::vector CopyListOfMITKImagesFromPython(const std::string &listVarName) override; + /// /// \see IPythonService::IsOpenCvPythonWrappingAvailable() bool IsOpenCvPythonWrappingAvailable() override; /// /// \see IPythonService::CopyToPythonAsCvImage() bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ) override; /// /// \see IPythonService::CopyCvImageFromPython() mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ) override; /// /// \see IPythonService::IsVtkPythonWrappingAvailable() bool IsVtkPythonWrappingAvailable() override; /// /// \see IPythonService::CopyToPythonAsVtkPolyData() bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ) override; /// /// \see IPythonService::CopyVtkPolyDataFromPython() mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ) override; /// /// \return the ctk abstract python manager instance - ctkAbstractPythonManager* GetPythonManager() override; + //ctkAbstractPythonManager* GetPythonManager() override; void AddRelativeSearchDirs(std::vector< std::string > dirs) override; void AddAbsoluteSearchDirs(std::vector< std::string > dirs) override; protected: private: - QList m_Observer; - ctkAbstractPythonManager m_PythonManager; + //ctkAbstractPythonManager m_PythonManager; + std::vector m_Observer; + std::vector m_PythonMITKImages; + PyThreadState *m_ThreadState; + PyObject *m_GlobalDictionary; + PyObject *m_LocalDictionary; bool m_ItkWrappingAvailable; bool m_OpenCVWrappingAvailable; bool m_VtkWrappingAvailable; bool m_ErrorOccured; }; } #endif diff --git a/Modules/PythonService/swigpyrun.h b/Modules/PythonService/swigpyrun.h new file mode 100644 index 0000000000..2c4fcac1df --- /dev/null +++ b/Modules/PythonService/swigpyrun.h @@ -0,0 +1,2650 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 4.0.2 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + * This section contains generic SWIG labels for method/variable + * declarations/attributes, and other compiler dependent labels. + * ----------------------------------------------------------------------------- */ + +/* template workaround for compilers that cannot correctly implement the C++ standard */ +#ifndef SWIGTEMPLATEDISAMBIGUATOR +# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) +# define SWIGTEMPLATEDISAMBIGUATOR template +# elif defined(__HP_aCC) +/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ +/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ +# define SWIGTEMPLATEDISAMBIGUATOR template +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +#endif + +/* inline attribute */ +#ifndef SWIGINLINE +# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +# else +# define SWIGINLINE +# endif +#endif + +/* attribute recognised by some compilers to avoid 'unused' warnings */ +#ifndef SWIGUNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIG_MSC_UNSUPPRESS_4505 +# if defined(_MSC_VER) +# pragma warning(disable : 4505) /* unreferenced local function has been removed */ +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if defined(__GNUC__) +# if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ +#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) +# define _SCL_SECURE_NO_DEPRECATE +#endif + +/* Deal with Apple's deprecated 'AssertMacros.h' from Carbon-framework */ +#if defined(__APPLE__) && !defined(__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES) +# define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 +#endif + +/* Intel's compiler complains if a variable which was never initialised is + * cast to void, which is a common idiom which we use to indicate that we + * are aware a variable isn't used. So we just silence that warning. + * See: https://github.com/swig/swig/issues/192 for more discussion. + */ +#ifdef __INTEL_COMPILER +# pragma warning disable 592 +#endif +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic C API SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "4" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the SWIG runtime code. + In 99.9% of the cases, SWIG just needs to declare them as 'static'. + + But only do this if strictly necessary, ie, if you have problems + with your compiler or suchlike. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 +#define SWIG_CAST_NEW_MEMORY 0x2 +#define SWIG_POINTER_NO_NULL 0x4 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The SWIG conversion methods, as ConvertPtr, return an integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old versions of SWIG, code such as the following was usually written: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + which is the same really, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + also requires SWIG_ConvertPtr to return new result values, such as + + int SWIG_ConvertPtr(obj, ptr,...) { + if () { + if () { + *ptr = ; + return SWIG_NEWOBJ; + } else { + *ptr = ; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + SWIG errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() +*/ + +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast(r) (r) +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *, int *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store information on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class" == "Class", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (int)((l1 - f1) - (l2 - f2)); +} + +/* + Check type equivalence in a name list like ||... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCmp(const char *nb, const char *tb) { + int equiv = 1; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (equiv != 0 && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = SWIG_TypeNameComp(nb, ne, tb, te); + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like ||... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + return SWIG_TypeCmp(nb, tb) == 0 ? 1 : 0; +} + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + if (ty) { + swig_cast_info *iter = ty->cast; + while (iter) { + if (strcmp(iter->type->name, c) == 0) { + if (iter == ty->cast) + return iter; + /* Move iter to the top of the linked list */ + iter->prev->next = iter->next; + if (iter->next) + iter->next->prev = iter->prev; + iter->next = ty->cast; + iter->prev = 0; + if (ty->cast) ty->cast->prev = iter; + ty->cast = iter; + return iter; + } + iter = iter->next; + } + } + return 0; +} + +/* + Identical to SWIG_TypeCheck, except strcmp is replaced with a pointer comparison +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *ty) { + if (ty) { + swig_cast_info *iter = ty->cast; + while (iter) { + if (iter->type == from) { + if (iter == ty->cast) + return iter; + /* Move iter to the top of the linked list */ + iter->prev->next = iter->next; + if (iter->next) + iter->next->prev = iter->prev; + iter->next = ty->cast; + iter->prev = 0; + if (ty->cast) ty->cast->prev = iter; + ty->cast = iter; + return iter; + } + iter = iter->next; + } + } + return 0; +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + size_t l = 0; + size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + const unsigned char *u = (unsigned char *) ptr; + const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + unsigned char *u = (unsigned char *) ptr; + const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + char d = *(c++); + unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = (unsigned char)((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = (unsigned char)((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (unsigned char)(d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (unsigned char)(d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif +/* Compatibility macros for Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + +#define PyClass_Check(obj) PyObject_IsInstance(obj, (PyObject *)&PyType_Type) +#define PyInt_Check(x) PyLong_Check(x) +#define PyInt_AsLong(x) PyLong_AsLong(x) +#define PyInt_FromLong(x) PyLong_FromLong(x) +#define PyInt_FromSize_t(x) PyLong_FromSize_t(x) +#define PyString_Check(name) PyBytes_Check(name) +#define PyString_FromString(x) PyUnicode_FromString(x) +#define PyString_Format(fmt, args) PyUnicode_Format(fmt, args) +#define PyString_AsString(str) PyBytes_AsString(str) +#define PyString_Size(str) PyBytes_Size(str) +#define PyString_InternFromString(key) PyUnicode_InternFromString(key) +#define Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_BASETYPE +#define PyString_AS_STRING(x) PyUnicode_AS_STRING(x) +#define _PyLong_FromSsize_t(x) PyLong_FromSsize_t(x) + +#endif + +#ifndef Py_TYPE +# define Py_TYPE(op) ((op)->ob_type) +#endif + +/* SWIG APIs for compatibility of both Python 2 & 3 */ + +#if PY_VERSION_HEX >= 0x03000000 +# define SWIG_Python_str_FromFormat PyUnicode_FromFormat +#else +# define SWIG_Python_str_FromFormat PyString_FromFormat +#endif + + +/* Warning: This function will allocate a new string in Python 3, + * so please call SWIG_Python_str_DelForPy3(x) to free the space. + */ +SWIGINTERN char* +SWIG_Python_str_AsChar(PyObject *str) +{ +#if PY_VERSION_HEX >= 0x03030000 + return (char *)PyUnicode_AsUTF8(str); +#elif PY_VERSION_HEX >= 0x03000000 + char *newstr = 0; + str = PyUnicode_AsUTF8String(str); + if (str) { + char *cstr; + Py_ssize_t len; + if (PyBytes_AsStringAndSize(str, &cstr, &len) != -1) { + newstr = (char *) malloc(len+1); + if (newstr) + memcpy(newstr, cstr, len+1); + } + Py_XDECREF(str); + } + return newstr; +#else + return PyString_AsString(str); +#endif +} + +#if PY_VERSION_HEX >= 0x03030000 || PY_VERSION_HEX < 0x03000000 +# define SWIG_Python_str_DelForPy3(x) +#else +# define SWIG_Python_str_DelForPy3(x) free( (void*) (x) ) +#endif + + +SWIGINTERN PyObject* +SWIG_Python_str_FromChar(const char *c) +{ +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromString(c); +#else + return PyString_FromString(c); +#endif +} + +#ifndef PyObject_DEL +# define PyObject_DEL PyObject_Del +#endif + +// SWIGPY_USE_CAPSULE is no longer used within SWIG itself, but some user +// interface files check for it. +# define SWIGPY_USE_CAPSULE +# define SWIGPY_CAPSULE_NAME ("swig_runtime_data" SWIG_RUNTIME_VERSION ".type_pointer_capsule" SWIG_TYPE_TABLE_NAME) + +#if PY_VERSION_HEX < 0x03020000 +#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type) +#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name) +#define Py_hash_t long +#endif +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIME PyObject* +SWIG_Python_ErrorType(int code) { + PyObject* type = 0; + switch(code) { + case SWIG_MemoryError: + type = PyExc_MemoryError; + break; + case SWIG_IOError: + type = PyExc_IOError; + break; + case SWIG_RuntimeError: + type = PyExc_RuntimeError; + break; + case SWIG_IndexError: + type = PyExc_IndexError; + break; + case SWIG_TypeError: + type = PyExc_TypeError; + break; + case SWIG_DivisionByZero: + type = PyExc_ZeroDivisionError; + break; + case SWIG_OverflowError: + type = PyExc_OverflowError; + break; + case SWIG_SyntaxError: + type = PyExc_SyntaxError; + break; + case SWIG_ValueError: + type = PyExc_ValueError; + break; + case SWIG_SystemError: + type = PyExc_SystemError; + break; + case SWIG_AttributeError: + type = PyExc_AttributeError; + break; + default: + type = PyExc_RuntimeError; + } + return type; +} + + +SWIGRUNTIME void +SWIG_Python_AddErrorMsg(const char* mesg) +{ + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + + if (PyErr_Occurred()) + PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + const char *tmp = SWIG_Python_str_AsChar(old_str); + PyErr_Clear(); + Py_XINCREF(type); + if (tmp) + PyErr_Format(type, "%s %s", tmp, mesg); + else + PyErr_Format(type, "%s", mesg); + SWIG_Python_str_DelForPy3(tmp); + Py_DECREF(old_str); + Py_DECREF(value); + } else { + PyErr_SetString(PyExc_RuntimeError, mesg); + } +} + +SWIGRUNTIME int +SWIG_Python_TypeErrorOccurred(PyObject *obj) +{ + PyObject *error; + if (obj) + return 0; + error = PyErr_Occurred(); + return error && PyErr_GivenExceptionMatches(error, PyExc_TypeError); +} + +SWIGRUNTIME void +SWIG_Python_RaiseOrModifyTypeError(const char *message) +{ + if (SWIG_Python_TypeErrorOccurred(NULL)) { + /* Use existing TypeError to preserve stacktrace and enhance with given message */ + PyObject *newvalue; + PyObject *type = NULL, *value = NULL, *traceback = NULL; + PyErr_Fetch(&type, &value, &traceback); +#if PY_VERSION_HEX >= 0x03000000 + newvalue = PyUnicode_FromFormat("%S\nAdditional information:\n%s", value, message); +#else + newvalue = PyString_FromFormat("%s\nAdditional information:\n%s", PyString_AsString(value), message); +#endif + Py_XDECREF(value); + PyErr_Restore(type, newvalue, traceback); + } else { + /* Raise TypeError using given message */ + PyErr_SetString(PyExc_TypeError, message); + } +} +#if defined(SWIG_PYTHON_NO_THREADS) +# if defined(SWIG_PYTHON_THREADS) +# undef SWIG_PYTHON_THREADS +# endif +#endif +#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ +# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) +# define SWIG_PYTHON_USE_GIL +# endif +# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ +# ifndef SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() +# endif +# ifdef __cplusplus /* C++ code */ + class SWIG_Python_Thread_Block { + bool status; + PyGILState_STATE state; + public: + void end() { if (status) { PyGILState_Release(state); status = false;} } + SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} + ~SWIG_Python_Thread_Block() { end(); } + }; + class SWIG_Python_Thread_Allow { + bool status; + PyThreadState *save; + public: + void end() { if (status) { PyEval_RestoreThread(save); status = false; }} + SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} + ~SWIG_Python_Thread_Allow() { end(); } + }; +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block +# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow +# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() +# else /* C code */ +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() +# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() +# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) +# endif +# else /* Old thread way, not implemented, user must provide it */ +# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) +# define SWIG_PYTHON_INITIALIZE_THREADS +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) +# define SWIG_PYTHON_THREAD_END_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# endif +# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) +# define SWIG_PYTHON_THREAD_END_ALLOW +# endif +# endif +#else /* No thread support */ +# define SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# define SWIG_PYTHON_THREAD_END_BLOCK +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# define SWIG_PYTHON_THREAD_END_ALLOW +#endif +/* ----------------------------------------------------------------------------- + * Python API portion that goes into the runtime + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------------------------------------------------------- + * Constant declarations + * ----------------------------------------------------------------------------- */ + +/* Constant Types */ +#define SWIG_PY_POINTER 4 +#define SWIG_PY_BINARY 5 + +/* Constant information structure */ +typedef struct swig_const_info { + int type; + const char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_const_info; + +#ifdef __cplusplus +} +#endif + +/* ----------------------------------------------------------------------------- + * pyrun.swg + * + * This file contains the runtime support for Python modules + * and includes code for managing global variables and pointer + * type checking. + * + * ----------------------------------------------------------------------------- */ + +#if PY_VERSION_HEX < 0x02070000 /* 2.7.0 */ +# error "This version of SWIG only supports Python >= 2.7" +#endif + +#if PY_VERSION_HEX >= 0x03000000 && PY_VERSION_HEX < 0x03020000 +# error "This version of SWIG only supports Python 3 >= 3.2" +#endif + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) +#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) +#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) + +#ifdef SWIGPYTHON_BUILTIN +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(self, ptr, type, flags) +#else +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) +#endif + +#define SWIG_InternalNewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) + +#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) +#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) +#define swig_owntype int + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) +#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(NULL, ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Python_GetModule(clientdata) +#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) +#define SWIG_NewClientData(obj) SwigPyClientData_New(obj) + +#define SWIG_SetErrorObj SWIG_Python_SetErrorObj +#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg +#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail + + +/* Runtime API implementation */ + +/* Error manipulation */ + +SWIGINTERN void +SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetObject(errtype, obj); + Py_DECREF(obj); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +SWIGINTERN void +SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetString(errtype, msg); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) + +/* Set a constant value */ + +#if defined(SWIGPYTHON_BUILTIN) + +SWIGINTERN void +SwigPyBuiltin_AddPublicSymbol(PyObject *seq, const char *key) { + PyObject *s = PyString_InternFromString(key); + PyList_Append(seq, s); + Py_DECREF(s); +} + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, PyObject *public_interface, const char *name, PyObject *obj) { + PyDict_SetItemString(d, name, obj); + Py_DECREF(obj); + if (public_interface) + SwigPyBuiltin_AddPublicSymbol(public_interface, name); +} + +#else + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { + PyDict_SetItemString(d, name, obj); + Py_DECREF(obj); +} + +#endif + +/* Append a value to the result obj */ + +SWIGINTERN PyObject* +SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyList_Check(result)) { + PyObject *o2 = result; + result = PyList_New(1); + PyList_SetItem(result, 0, o2); + } + PyList_Append(result,obj); + Py_DECREF(obj); + } + return result; +} + +/* Unpack the argument tuple */ + +SWIGINTERN Py_ssize_t +SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) +{ + if (!args) { + if (!min && !max) { + return 1; + } else { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", + name, (min == max ? "" : "at least "), (int)min); + return 0; + } + } + if (!PyTuple_Check(args)) { + if (min <= 1 && max >= 1) { + Py_ssize_t i; + objs[0] = args; + for (i = 1; i < max; ++i) { + objs[i] = 0; + } + return 2; + } + PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); + return 0; + } else { + Py_ssize_t l = PyTuple_GET_SIZE(args); + if (l < min) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at least "), (int)min, (int)l); + return 0; + } else if (l > max) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at most "), (int)max, (int)l); + return 0; + } else { + Py_ssize_t i; + for (i = 0; i < l; ++i) { + objs[i] = PyTuple_GET_ITEM(args, i); + } + for (; l < max; ++l) { + objs[l] = 0; + } + return i + 1; + } + } +} + +SWIGINTERN int +SWIG_Python_CheckNoKeywords(PyObject *kwargs, const char *name) { + int no_kwargs = 1; + if (kwargs) { + assert(PyDict_Check(kwargs)); + if (PyDict_Size(kwargs) > 0) { + PyErr_Format(PyExc_TypeError, "%s() does not take keyword arguments", name); + no_kwargs = 0; + } + } + return no_kwargs; +} + +/* A functor is a function object with one single object argument */ +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); + +/* + Helper for static pointer initialization for both C and C++ code, for example + static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); +*/ +#ifdef __cplusplus +#define SWIG_STATIC_POINTER(var) var +#else +#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var +#endif + +/* ----------------------------------------------------------------------------- + * Pointer declarations + * ----------------------------------------------------------------------------- */ + +/* Flags for new pointer objects */ +#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) +#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) + +#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) + +#define SWIG_BUILTIN_TP_INIT (SWIG_POINTER_OWN << 2) +#define SWIG_BUILTIN_INIT (SWIG_BUILTIN_TP_INIT | SWIG_POINTER_OWN) + +#ifdef __cplusplus +extern "C" { +#endif + +/* The python void return value */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Py_Void(void) +{ + PyObject *none = Py_None; + Py_INCREF(none); + return none; +} + +/* SwigPyClientData */ + +typedef struct { + PyObject *klass; + PyObject *newraw; + PyObject *newargs; + PyObject *destroy; + int delargs; + int implicitconv; + PyTypeObject *pytype; +} SwigPyClientData; + +SWIGRUNTIMEINLINE int +SWIG_Python_CheckImplicit(swig_type_info *ty) +{ + SwigPyClientData *data = (SwigPyClientData *)ty->clientdata; + int fail = data ? data->implicitconv : 0; + if (fail) + PyErr_SetString(PyExc_TypeError, "Implicit conversion is prohibited for explicit constructors."); + return fail; +} + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_ExceptionType(swig_type_info *desc) { + SwigPyClientData *data = desc ? (SwigPyClientData *) desc->clientdata : 0; + PyObject *klass = data ? data->klass : 0; + return (klass ? klass : PyExc_RuntimeError); +} + + +SWIGRUNTIME SwigPyClientData * +SwigPyClientData_New(PyObject* obj) +{ + if (!obj) { + return 0; + } else { + SwigPyClientData *data = (SwigPyClientData *)malloc(sizeof(SwigPyClientData)); + /* the klass element */ + data->klass = obj; + Py_INCREF(data->klass); + /* the newraw method and newargs arguments used to create a new raw instance */ + if (PyClass_Check(obj)) { + data->newraw = 0; + data->newargs = obj; + Py_INCREF(obj); + } else { + data->newraw = PyObject_GetAttrString(data->klass, "__new__"); + if (data->newraw) { + Py_INCREF(data->newraw); + data->newargs = PyTuple_New(1); + PyTuple_SetItem(data->newargs, 0, obj); + } else { + data->newargs = obj; + } + Py_INCREF(data->newargs); + } + /* the destroy method, aka as the C++ delete method */ + data->destroy = PyObject_GetAttrString(data->klass, "__swig_destroy__"); + if (PyErr_Occurred()) { + PyErr_Clear(); + data->destroy = 0; + } + if (data->destroy) { + int flags; + Py_INCREF(data->destroy); + flags = PyCFunction_GET_FLAGS(data->destroy); + data->delargs = !(flags & (METH_O)); + } else { + data->delargs = 0; + } + data->implicitconv = 0; + data->pytype = 0; + return data; + } +} + +SWIGRUNTIME void +SwigPyClientData_Del(SwigPyClientData *data) { + Py_XDECREF(data->newraw); + Py_XDECREF(data->newargs); + Py_XDECREF(data->destroy); +} + +/* =============== SwigPyObject =====================*/ + +typedef struct { + PyObject_HEAD + void *ptr; + swig_type_info *ty; + int own; + PyObject *next; +#ifdef SWIGPYTHON_BUILTIN + PyObject *dict; +#endif +} SwigPyObject; + + +#ifdef SWIGPYTHON_BUILTIN + +SWIGRUNTIME PyObject * +SwigPyObject_get___dict__(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) +{ + SwigPyObject *sobj = (SwigPyObject *)v; + + if (!sobj->dict) + sobj->dict = PyDict_New(); + + Py_INCREF(sobj->dict); + return sobj->dict; +} + +#endif + +SWIGRUNTIME PyObject * +SwigPyObject_long(SwigPyObject *v) +{ + return PyLong_FromVoidPtr(v->ptr); +} + +SWIGRUNTIME PyObject * +SwigPyObject_format(const char* fmt, SwigPyObject *v) +{ + PyObject *res = NULL; + PyObject *args = PyTuple_New(1); + if (args) { + if (PyTuple_SetItem(args, 0, SwigPyObject_long(v)) == 0) { + PyObject *ofmt = SWIG_Python_str_FromChar(fmt); + if (ofmt) { +#if PY_VERSION_HEX >= 0x03000000 + res = PyUnicode_Format(ofmt,args); +#else + res = PyString_Format(ofmt,args); +#endif + Py_DECREF(ofmt); + } + Py_DECREF(args); + } + } + return res; +} + +SWIGRUNTIME PyObject * +SwigPyObject_oct(SwigPyObject *v) +{ + return SwigPyObject_format("%o",v); +} + +SWIGRUNTIME PyObject * +SwigPyObject_hex(SwigPyObject *v) +{ + return SwigPyObject_format("%x",v); +} + +SWIGRUNTIME PyObject * +SwigPyObject_repr(SwigPyObject *v) +{ + const char *name = SWIG_TypePrettyName(v->ty); + PyObject *repr = SWIG_Python_str_FromFormat("", (name ? name : "unknown"), (void *)v); + if (v->next) { + PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next); +# if PY_VERSION_HEX >= 0x03000000 + PyObject *joined = PyUnicode_Concat(repr, nrep); + Py_DecRef(repr); + Py_DecRef(nrep); + repr = joined; +# else + PyString_ConcatAndDel(&repr,nrep); +# endif + } + return repr; +} + +/* We need a version taking two PyObject* parameters so it's a valid + * PyCFunction to use in swigobject_methods[]. */ +SWIGRUNTIME PyObject * +SwigPyObject_repr2(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) +{ + return SwigPyObject_repr((SwigPyObject*)v); +} + +SWIGRUNTIME int +SwigPyObject_compare(SwigPyObject *v, SwigPyObject *w) +{ + void *i = v->ptr; + void *j = w->ptr; + return (i < j) ? -1 : ((i > j) ? 1 : 0); +} + +/* Added for Python 3.x, would it also be useful for Python 2.x? */ +SWIGRUNTIME PyObject* +SwigPyObject_richcompare(SwigPyObject *v, SwigPyObject *w, int op) +{ + PyObject* res; + if( op != Py_EQ && op != Py_NE ) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + res = PyBool_FromLong( (SwigPyObject_compare(v, w)==0) == (op == Py_EQ) ? 1 : 0); + return res; +} + + +SWIGRUNTIME PyTypeObject* SwigPyObject_TypeOnce(void); + +#ifdef SWIGPYTHON_BUILTIN +static swig_type_info *SwigPyObject_stype = 0; +SWIGRUNTIME PyTypeObject* +SwigPyObject_type(void) { + SwigPyClientData *cd; + assert(SwigPyObject_stype); + cd = (SwigPyClientData*) SwigPyObject_stype->clientdata; + assert(cd); + assert(cd->pytype); + return cd->pytype; +} +#else +SWIGRUNTIME PyTypeObject* +SwigPyObject_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyObject_TypeOnce(); + return type; +} +#endif + +SWIGRUNTIMEINLINE int +SwigPyObject_Check(PyObject *op) { +#ifdef SWIGPYTHON_BUILTIN + PyTypeObject *target_tp = SwigPyObject_type(); + if (PyType_IsSubtype(op->ob_type, target_tp)) + return 1; + return (strcmp(op->ob_type->tp_name, "SwigPyObject") == 0); +#else + return (Py_TYPE(op) == SwigPyObject_type()) + || (strcmp(Py_TYPE(op)->tp_name,"SwigPyObject") == 0); +#endif +} + +SWIGRUNTIME PyObject * +SwigPyObject_New(void *ptr, swig_type_info *ty, int own); + +SWIGRUNTIME void +SwigPyObject_dealloc(PyObject *v) +{ + SwigPyObject *sobj = (SwigPyObject *) v; + PyObject *next = sobj->next; + if (sobj->own == SWIG_POINTER_OWN) { + swig_type_info *ty = sobj->ty; + SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; + PyObject *destroy = data ? data->destroy : 0; + if (destroy) { + /* destroy is always a VARARGS method */ + PyObject *res; + + /* PyObject_CallFunction() has the potential to silently drop + the active exception. In cases of unnamed temporary + variable or where we just finished iterating over a generator + StopIteration will be active right now, and this needs to + remain true upon return from SwigPyObject_dealloc. So save + and restore. */ + + PyObject *type = NULL, *value = NULL, *traceback = NULL; + PyErr_Fetch(&type, &value, &traceback); + + if (data->delargs) { + /* we need to create a temporary object to carry the destroy operation */ + PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0); + res = SWIG_Python_CallFunctor(destroy, tmp); + Py_DECREF(tmp); + } else { + PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); + PyObject *mself = PyCFunction_GET_SELF(destroy); + res = ((*meth)(mself, v)); + } + if (!res) + PyErr_WriteUnraisable(destroy); + + PyErr_Restore(type, value, traceback); + + Py_XDECREF(res); + } +#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) + else { + const char *name = SWIG_TypePrettyName(ty); + printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); + } +#endif + } + Py_XDECREF(next); + PyObject_DEL(v); +} + +SWIGRUNTIME PyObject* +SwigPyObject_append(PyObject* v, PyObject* next) +{ + SwigPyObject *sobj = (SwigPyObject *) v; + if (!SwigPyObject_Check(next)) { + PyErr_SetString(PyExc_TypeError, "Attempt to append a non SwigPyObject"); + return NULL; + } + sobj->next = next; + Py_INCREF(next); + return SWIG_Py_Void(); +} + +SWIGRUNTIME PyObject* +SwigPyObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +{ + SwigPyObject *sobj = (SwigPyObject *) v; + if (sobj->next) { + Py_INCREF(sobj->next); + return sobj->next; + } else { + return SWIG_Py_Void(); + } +} + +SWIGINTERN PyObject* +SwigPyObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +{ + SwigPyObject *sobj = (SwigPyObject *)v; + sobj->own = 0; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +SwigPyObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +{ + SwigPyObject *sobj = (SwigPyObject *)v; + sobj->own = SWIG_POINTER_OWN; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +SwigPyObject_own(PyObject *v, PyObject *args) +{ + PyObject *val = 0; + if (!PyArg_UnpackTuple(args, "own", 0, 1, &val)) { + return NULL; + } else { + SwigPyObject *sobj = (SwigPyObject *)v; + PyObject *obj = PyBool_FromLong(sobj->own); + if (val) { + if (PyObject_IsTrue(val)) { + SwigPyObject_acquire(v,args); + } else { + SwigPyObject_disown(v,args); + } + } + return obj; + } +} + +static PyMethodDef +swigobject_methods[] = { + {"disown", SwigPyObject_disown, METH_NOARGS, "releases ownership of the pointer"}, + {"acquire", SwigPyObject_acquire, METH_NOARGS, "acquires ownership of the pointer"}, + {"own", SwigPyObject_own, METH_VARARGS, "returns/sets ownership of the pointer"}, + {"append", SwigPyObject_append, METH_O, "appends another 'this' object"}, + {"next", SwigPyObject_next, METH_NOARGS, "returns the next 'this' object"}, + {"__repr__",SwigPyObject_repr2, METH_NOARGS, "returns object representation"}, + {0, 0, 0, 0} +}; + +SWIGRUNTIME PyTypeObject* +SwigPyObject_TypeOnce(void) { + static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; + + static PyNumberMethods SwigPyObject_as_number = { + (binaryfunc)0, /*nb_add*/ + (binaryfunc)0, /*nb_subtract*/ + (binaryfunc)0, /*nb_multiply*/ + /* nb_divide removed in Python 3 */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc)0, /*nb_divide*/ +#endif + (binaryfunc)0, /*nb_remainder*/ + (binaryfunc)0, /*nb_divmod*/ + (ternaryfunc)0,/*nb_power*/ + (unaryfunc)0, /*nb_negative*/ + (unaryfunc)0, /*nb_positive*/ + (unaryfunc)0, /*nb_absolute*/ + (inquiry)0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ +#if PY_VERSION_HEX < 0x03000000 + 0, /*nb_coerce*/ +#endif + (unaryfunc)SwigPyObject_long, /*nb_int*/ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc)SwigPyObject_long, /*nb_long*/ +#else + 0, /*nb_reserved*/ +#endif + (unaryfunc)0, /*nb_float*/ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc)SwigPyObject_oct, /*nb_oct*/ + (unaryfunc)SwigPyObject_hex, /*nb_hex*/ +#endif +#if PY_VERSION_HEX >= 0x03050000 /* 3.5 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_matrix_multiply */ +#elif PY_VERSION_HEX >= 0x03000000 /* 3.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index, nb_inplace_divide removed */ +#else + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ +#endif + }; + + static PyTypeObject swigpyobject_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp = { +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "SwigPyObject", /* tp_name */ + sizeof(SwigPyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SwigPyObject_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ +#if PY_VERSION_HEX >= 0x03000000 + 0, /* tp_reserved in 3.0.1, tp_compare in 3.0.0 but not used */ +#else + (cmpfunc)SwigPyObject_compare, /* tp_compare */ +#endif + (reprfunc)SwigPyObject_repr, /* tp_repr */ + &SwigPyObject_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigobject_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)SwigPyObject_richcompare,/* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + swigobject_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif +#if PY_VERSION_HEX >= 0x03080000 + 0, /* tp_vectorcall */ +#endif +#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000) + 0, /* tp_print */ +#endif +#ifdef COUNT_ALLOCS + 0, /* tp_allocs */ + 0, /* tp_frees */ + 0, /* tp_maxalloc */ + 0, /* tp_prev */ + 0 /* tp_next */ +#endif + }; + swigpyobject_type = tmp; + type_init = 1; + if (PyType_Ready(&swigpyobject_type) < 0) + return NULL; + } + return &swigpyobject_type; +} + +SWIGRUNTIME PyObject * +SwigPyObject_New(void *ptr, swig_type_info *ty, int own) +{ + SwigPyObject *sobj = PyObject_NEW(SwigPyObject, SwigPyObject_type()); + if (sobj) { + sobj->ptr = ptr; + sobj->ty = ty; + sobj->own = own; + sobj->next = 0; + } + return (PyObject *)sobj; +} + +/* ----------------------------------------------------------------------------- + * Implements a simple Swig Packed type, and use it instead of string + * ----------------------------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + void *pack; + swig_type_info *ty; + size_t size; +} SwigPyPacked; + +SWIGRUNTIME PyObject * +SwigPyPacked_repr(SwigPyPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + return SWIG_Python_str_FromFormat("", result, v->ty->name); + } else { + return SWIG_Python_str_FromFormat("", v->ty->name); + } +} + +SWIGRUNTIME PyObject * +SwigPyPacked_str(SwigPyPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ + return SWIG_Python_str_FromFormat("%s%s", result, v->ty->name); + } else { + return SWIG_Python_str_FromChar(v->ty->name); + } +} + +SWIGRUNTIME int +SwigPyPacked_compare(SwigPyPacked *v, SwigPyPacked *w) +{ + size_t i = v->size; + size_t j = w->size; + int s = (i < j) ? -1 : ((i > j) ? 1 : 0); + return s ? s : strncmp((const char *)v->pack, (const char *)w->pack, 2*v->size); +} + +SWIGRUNTIME PyTypeObject* SwigPyPacked_TypeOnce(void); + +SWIGRUNTIME PyTypeObject* +SwigPyPacked_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyPacked_TypeOnce(); + return type; +} + +SWIGRUNTIMEINLINE int +SwigPyPacked_Check(PyObject *op) { + return ((op)->ob_type == SwigPyPacked_TypeOnce()) + || (strcmp((op)->ob_type->tp_name,"SwigPyPacked") == 0); +} + +SWIGRUNTIME void +SwigPyPacked_dealloc(PyObject *v) +{ + if (SwigPyPacked_Check(v)) { + SwigPyPacked *sobj = (SwigPyPacked *) v; + free(sobj->pack); + } + PyObject_DEL(v); +} + +SWIGRUNTIME PyTypeObject* +SwigPyPacked_TypeOnce(void) { + static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; + static PyTypeObject swigpypacked_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp = { +#if PY_VERSION_HEX>=0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "SwigPyPacked", /* tp_name */ + sizeof(SwigPyPacked), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SwigPyPacked_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ +#if PY_VERSION_HEX>=0x03000000 + 0, /* tp_reserved in 3.0.1 */ +#else + (cmpfunc)SwigPyPacked_compare, /* tp_compare */ +#endif + (reprfunc)SwigPyPacked_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)SwigPyPacked_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigpacked_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif +#if PY_VERSION_HEX >= 0x03080000 + 0, /* tp_vectorcall */ +#endif +#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000) + 0, /* tp_print */ +#endif +#ifdef COUNT_ALLOCS + 0, /* tp_allocs */ + 0, /* tp_frees */ + 0, /* tp_maxalloc */ + 0, /* tp_prev */ + 0 /* tp_next */ +#endif + }; + swigpypacked_type = tmp; + type_init = 1; + if (PyType_Ready(&swigpypacked_type) < 0) + return NULL; + } + return &swigpypacked_type; +} + +SWIGRUNTIME PyObject * +SwigPyPacked_New(void *ptr, size_t size, swig_type_info *ty) +{ + SwigPyPacked *sobj = PyObject_NEW(SwigPyPacked, SwigPyPacked_type()); + if (sobj) { + void *pack = malloc(size); + if (pack) { + memcpy(pack, ptr, size); + sobj->pack = pack; + sobj->ty = ty; + sobj->size = size; + } else { + PyObject_DEL((PyObject *) sobj); + sobj = 0; + } + } + return (PyObject *) sobj; +} + +SWIGRUNTIME swig_type_info * +SwigPyPacked_UnpackData(PyObject *obj, void *ptr, size_t size) +{ + if (SwigPyPacked_Check(obj)) { + SwigPyPacked *sobj = (SwigPyPacked *)obj; + if (sobj->size != size) return 0; + memcpy(ptr, sobj->pack, size); + return sobj->ty; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +static PyObject *Swig_This_global = NULL; + +SWIGRUNTIME PyObject * +SWIG_This(void) +{ + if (Swig_This_global == NULL) + Swig_This_global = SWIG_Python_str_FromChar("this"); + return Swig_This_global; +} + +/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ + +/* TODO: I don't know how to implement the fast getset in Python 3 right now */ +#if PY_VERSION_HEX>=0x03000000 +#define SWIG_PYTHON_SLOW_GETSET_THIS +#endif + +SWIGRUNTIME SwigPyObject * +SWIG_Python_GetSwigThis(PyObject *pyobj) +{ + PyObject *obj; + + if (SwigPyObject_Check(pyobj)) + return (SwigPyObject *) pyobj; + +#ifdef SWIGPYTHON_BUILTIN + (void)obj; +# ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + pyobj = PyWeakref_GET_OBJECT(pyobj); + if (pyobj && SwigPyObject_Check(pyobj)) + return (SwigPyObject*) pyobj; + } +# endif + return NULL; +#else + + obj = 0; + +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + if (PyInstance_Check(pyobj)) { + obj = _PyInstance_Lookup(pyobj, SWIG_This()); + } else { + PyObject **dictptr = _PyObject_GetDictPtr(pyobj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; + } else { +#ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); + return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; + } +#endif + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } + } + } +#else + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } +#endif + if (obj && !SwigPyObject_Check(obj)) { + /* a PyObject is called 'this', try to get the 'real this' + SwigPyObject from it */ + return SWIG_Python_GetSwigThis(obj); + } + return (SwigPyObject *)obj; +#endif +} + +/* Acquire a pointer value */ + +SWIGRUNTIME int +SWIG_Python_AcquirePtr(PyObject *obj, int own) { + if (own == SWIG_POINTER_OWN) { + SwigPyObject *sobj = SWIG_Python_GetSwigThis(obj); + if (sobj) { + int oldown = sobj->own; + sobj->own = own; + return oldown; + } + } + return 0; +} + +/* Convert a pointer value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { + int res; + SwigPyObject *sobj; + int implicit_conv = (flags & SWIG_POINTER_IMPLICIT_CONV) != 0; + + if (!obj) + return SWIG_ERROR; + if (obj == Py_None && !implicit_conv) { + if (ptr) + *ptr = 0; + return (flags & SWIG_POINTER_NO_NULL) ? SWIG_NullReferenceError : SWIG_OK; + } + + res = SWIG_ERROR; + + sobj = SWIG_Python_GetSwigThis(obj); + if (own) + *own = 0; + while (sobj) { + void *vptr = sobj->ptr; + if (ty) { + swig_type_info *to = sobj->ty; + if (to == ty) { + /* no type cast needed */ + if (ptr) *ptr = vptr; + break; + } else { + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) { + sobj = (SwigPyObject *)sobj->next; + } else { + if (ptr) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + if (newmemory == SWIG_CAST_NEW_MEMORY) { + assert(own); /* badly formed typemap which will lead to a memory leak - it must set and use own to delete *ptr */ + if (own) + *own = *own | SWIG_CAST_NEW_MEMORY; + } + } + break; + } + } + } else { + if (ptr) *ptr = vptr; + break; + } + } + if (sobj) { + if (own) + *own = *own | sobj->own; + if (flags & SWIG_POINTER_DISOWN) { + sobj->own = 0; + } + res = SWIG_OK; + } else { + if (implicit_conv) { + SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; + if (data && !data->implicitconv) { + PyObject *klass = data->klass; + if (klass) { + PyObject *impconv; + data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ + impconv = SWIG_Python_CallFunctor(klass, obj); + data->implicitconv = 0; + if (PyErr_Occurred()) { + PyErr_Clear(); + impconv = 0; + } + if (impconv) { + SwigPyObject *iobj = SWIG_Python_GetSwigThis(impconv); + if (iobj) { + void *vptr; + res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); + if (SWIG_IsOK(res)) { + if (ptr) { + *ptr = vptr; + /* transfer the ownership to 'ptr' */ + iobj->own = 0; + res = SWIG_AddCast(res); + res = SWIG_AddNewMask(res); + } else { + res = SWIG_AddCast(res); + } + } + } + Py_DECREF(impconv); + } + } + } + if (!SWIG_IsOK(res) && obj == Py_None) { + if (ptr) + *ptr = 0; + if (PyErr_Occurred()) + PyErr_Clear(); + res = SWIG_OK; + } + } + } + return res; +} + +/* Convert a function ptr value */ + +SWIGRUNTIME int +SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { + if (!PyCFunction_Check(obj)) { + return SWIG_ConvertPtr(obj, ptr, ty, 0); + } else { + void *vptr = 0; + swig_cast_info *tc; + + /* here we get the method pointer for callbacks */ + const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); + const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; + if (desc) + desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; + if (!desc) + return SWIG_ERROR; + tc = SWIG_TypeCheck(desc,ty); + if (tc) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + assert(!newmemory); /* newmemory handling not yet implemented */ + } else { + return SWIG_ERROR; + } + return SWIG_OK; + } +} + +/* Convert a packed pointer value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { + swig_type_info *to = SwigPyPacked_UnpackData(obj, ptr, sz); + if (!to) return SWIG_ERROR; + if (ty) { + if (to != ty) { + /* check type cast? */ + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) return SWIG_ERROR; + } + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Create a new pointer object + * ----------------------------------------------------------------------------- */ + +/* + Create a new instance object, without calling __init__, and set the + 'this' attribute. +*/ + +SWIGRUNTIME PyObject* +SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this) +{ + PyObject *inst = 0; + PyObject *newraw = data->newraw; + if (newraw) { + inst = PyObject_Call(newraw, data->newargs, NULL); + if (inst) { +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + PyDict_SetItem(dict, SWIG_This(), swig_this); + } + } +#else + if (PyObject_SetAttr(inst, SWIG_This(), swig_this) == -1) { + Py_DECREF(inst); + inst = 0; + } +#endif + } + } else { +#if PY_VERSION_HEX >= 0x03000000 + PyObject *empty_args = PyTuple_New(0); + if (empty_args) { + PyObject *empty_kwargs = PyDict_New(); + if (empty_kwargs) { + inst = ((PyTypeObject *)data->newargs)->tp_new((PyTypeObject *)data->newargs, empty_args, empty_kwargs); + Py_DECREF(empty_kwargs); + if (inst) { + if (PyObject_SetAttr(inst, SWIG_This(), swig_this) == -1) { + Py_DECREF(inst); + inst = 0; + } else { + Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; + } + } + } + Py_DECREF(empty_args); + } +#else + PyObject *dict = PyDict_New(); + if (dict) { + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + } +#endif + } + return inst; +} + +SWIGRUNTIME int +SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) +{ +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + } + return PyDict_SetItem(dict, SWIG_This(), swig_this); + } +#endif + return PyObject_SetAttr(inst, SWIG_This(), swig_this); +} + + +SWIGINTERN PyObject * +SWIG_Python_InitShadowInstance(PyObject *args) { + PyObject *obj[2]; + if (!SWIG_Python_UnpackTuple(args, "swiginit", 2, 2, obj)) { + return NULL; + } else { + SwigPyObject *sthis = SWIG_Python_GetSwigThis(obj[0]); + if (sthis) { + SwigPyObject_append((PyObject*) sthis, obj[1]); + } else { + if (SWIG_Python_SetSwigThis(obj[0], obj[1]) != 0) + return NULL; + } + return SWIG_Py_Void(); + } +} + +/* Create a new pointer object */ + +SWIGRUNTIME PyObject * +SWIG_Python_NewPointerObj(PyObject *self, void *ptr, swig_type_info *type, int flags) { + SwigPyClientData *clientdata; + PyObject * robj; + int own; + + if (!ptr) + return SWIG_Py_Void(); + + clientdata = type ? (SwigPyClientData *)(type->clientdata) : 0; + own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; + if (clientdata && clientdata->pytype) { + SwigPyObject *newobj; + if (flags & SWIG_BUILTIN_TP_INIT) { + newobj = (SwigPyObject*) self; + if (newobj->ptr) { + PyObject *next_self = clientdata->pytype->tp_alloc(clientdata->pytype, 0); + while (newobj->next) + newobj = (SwigPyObject *) newobj->next; + newobj->next = next_self; + newobj = (SwigPyObject *)next_self; +#ifdef SWIGPYTHON_BUILTIN + newobj->dict = 0; +#endif + } + } else { + newobj = PyObject_New(SwigPyObject, clientdata->pytype); +#ifdef SWIGPYTHON_BUILTIN + newobj->dict = 0; +#endif + } + if (newobj) { + newobj->ptr = ptr; + newobj->ty = type; + newobj->own = own; + newobj->next = 0; + return (PyObject*) newobj; + } + return SWIG_Py_Void(); + } + + assert(!(flags & SWIG_BUILTIN_TP_INIT)); + + robj = SwigPyObject_New(ptr, type, own); + if (robj && clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { + PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); + Py_DECREF(robj); + robj = inst; + } + return robj; +} + +/* Create a new packed object */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { + return ptr ? SwigPyPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); +} + +/* -----------------------------------------------------------------------------* + * Get type list + * -----------------------------------------------------------------------------*/ + +#ifdef SWIG_LINK_RUNTIME +void *SWIG_ReturnGlobalTypeList(void *); +#endif + +SWIGRUNTIME swig_module_info * +SWIG_Python_GetModule(void *SWIGUNUSEDPARM(clientdata)) { + static void *type_pointer = (void *)0; + /* first check if module already created */ + if (!type_pointer) { +#ifdef SWIG_LINK_RUNTIME + type_pointer = SWIG_ReturnGlobalTypeList((void *)0); +#else + type_pointer = PyCapsule_Import(SWIGPY_CAPSULE_NAME, 0); + if (PyErr_Occurred()) { + PyErr_Clear(); + type_pointer = (void *)0; + } +#endif + } + return (swig_module_info *) type_pointer; +} + +SWIGRUNTIME void +SWIG_Python_DestroyModule(PyObject *obj) +{ + swig_module_info *swig_module = (swig_module_info *) PyCapsule_GetPointer(obj, SWIGPY_CAPSULE_NAME); + swig_type_info **types = swig_module->types; + size_t i; + for (i =0; i < swig_module->size; ++i) { + swig_type_info *ty = types[i]; + if (ty->owndata) { + SwigPyClientData *data = (SwigPyClientData *) ty->clientdata; + if (data) SwigPyClientData_Del(data); + } + } + Py_DECREF(SWIG_This()); + Swig_This_global = NULL; +} + +SWIGRUNTIME void +SWIG_Python_SetModule(swig_module_info *swig_module) { +#if PY_VERSION_HEX >= 0x03000000 + /* Add a dummy module object into sys.modules */ + PyObject *module = PyImport_AddModule("swig_runtime_data" SWIG_RUNTIME_VERSION); +#else + static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} }; /* Sentinel */ + PyObject *module = Py_InitModule("swig_runtime_data" SWIG_RUNTIME_VERSION, swig_empty_runtime_method_table); +#endif + PyObject *pointer = PyCapsule_New((void *) swig_module, SWIGPY_CAPSULE_NAME, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, "type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +} + +/* The python cached type query */ +SWIGRUNTIME PyObject * +SWIG_Python_TypeCache(void) { + static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); + return cache; +} + +SWIGRUNTIME swig_type_info * +SWIG_Python_TypeQuery(const char *type) +{ + PyObject *cache = SWIG_Python_TypeCache(); + PyObject *key = SWIG_Python_str_FromChar(type); + PyObject *obj = PyDict_GetItem(cache, key); + swig_type_info *descriptor; + if (obj) { + descriptor = (swig_type_info *) PyCapsule_GetPointer(obj, NULL); + } else { + swig_module_info *swig_module = SWIG_GetModule(0); + descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); + if (descriptor) { + obj = PyCapsule_New((void*) descriptor, NULL, NULL); + PyDict_SetItem(cache, key, obj); + Py_DECREF(obj); + } + } + Py_DECREF(key); + return descriptor; +} + +/* + For backward compatibility only +*/ +#define SWIG_POINTER_EXCEPTION 0 +#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) +#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) + +SWIGRUNTIME int +SWIG_Python_AddErrMesg(const char* mesg, int infront) +{ + if (PyErr_Occurred()) { + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + const char *tmp = SWIG_Python_str_AsChar(old_str); + const char *errmesg = tmp ? tmp : "Invalid error message"; + Py_XINCREF(type); + PyErr_Clear(); + if (infront) { + PyErr_Format(type, "%s %s", mesg, errmesg); + } else { + PyErr_Format(type, "%s %s", errmesg, mesg); + } + SWIG_Python_str_DelForPy3(tmp); + Py_DECREF(old_str); + } + return 1; + } else { + return 0; + } +} + +SWIGRUNTIME int +SWIG_Python_ArgFail(int argnum) +{ + if (PyErr_Occurred()) { + /* add information about failing argument */ + char mesg[256]; + PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); + return SWIG_Python_AddErrMesg(mesg, 1); + } else { + return 0; + } +} + +SWIGRUNTIMEINLINE const char * +SwigPyObject_GetDesc(PyObject *self) +{ + SwigPyObject *v = (SwigPyObject *)self; + swig_type_info *ty = v ? v->ty : 0; + return ty ? ty->str : ""; +} + +SWIGRUNTIME void +SWIG_Python_TypeError(const char *type, PyObject *obj) +{ + if (type) { +#if defined(SWIG_COBJECT_TYPES) + if (obj && SwigPyObject_Check(obj)) { + const char *otype = (const char *) SwigPyObject_GetDesc(obj); + if (otype) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'SwigPyObject(%s)' is received", + type, otype); + return; + } + } else +#endif + { + const char *otype = (obj ? obj->ob_type->tp_name : 0); + if (otype) { + PyObject *str = PyObject_Str(obj); + const char *cstr = str ? SWIG_Python_str_AsChar(str) : 0; + if (cstr) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", + type, otype, cstr); + SWIG_Python_str_DelForPy3(cstr); + } else { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", + type, otype); + } + Py_XDECREF(str); + return; + } + } + PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); + } else { + PyErr_Format(PyExc_TypeError, "unexpected type is received"); + } +} + + +/* Convert a pointer value, signal an exception on a type mismatch */ +SWIGRUNTIME void * +SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int SWIGUNUSEDPARM(argnum), int flags) { + void *result; + if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { + PyErr_Clear(); +#if SWIG_POINTER_EXCEPTION + if (flags) { + SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); + SWIG_Python_ArgFail(argnum); + } +#endif + } + return result; +} + +#ifdef SWIGPYTHON_BUILTIN +SWIGRUNTIME int +SWIG_Python_NonDynamicSetAttr(PyObject *obj, PyObject *name, PyObject *value) { + PyTypeObject *tp = obj->ob_type; + PyObject *descr; + PyObject *encoded_name; + descrsetfunc f; + int res = -1; + +# ifdef Py_USING_UNICODE + if (PyString_Check(name)) { + name = PyUnicode_Decode(PyString_AsString(name), PyString_Size(name), NULL, NULL); + if (!name) + return -1; + } else if (!PyUnicode_Check(name)) +# else + if (!PyString_Check(name)) +# endif + { + PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", name->ob_type->tp_name); + return -1; + } else { + Py_INCREF(name); + } + + if (!tp->tp_dict) { + if (PyType_Ready(tp) < 0) + goto done; + } + + descr = _PyType_Lookup(tp, name); + f = NULL; + if (descr != NULL) + f = descr->ob_type->tp_descr_set; + if (!f) { + if (PyString_Check(name)) { + encoded_name = name; + Py_INCREF(name); + } else { + encoded_name = PyUnicode_AsUTF8String(name); + if (!encoded_name) + return -1; + } + PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_name)); + Py_DECREF(encoded_name); + } else { + res = f(descr, obj, value); + } + + done: + Py_DECREF(name); + return res; +} +#endif + + +#ifdef __cplusplus +} +#endif +/* -----------------------------------------------------------------------------* + Standard SWIG API for use inside user code. + + Don't include this file directly, run the command + swig -python -external-runtime + Also, read the Modules chapter of the SWIG Manual. + + * -----------------------------------------------------------------------------*/ + +#ifdef SWIG_MODULE_CLIENTDATA_TYPE + +SWIGRUNTIMEINLINE swig_type_info * +SWIG_TypeQuery(SWIG_MODULE_CLIENTDATA_TYPE clientdata, const char *name) { + swig_module_info *module = SWIG_GetModule(clientdata); + return SWIG_TypeQueryModule(module, module, name); +} + +SWIGRUNTIMEINLINE swig_type_info * +SWIG_MangledTypeQuery(SWIG_MODULE_CLIENTDATA_TYPE clientdata, const char *name) { + swig_module_info *module = SWIG_GetModule(clientdata); + return SWIG_MangledTypeQueryModule(module, module, name); +} + +#else + +SWIGRUNTIMEINLINE swig_type_info * +SWIG_TypeQuery(const char *name) { + swig_module_info *module = SWIG_GetModule(NULL); + return SWIG_TypeQueryModule(module, module, name); +} + +SWIGRUNTIMEINLINE swig_type_info * +SWIG_MangledTypeQuery(const char *name) { + swig_module_info *module = SWIG_GetModule(NULL); + return SWIG_MangledTypeQueryModule(module, module, name); +} + +#endif diff --git a/Modules/QtPython/QmitkCtkPythonShell.cpp b/Modules/QtPython/QmitkCtkPythonShell.cpp index ebdbbf36d8..18ac980cc4 100644 --- a/Modules/QtPython/QmitkCtkPythonShell.cpp +++ b/Modules/QtPython/QmitkCtkPythonShell.cpp @@ -1,94 +1,94 @@ /*============================================================================ 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 "QmitkCtkPythonShell.h" #include #include #include #include #include #include "mitkIPythonService.h" #include #include #include struct QmitkCtkPythonShellData { mitk::IPythonService* m_PythonService; us::ServiceReference m_PythonServiceRef; }; QmitkCtkPythonShell::QmitkCtkPythonShell(QWidget* parent) : ctkPythonConsole(parent), d( new QmitkCtkPythonShellData ) { this->setWelcomeTextColor(Qt::green); this->setPromptColor(Qt::gray); this->setStdinTextColor(Qt::white); this->setCommandTextColor(Qt::white); this->setOutputTextColor(Qt::white); MITK_DEBUG("QmitkCtkPythonShell") << "retrieving IPythonService"; us::ModuleContext* context = us::GetModuleContext(); d->m_PythonServiceRef = context->GetServiceReference(); d->m_PythonService = dynamic_cast ( context->GetService(d->m_PythonServiceRef) ); MITK_DEBUG("QmitkCtkPythonShell") << "checking IPythonService"; Q_ASSERT( d->m_PythonService ); MITK_DEBUG("QmitkCtkPythonShell") << "initialize m_PythonService"; - this->initialize( d->m_PythonService->GetPythonManager() ); + //this->initialize( d->m_PythonService->GetPythonManager() ); MITK_DEBUG("QmitkCtkPythonShell") << "m_PythonService initialized"; mitk::IPythonService::ForceLoadModule(); } QmitkCtkPythonShell::~QmitkCtkPythonShell() { us::ModuleContext* context = us::GetModuleContext(); context->UngetService( d->m_PythonServiceRef ); delete d; } void QmitkCtkPythonShell::dragEnterEvent(QDragEnterEvent *event) { event->accept(); } void QmitkCtkPythonShell::dropEvent(QDropEvent *event) { QList urls = event->mimeData()->urls(); for(int i = 0; i < urls.size(); i++) { d->m_PythonService->Execute( urls[i].toString().toStdString(), mitk::IPythonService::SINGLE_LINE_COMMAND ); } } bool QmitkCtkPythonShell::canInsertFromMimeData(const QMimeData *) const { return true; } void QmitkCtkPythonShell::executeCommand(const QString& command) { MITK_DEBUG("QmitkCtkPythonShell") << "executing command " << command.toStdString(); d->m_PythonService->Execute(command.toStdString(),mitk::IPythonService::MULTI_LINE_COMMAND); d->m_PythonService->NotifyObserver(command.toStdString()); } void QmitkCtkPythonShell::Paste(const QString &command) { if( this->isVisible() ) { this->exec( command ); //this->executeCommand( command ); } } diff --git a/Modules/QtPython/Testing/CMakeLists.txt b/Modules/QtPython/Testing/CMakeLists.txt index e9cde47bc8..bca7958889 100644 --- a/Modules/QtPython/Testing/CMakeLists.txt +++ b/Modules/QtPython/Testing/CMakeLists.txt @@ -1,19 +1,19 @@ set(package_deps PACKAGE_DEPENDS PRIVATE) MITK_CREATE_MODULE_TESTS(${package_deps}) if(UNIX AND NOT APPLE) #[[ The PythonQt library (dependency of MitkQtPython module) depends on Qt libraries without absolute paths. Use LD_LIBRARY_PATH as workaround. See T26955. ]] if(TARGET ${TESTDRIVER}) get_target_property(ld_library_path Qt5::Core IMPORTED_LOCATION_RELEASE) get_filename_component(ld_library_path "${ld_library_path}" DIRECTORY) add_test( NAME mitkPythonTest COMMAND ${CMAKE_COMMAND} -E env "LD_LIBRARY_PATH=${ld_library_path}" - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPythonTest + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPythonConsoleTest ) endif() endif() diff --git a/Modules/QtPython/Testing/files.cmake b/Modules/QtPython/Testing/files.cmake index 2be97879a7..9f32bcc809 100644 --- a/Modules/QtPython/Testing/files.cmake +++ b/Modules/QtPython/Testing/files.cmake @@ -1,10 +1,10 @@ if(UNIX AND NOT APPLE) # See T26955. set(MODULE_CUSTOM_TESTS - mitkPythonTest.cpp + mitkPythonConsoleTest.cpp ) else() set(MODULE_TESTS - mitkPythonTest.cpp + mitkPythonConsoleTest.cpp ) endif() diff --git a/Modules/QtPython/Testing/mitkPythonTest.cpp b/Modules/QtPython/Testing/mitkPythonConsoleTest.cpp similarity index 89% rename from Modules/QtPython/Testing/mitkPythonTest.cpp rename to Modules/QtPython/Testing/mitkPythonConsoleTest.cpp index 762a8f3a18..c92ea15d72 100644 --- a/Modules/QtPython/Testing/mitkPythonTest.cpp +++ b/Modules/QtPython/Testing/mitkPythonConsoleTest.cpp @@ -1,43 +1,43 @@ /*============================================================================ 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 +class mitkPythonConsoleTestSuite : public mitk::TestFixture { - CPPUNIT_TEST_SUITE(mitkPythonTestSuite); + CPPUNIT_TEST_SUITE(mitkPythonConsoleTestSuite); MITK_TEST(TestPython); CPPUNIT_TEST_SUITE_END(); public: void TestPython() { us::ModuleContext* context = us::GetModuleContext(); us::ServiceReference m_PythonServiceRef = context->GetServiceReference(); mitk::IPythonService* m_PythonService = dynamic_cast ( context->GetService(m_PythonServiceRef) ); mitk::IPythonService::ForceLoadModule(); std::string result = m_PythonService->Execute( "5+5", mitk::IPythonService::EVAL_COMMAND ); MITK_TEST_CONDITION( result == "10", "Testing if running python code 5+5 results in 10" ); } }; -MITK_TEST_SUITE_REGISTRATION(mitkPython) +MITK_TEST_SUITE_REGISTRATION(mitkPythonConsole) diff --git a/Modules/Python/autoload/PythonService/CMakeLists.txt b/Modules/QtPythonService/CMakeLists.txt similarity index 78% rename from Modules/Python/autoload/PythonService/CMakeLists.txt rename to Modules/QtPythonService/CMakeLists.txt index 57455c3863..bf9eed9014 100644 --- a/Modules/Python/autoload/PythonService/CMakeLists.txt +++ b/Modules/QtPythonService/CMakeLists.txt @@ -1,15 +1,15 @@ mitkFunctionCheckCompilerFlags("-Wno-cpp" CMAKE_CXX_FLAGS) -mitk_create_module(PythonService +mitk_create_module(QtPythonService INCLUDE_DIRS - PRIVATE src/PythonService + PRIVATE src/QtPythonService DEPENDS PUBLIC MitkPython PACKAGE_DEPENDS PUBLIC Qt5|Widgets CTK|CTKScriptingPythonCore+CTKScriptingPythonWidgets - AUTOLOAD_WITH MitkPython + AUTOLOAD_WITH MitkPython ) if(TARGET ${MODULE_TARGET}) target_link_libraries(${MODULE_TARGET} PUBLIC Python3::NumPy) configure_file(PythonPath.h.in "${CMAKE_CURRENT_BINARY_DIR}/PythonPath.h" @ONLY) -endif() +endif() \ No newline at end of file diff --git a/Modules/Python/autoload/PythonService/PythonPath.h.in b/Modules/QtPythonService/PythonPath.h.in similarity index 100% rename from Modules/Python/autoload/PythonService/PythonPath.h.in rename to Modules/QtPythonService/PythonPath.h.in diff --git a/Modules/QtPythonService/files.cmake b/Modules/QtPythonService/files.cmake new file mode 100644 index 0000000000..66e7471410 --- /dev/null +++ b/Modules/QtPythonService/files.cmake @@ -0,0 +1,4 @@ +set(CPP_FILES + mitkQtPythonService.cpp + mitkQtPythonActivator.cpp +) diff --git a/Modules/Python/autoload/PythonService/mitkPythonActivator.cpp b/Modules/QtPythonService/mitkQtPythonActivator.cpp similarity index 51% rename from Modules/Python/autoload/PythonService/mitkPythonActivator.cpp rename to Modules/QtPythonService/mitkQtPythonActivator.cpp index d58ba5cf27..84bd97a9b4 100644 --- a/Modules/Python/autoload/PythonService/mitkPythonActivator.cpp +++ b/Modules/QtPythonService/mitkQtPythonActivator.cpp @@ -1,63 +1,64 @@ /*============================================================================ 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 mitkPythonActivator_h -#define mitkPythonActivator_h +#ifndef mitkQtPythonActivator_h +#define mitkQtPythonActivator_h // Microservices #include #include "usModuleContext.h" -#include "mitkPythonService.h" +#include "mitkQtPythonService.h" #include namespace mitk { /// /// installs the PythonService /// runs all initial commands (setting env paths etc) /// - class PythonActivator : public us::ModuleActivator + class QtPythonActivator : public us::ModuleActivator { public: void Load(us::ModuleContext* context) override { - MITK_DEBUG << "PythonActivator::Load"; - // Registering PythonService as MicroService - m_PythonService = itk::SmartPointer(new PythonService()); + MITK_DEBUG << "QtPythonActivator::Load"; + //Registering QtPythonService as MicroService + m_PythonService = itk::SmartPointer(new QtPythonService()); us::ServiceProperties _PythonServiceProps; - _PythonServiceProps["Name"] = std::string("PythonService"); + _PythonServiceProps["Name"] = std::string("QtPythonService"); + _PythonServiceProps["service.ranking"] = int(1); m_PythonServiceRegistration = context->RegisterService(m_PythonService.GetPointer(), _PythonServiceProps); } void Unload(us::ModuleContext*) override { - MITK_DEBUG("PythonActivator") << "PythonActivator::Unload"; - MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); + MITK_DEBUG("QtPythonActivator") << "QtPythonActivator::Unload"; + MITK_DEBUG("QtPythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); m_PythonServiceRegistration.Unregister(); m_PythonService->Delete(); - MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); + MITK_DEBUG("QtPythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); } - ~PythonActivator() override + ~QtPythonActivator() override { } private: - itk::SmartPointer m_PythonService; - us::ServiceRegistration m_PythonServiceRegistration; + itk::SmartPointer m_PythonService; + us::ServiceRegistration m_PythonServiceRegistration; }; } -US_EXPORT_MODULE_ACTIVATOR(mitk::PythonActivator) +US_EXPORT_MODULE_ACTIVATOR(mitk::QtPythonActivator) #endif diff --git a/Modules/Python/autoload/PythonService/mitkPythonService.cpp b/Modules/QtPythonService/mitkQtPythonService.cpp similarity index 86% rename from Modules/Python/autoload/PythonService/mitkPythonService.cpp rename to Modules/QtPythonService/mitkQtPythonService.cpp index 4dd7ae1c18..30bbc08488 100644 --- a/Modules/Python/autoload/PythonService/mitkPythonService.cpp +++ b/Modules/QtPythonService/mitkQtPythonService.cpp @@ -1,917 +1,943 @@ /*============================================================================ 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 "mitkQtPythonService.h" #include #include #include #include #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 typedef itksys::SystemTools ist; -mitk::PythonService::PythonService() +mitk::QtPythonService::QtPythonService() : m_ItkWrappingAvailable( true ) , m_OpenCVWrappingAvailable( true ) , m_VtkWrappingAvailable( true ) , m_ErrorOccured( false ) { + m_PythonManager = new ctkAbstractPythonManager(); bool pythonInitialized = static_cast( Py_IsInitialized() ); //m_PythonManager.isPythonInitialized() ); // due to strange static var behaviour on windows Py_IsInitialized() returns correct value while // m_PythonManager.isPythonInitialized() does not because it has been constructed and destructed again if( !pythonInitialized ) { MITK_INFO << "Initializing python service"; //TODO a better way to do this #ifndef WIN32 dlerror(); if(dlopen(PYTHON_LIBRARY, RTLD_NOW | RTLD_GLOBAL) == nullptr ) { mitkThrow() << "Python runtime could not be loaded: " << dlerror(); } #endif std::string programPath = QCoreApplication::applicationDirPath().toStdString() + "/"; - QString pythonCommand; pythonCommand.append( QString("import site, sys\n") ); pythonCommand.append( QString("import SimpleITK as sitk\n") ); pythonCommand.append( QString("import SimpleITK._SimpleITK as _SimpleITK\n") ); pythonCommand.append( QString("import numpy\n") ); pythonCommand.append( QString("sys.path.append('')\n") ); pythonCommand.append( QString("sys.path.append('%1')\n").arg(programPath.c_str()) ); pythonCommand.append( QString("sys.path.append('%1')\n").arg(EXTERNAL_DIST_PACKAGES) ); pythonCommand.append( QString("\nsite.addsitedir('%1')").arg(EXTERNAL_SITE_PACKAGES) ); - if( pythonInitialized ) - m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut|PythonQt::PythonAlreadyInitialized); - else - m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut); - m_PythonManager.initialize(); + //if( pythonInitialized ) + // m_PythonManager->setInitializationFlags(PythonQt::RedirectStdOut|PythonQt::PythonAlreadyInitialized); + //else + // m_PythonManager->setInitializationFlags(PythonQt::RedirectStdOut); + + if (pythonInitialized) + m_PythonManager->setInitializationFlags(PythonQt::PythonAlreadyInitialized); - m_PythonManager.executeString( pythonCommand, ctkAbstractPythonManager::FileInput ); + m_PythonManager->initialize(); + + m_PythonManager->executeString( pythonCommand, ctkAbstractPythonManager::FileInput ); } + std::string programPath = QCoreApplication::applicationDirPath().toStdString() + "/"; + MITK_INFO << programPath; } -mitk::PythonService::~PythonService() +mitk::QtPythonService::~QtPythonService() { - MITK_DEBUG("mitk::PythonService") << "destructing PythonService"; + MITK_DEBUG("mitk::QtPythonService") << "destructing QtPythonService"; } -void mitk::PythonService::AddRelativeSearchDirs(std::vector< std::string > dirs) +void mitk::QtPythonService::AddRelativeSearchDirs(std::vector< std::string > dirs) { std::string programPath = QCoreApplication::applicationDirPath().toStdString() + "/"; std::string cwd = ist::GetCurrentWorkingDirectory() + "/"; for (auto dir : dirs) { - m_PythonManager.executeString(QString("sys.path.append('%1')").arg((programPath + dir).c_str()), ctkAbstractPythonManager::SingleInput ); - m_PythonManager.executeString(QString("sys.path.append('%1')").arg((cwd + dir).c_str()), ctkAbstractPythonManager::SingleInput ); + m_PythonManager->executeString(QString("sys.path.append('%1')").arg((programPath + dir).c_str()), ctkAbstractPythonManager::SingleInput ); + m_PythonManager->executeString(QString("sys.path.append('%1')").arg((cwd + dir).c_str()), ctkAbstractPythonManager::SingleInput ); } } -void mitk::PythonService::AddAbsoluteSearchDirs(std::vector< std::string > dirs) +void mitk::QtPythonService::AddAbsoluteSearchDirs(std::vector< std::string > dirs) { for (auto dir : dirs) { - m_PythonManager.executeString(QString("sys.path.append('%1')").arg(dir.c_str()), ctkAbstractPythonManager::SingleInput ); + m_PythonManager->executeString(QString("sys.path.append('%1')").arg(dir.c_str()), ctkAbstractPythonManager::SingleInput ); } } -std::string mitk::PythonService::Execute(const std::string &stdpythonCommand, int commandType) +std::string mitk::QtPythonService::Execute(const std::string &stdpythonCommand, + int commandType) { QString pythonCommand = QString::fromStdString(stdpythonCommand); QVariant result; - + PyGILState_STATE gState = PyGILState_Ensure(); bool commandIssued = true; if(commandType == IPythonService::SINGLE_LINE_COMMAND ) - result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::SingleInput ); + result = m_PythonManager->executeString(pythonCommand, ctkAbstractPythonManager::SingleInput ); else if(commandType == IPythonService::MULTI_LINE_COMMAND ) - result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::FileInput ); + result = m_PythonManager->executeString(pythonCommand, ctkAbstractPythonManager::FileInput ); else if(commandType == IPythonService::EVAL_COMMAND ) - result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::EvalInput ); + result = m_PythonManager->executeString(pythonCommand, ctkAbstractPythonManager::EvalInput ); else commandIssued = false; if(commandIssued) { this->NotifyObserver(pythonCommand.toStdString()); m_ErrorOccured = PythonQt::self()->hadError(); } return result.toString().toStdString(); } -void mitk::PythonService::ExecuteScript( const std::string& pythonScript ) +void mitk::QtPythonService::ExecuteScript(const std::string &pythonScript) { std::ifstream t(pythonScript.c_str()); std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); t.close(); - m_PythonManager.executeString(QString::fromStdString(str)); + m_PythonManager->executeString(QString::fromStdString(str)); } -std::vector mitk::PythonService::GetVariableStack() const +std::vector mitk::QtPythonService::GetVariableStack() { std::vector list; PyObject* dict = PyImport_GetModuleDict(); PyObject* object = PyDict_GetItemString(dict, "__main__"); PyObject* dirMain = PyObject_Dir(object); PyObject* tempObject = nullptr; //PyObject* strTempObject = 0; if(dirMain) { std::string name, attrValue, attrType; for(int i = 0; iob_type->tp_name; if(tempObject && ( PyUnicode_Check(tempObject) || PyString_Check(tempObject) ) ) attrValue = PyString_AsString(tempObject); else attrValue = ""; mitk::PythonVariable var; var.m_Name = name; var.m_Value = attrValue; var.m_Type = attrType; list.push_back(var); } } return list; } -std::string mitk::PythonService::GetVariable(const std::string& name) const +std::string mitk::QtPythonService::GetVariable(const std::string& name) { std::vector allVars = this->GetVariableStack(); 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) const +bool mitk::QtPythonService::DoesVariableExist(const std::string& name) { bool varExists = false; std::vector allVars = this->GetVariableStack(); 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) +void mitk::QtPythonService::AddPythonCommandObserver(mitk::PythonCommandObserver *observer) { if(!m_Observer.contains(observer)) m_Observer.append(observer); } -void mitk::PythonService::RemovePythonCommandObserver(mitk::PythonCommandObserver *observer) +void mitk::QtPythonService::RemovePythonCommandObserver(mitk::PythonCommandObserver *observer) { m_Observer.removeOne(observer); } -void mitk::PythonService::NotifyObserver(const std::string &command) +void mitk::QtPythonService::NotifyObserver(const std::string &command) { - MITK_DEBUG("mitk::PythonService") << "number of observer " << m_Observer.size(); + MITK_DEBUG("mitk::QtPythonService") << "number of observer " << m_Observer.size(); for( int i=0; i< m_Observer.size(); ++i ) { m_Observer.at(i)->CommandExecuted(command); } } -bool mitk::PythonService::CopyToPythonAsSimpleItkImage(mitk::Image *image, const std::string &stdvarName) +int mitk::QtPythonService::GetNumberOfObserver() +{ + return m_Observer.size(); +} + +bool mitk::QtPythonService::CopyToPythonAsSimpleItkImage(mitk::Image::Pointer image, const std::string &stdvarName) { QString varName = QString::fromStdString( stdvarName ); QString command; unsigned int* imgDim = image->GetDimensions(); int npy_nd = 1; // access python module PyObject *pyMod = PyImport_AddModule("__main__"); // global dictionary PyObject *pyDict = PyModule_GetDict(pyMod); const mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); const mitk::Point3D origin = image->GetGeometry()->GetOrigin(); mitk::PixelType pixelType = image->GetPixelType(); itk::ImageIOBase::IOPixelType ioPixelType = image->GetPixelType().GetPixelType(); PyObject* npyArray = nullptr; mitk::ImageReadAccessor racc(image); void* array = const_cast(racc.GetData()); mitk::Vector3D xDirection; mitk::Vector3D yDirection; mitk::Vector3D zDirection; const vnl_matrix_fixed &transform = image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); mitk::Vector3D s = image->GetGeometry()->GetSpacing(); // ToDo: Check if this is a collumn or row vector from the matrix. // right now it works but not sure for rotated geometries mitk::FillVector3D(xDirection, transform[0][0]/s[0], transform[0][1]/s[1], transform[0][2]/s[2]); mitk::FillVector3D(yDirection, transform[1][0]/s[0], transform[1][1]/s[1], transform[1][2]/s[2]); mitk::FillVector3D(zDirection, transform[2][0]/s[0], transform[2][1]/s[1], transform[2][2]/s[2]); // save the total number of elements here (since the numpy array is one dimensional) npy_intp* npy_dims = new npy_intp[1]; npy_dims[0] = imgDim[0]; /** * Build a string in the format [1024,1028,1] * to describe the dimensionality. This is needed for simple itk * to know the dimensions of the image */ QString dimensionString; dimensionString.append(QString("[")); dimensionString.append(QString::number(imgDim[0])); for (unsigned i = 1; i < 3; ++i) // always three because otherwise the 3d-geometry gets destroyed // (relevant for backtransformation of simple itk image to mitk. { dimensionString.append(QString(",")); dimensionString.append(QString::number(imgDim[i])); npy_dims[0] *= imgDim[i]; } dimensionString.append("]"); // the next line is necessary for vectorimages npy_dims[0] *= pixelType.GetNumberOfComponents(); // default pixeltype: unsigned short NPY_TYPES npy_type = NPY_USHORT; std::string sitk_type = "sitkUInt8"; if( ioPixelType == itk::ImageIOBase::SCALAR ) { if( pixelType.GetComponentType() == itk::ImageIOBase::DOUBLE ) { npy_type = NPY_DOUBLE; sitk_type = "sitkFloat64"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::FLOAT ) { npy_type = NPY_FLOAT; sitk_type = "sitkFloat32"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::SHORT) { npy_type = NPY_SHORT; sitk_type = "sitkInt16"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::CHAR ) { npy_type = NPY_BYTE; sitk_type = "sitkInt8"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::INT ) { npy_type = NPY_INT; sitk_type = "sitkInt32"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::LONG ) { npy_type = NPY_LONG; sitk_type = "sitkInt64"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::UCHAR ) { npy_type = NPY_UBYTE; sitk_type = "sitkUInt8"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::UINT ) { npy_type = NPY_UINT; sitk_type = "sitkUInt32"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::ULONG ) { npy_type = NPY_LONG; sitk_type = "sitkUInt64"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::USHORT ) { npy_type = NPY_USHORT; sitk_type = "sitkUInt16"; } } else if ( ioPixelType == itk::ImageIOBase::VECTOR || ioPixelType == itk::ImageIOBase::RGB || ioPixelType == itk::ImageIOBase::RGBA ) { if( pixelType.GetComponentType() == itk::ImageIOBase::DOUBLE ) { npy_type = NPY_DOUBLE; sitk_type = "sitkVectorFloat64"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::FLOAT ) { npy_type = NPY_FLOAT; sitk_type = "sitkVectorFloat32"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::SHORT) { npy_type = NPY_SHORT; sitk_type = "sitkVectorInt16"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::CHAR ) { npy_type = NPY_BYTE; sitk_type = "sitkVectorInt8"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::INT ) { npy_type = NPY_INT; sitk_type = "sitkVectorInt32"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::LONG ) { npy_type = NPY_LONG; sitk_type = "sitkVectorInt64"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::UCHAR ) { npy_type = NPY_UBYTE; sitk_type = "sitkVectorUInt8"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::UINT ) { npy_type = NPY_UINT; sitk_type = "sitkVectorUInt32"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::ULONG ) { npy_type = NPY_LONG; sitk_type = "sitkVectorUInt64"; } else if( pixelType.GetComponentType() == itk::ImageIOBase::USHORT ) { npy_type = NPY_USHORT; sitk_type = "sitkVectorUInt16"; } } else { MITK_WARN << "not a recognized pixeltype"; return false; } // creating numpy array import_array1 (true); npyArray = PyArray_SimpleNewFromData(npy_nd,npy_dims,npy_type,array); // add temp array it to the python dictionary to access it in python code const int status = PyDict_SetItemString( pyDict,QString("%1_numpy_array") .arg(varName).toStdString().c_str(), npyArray ); // sanity check if ( status != 0 ) return false; command.append( QString("%1 = sitk.Image(%2,sitk.%3,%4)\n").arg(varName) .arg(dimensionString) .arg(QString(sitk_type.c_str())).arg(QString::number(pixelType.GetNumberOfComponents())) ); command.append( QString("%1.SetSpacing([%2,%3,%4])\n").arg(varName) .arg(QString::number(spacing[0])) .arg(QString::number(spacing[1])) .arg(QString::number(spacing[2])) ); command.append( QString("%1.SetOrigin([%2,%3,%4])\n").arg(varName) .arg(QString::number(origin[0])) .arg(QString::number(origin[1])) .arg(QString::number(origin[2])) ); command.append( QString("%1.SetDirection([%2,%3,%4,%5,%6,%7,%8,%9,%10])\n").arg(varName) .arg(QString::number(xDirection[0])) .arg(QString::number(xDirection[1])) .arg(QString::number(xDirection[2])) .arg(QString::number(yDirection[0])) .arg(QString::number(yDirection[1])) .arg(QString::number(yDirection[2])) .arg(QString::number(zDirection[0])) .arg(QString::number(zDirection[1])) .arg(QString::number(zDirection[2])) ); // directly access the cpp api from the lib command.append( QString("_SimpleITK._SetImageFromArray(%1_numpy_array,%1)\n").arg(varName) ); command.append( QString("del %1_numpy_array").arg(varName) ); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + MITK_DEBUG("QtPythonService") << "Issuing python command " << command.toStdString(); this->Execute( command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); return true; } mitk::PixelType DeterminePixelType(const std::string& pythonPixeltype, unsigned long nrComponents, int dimensions) { typedef itk::RGBPixel< unsigned char > UCRGBPixelType; typedef itk::RGBPixel< unsigned short > USRGBPixelType; typedef itk::RGBPixel< float > FloatRGBPixelType; typedef itk::RGBPixel< double > DoubleRGBPixelType; typedef itk::Image< UCRGBPixelType > UCRGBImageType; typedef itk::Image< USRGBPixelType > USRGBImageType; typedef itk::Image< FloatRGBPixelType > FloatRGBImageType; typedef itk::Image< DoubleRGBPixelType > DoubleRGBImageType; typedef itk::RGBAPixel< unsigned char > UCRGBAPixelType; typedef itk::RGBAPixel< unsigned short > USRGBAPixelType; typedef itk::RGBAPixel< float > FloatRGBAPixelType; typedef itk::RGBAPixel< double > DoubleRGBAPixelType; typedef itk::Image< UCRGBAPixelType > UCRGBAImageType; typedef itk::Image< USRGBAPixelType > USRGBAImageType; typedef itk::Image< FloatRGBAPixelType > FloatRGBAImageType; typedef itk::Image< DoubleRGBAPixelType > DoubleRGBAImageType; auto pixelType = mitk::MakePixelType(nrComponents); if (nrComponents == 1) { if( pythonPixeltype.compare("float64") == 0 ) { pixelType = mitk::MakePixelType(nrComponents); } else if( pythonPixeltype.compare("float32") == 0 ) { pixelType = mitk::MakePixelType(nrComponents); } else if( pythonPixeltype.compare("int16") == 0) { pixelType = mitk::MakePixelType(nrComponents); } else if( pythonPixeltype.compare("int8") == 0 ) { pixelType = mitk::MakePixelType(nrComponents); } else if( pythonPixeltype.compare("int32") == 0 ) { pixelType = mitk::MakePixelType(nrComponents); } else if( pythonPixeltype.compare("int64") == 0 ) { pixelType = mitk::MakePixelType(nrComponents); } else if( pythonPixeltype.compare("uint8") == 0 ) { pixelType = mitk::MakePixelType(nrComponents); } else if( pythonPixeltype.compare("uint32") == 0 ) { pixelType = mitk::MakePixelType(nrComponents); } else if( pythonPixeltype.compare("uint64") == 0 ) { pixelType = mitk::MakePixelType(nrComponents); } else if( pythonPixeltype.compare("uint16") == 0 ) { pixelType = mitk::MakePixelType(nrComponents); } else { mitkThrow()<< "unknown scalar PixelType"; } } else if(nrComponents == 3 && dimensions == 2) { if( pythonPixeltype.compare("float64") == 0 ) { pixelType = mitk::MakePixelType(); } else if( pythonPixeltype.compare("float32") == 0 ) { pixelType = mitk::MakePixelType(); } else if( pythonPixeltype.compare("uint8") == 0 ) { pixelType = mitk::MakePixelType(); } else if( pythonPixeltype.compare("uint16") == 0 ) { pixelType = mitk::MakePixelType(); } } else if( (nrComponents == 4) && dimensions == 2 ) { if( pythonPixeltype.compare("float64") == 0 ) { pixelType = mitk::MakePixelType(); } else if( pythonPixeltype.compare("float32") == 0 ) { pixelType = mitk::MakePixelType(); } else if( pythonPixeltype.compare("uint8") == 0 ) { pixelType = mitk::MakePixelType(); } else if( pythonPixeltype.compare("uint16") == 0 ) { pixelType = mitk::MakePixelType(); } } else { if( pythonPixeltype.compare("float64") == 0 ) { pixelType = mitk::MakePixelType >(nrComponents); } else if( pythonPixeltype.compare("float32") == 0 ) { pixelType = mitk::MakePixelType >(nrComponents); } else if( pythonPixeltype.compare("int16") == 0) { pixelType = mitk::MakePixelType >(nrComponents); } else if( pythonPixeltype.compare("int8") == 0 ) { pixelType = mitk::MakePixelType >(nrComponents); } else if( pythonPixeltype.compare("int32") == 0 ) { pixelType = mitk::MakePixelType >(nrComponents); } else if( pythonPixeltype.compare("int64") == 0 ) { pixelType = mitk::MakePixelType >(nrComponents); } else if( pythonPixeltype.compare("uint8") == 0 ) { pixelType = mitk::MakePixelType >(nrComponents); } else if( pythonPixeltype.compare("uint16") == 0 ) { pixelType = mitk::MakePixelType >(nrComponents); } else if( pythonPixeltype.compare("uint32") == 0 ) { pixelType = mitk::MakePixelType >(nrComponents); } else if( pythonPixeltype.compare("uint64") == 0 ) { pixelType = mitk::MakePixelType >(nrComponents); } else { mitkThrow()<< "unknown vectorial PixelType"; } } return pixelType; } -mitk::Image::Pointer mitk::PythonService::CopySimpleItkImageFromPython(const std::string &stdvarName) +mitk::Image::Pointer mitk::QtPythonService::CopySimpleItkImageFromPython(const std::string &stdvarName) { double*ds = nullptr; // access python module PyObject *pyMod = PyImport_AddModule("__main__"); // global dictionarry PyObject *pyDict = PyModule_GetDict(pyMod); mitk::Image::Pointer mitkImage = mitk::Image::New(); mitk::Vector3D spacing; mitk::Point3D origin; QString command; QString varName = QString::fromStdString( stdvarName ); command.append( QString("%1_numpy_array = sitk.GetArrayFromImage(%1)\n").arg(varName) ); command.append( QString("%1_spacing = numpy.asarray(%1.GetSpacing())\n").arg(varName) ); command.append( QString("%1_origin = numpy.asarray(%1.GetOrigin())\n").arg(varName) ); command.append( QString("%1_dtype = %1_numpy_array.dtype.name\n").arg(varName) ); command.append( QString("%1_direction = numpy.asarray(%1.GetDirection())\n").arg(varName) ); command.append( QString("%1_nrComponents = numpy.asarray(%1.GetNumberOfComponentsPerPixel())\n").arg(varName)); command.append( QString("%1_dtype = %1_numpy_array.dtype.name\n").arg(varName) ); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + MITK_DEBUG("QtPythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); PyObject* py_dtype = PyDict_GetItemString(pyDict,QString("%1_dtype").arg(varName).toStdString().c_str() ); std::string dtype = PyString_AsString(py_dtype); PyArrayObject* py_data = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_numpy_array").arg(varName).toStdString().c_str() ); PyArrayObject* py_spacing = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_spacing").arg(varName).toStdString().c_str() ); PyArrayObject* py_origin = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_origin").arg(varName).toStdString().c_str() ); PyArrayObject* py_direction = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_direction").arg(varName).toStdString().c_str() ); PyArrayObject* py_nrComponents = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_nrComponents").arg(varName).toStdString().c_str() ); unsigned int nr_Components = *(reinterpret_cast(PyArray_DATA(py_nrComponents))); unsigned int nr_dimensions = PyArray_NDIM(py_data); if (nr_Components > 1) // for VectorImages the last dimension in the numpy array are the vector components. { --nr_dimensions; } mitk::PixelType pixelType = DeterminePixelType(dtype, nr_Components, nr_dimensions); unsigned int* dimensions = new unsigned int[nr_dimensions]; // fill backwards , nd data saves dimensions in opposite direction for( unsigned i = 0; i < nr_dimensions; ++i ) { dimensions[i] = PyArray_DIMS(py_data)[nr_dimensions - 1 - i]; } mitkImage->Initialize(pixelType, nr_dimensions, dimensions); mitkImage->SetChannel(PyArray_DATA(py_data)); ds = reinterpret_cast(PyArray_DATA(py_spacing)); spacing[0] = ds[0]; spacing[1] = ds[1]; spacing[2] = ds[2]; mitkImage->GetGeometry()->SetSpacing(spacing); ds = reinterpret_cast(PyArray_DATA(py_origin)); origin[0] = ds[0]; origin[1] = ds[1]; origin[2] = ds[2]; mitkImage->GetGeometry()->SetOrigin(origin); itk::Matrix py_transform; ds = reinterpret_cast(PyArray_DATA(py_direction)); py_transform[0][0] = ds[0]; py_transform[0][1] = ds[1]; py_transform[0][2] = ds[2]; py_transform[1][0] = ds[3]; py_transform[1][1] = ds[4]; py_transform[1][2] = ds[5]; py_transform[2][0] = ds[6]; py_transform[2][1] = ds[7]; py_transform[2][2] = ds[8]; mitk::AffineTransform3D::Pointer affineTransform = mitkImage->GetGeometry()->GetIndexToWorldTransform(); itk::Matrix transform = py_transform * affineTransform->GetMatrix(); affineTransform->SetMatrix(transform); mitkImage->GetGeometry()->SetIndexToWorldTransform(affineTransform); // mitk::AffineTransform3D::New(); //mitkImage->GetGeometry()->SetIndexToWorldTransform(); // cleanup command.clear(); command.append( QString("del %1_numpy_array\n").arg(varName) ); command.append( QString("del %1_dtype\n").arg(varName) ); command.append( QString("del %1_spacing\n").arg(varName) ); command.append( QString("del %1_origin\n").arg(varName) ); command.append( QString("del %1_direction\n").arg(varName) ); command.append( QString("del %1_nrComponents\n").arg(varName) ); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + MITK_DEBUG("QtPythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); delete[] dimensions; return mitkImage; } -bool mitk::PythonService::CopyToPythonAsCvImage( mitk::Image* image, const std::string& stdvarName ) +bool mitk::QtPythonService::CopyMITKImageToPython(mitk::Image::Pointer &image, const std::string &varName) +{ + mitkThrow() << "This function is not implemented"; +} + +mitk::Image::Pointer mitk::QtPythonService::CopyMITKImageFromPython(const std::string &varName) +{ + mitkThrow() << "This function is not implemented"; +} + +std::vector mitk::QtPythonService::CopyListOfMITKImagesFromPython(const std::string &listVarName) +{ + mitkThrow() << "This function is not implemented"; +} + +bool mitk::QtPythonService::CopyToPythonAsCvImage( mitk::Image* image, const std::string& stdvarName ) { QString varName = QString::fromStdString( stdvarName ); QString command; unsigned int* imgDim = image->GetDimensions(); int npy_nd = 1; // access python module PyObject *pyMod = PyImport_AddModule((char*)"__main__"); // global dictionary PyObject *pyDict = PyModule_GetDict(pyMod); mitk::PixelType pixelType = image->GetPixelType(); PyObject* npyArray = nullptr; mitk::ImageReadAccessor racc(image); void* array = (void*) racc.GetData(); // save the total number of elements here (since the numpy array is one dimensional) npy_intp* npy_dims = new npy_intp[1]; npy_dims[0] = imgDim[0]; /** * Build a string in the format [1024,1028,1] * to describe the dimensionality. This is needed for simple itk * to know the dimensions of the image */ QString dimensionString; dimensionString.append(QString("[")); dimensionString.append(QString::number(imgDim[0])); // ToDo: check if we need this for (unsigned i = 1; i < 3; ++i) // always three because otherwise the 3d-geometry gets destroyed // (relevant for backtransformation of simple itk image to mitk. { dimensionString.append(QString(",")); dimensionString.append(QString::number(imgDim[i])); npy_dims[0] *= imgDim[i]; } dimensionString.append("]"); // the next line is necessary for vectorimages npy_dims[0] *= pixelType.GetNumberOfComponents(); // default pixeltype: unsigned short NPY_TYPES npy_type = NPY_USHORT; if( pixelType.GetComponentType() == itk::ImageIOBase::DOUBLE ) { npy_type = NPY_DOUBLE; } else if( pixelType.GetComponentType() == itk::ImageIOBase::FLOAT ) { npy_type = NPY_FLOAT; } else if( pixelType.GetComponentType() == itk::ImageIOBase::SHORT) { npy_type = NPY_SHORT; } else if( pixelType.GetComponentType() == itk::ImageIOBase::CHAR ) { npy_type = NPY_BYTE; } else if( pixelType.GetComponentType() == itk::ImageIOBase::INT ) { npy_type = NPY_INT; } else if( pixelType.GetComponentType() == itk::ImageIOBase::LONG ) { npy_type = NPY_LONG; } else if( pixelType.GetComponentType() == itk::ImageIOBase::UCHAR ) { npy_type = NPY_UBYTE; } else if( pixelType.GetComponentType() == itk::ImageIOBase::UINT ) { npy_type = NPY_UINT; } else if( pixelType.GetComponentType() == itk::ImageIOBase::ULONG ) { npy_type = NPY_LONG; } else if( pixelType.GetComponentType() == itk::ImageIOBase::USHORT ) { npy_type = NPY_USHORT; } else { MITK_WARN << "not a recognized pixeltype"; return false; } // creating numpy array import_array1 (true); npyArray = PyArray_SimpleNewFromData(npy_nd,npy_dims,npy_type,array); // add temp array it to the python dictionary to access it in python code const int status = PyDict_SetItemString( pyDict,QString("%1_numpy_array") .arg(varName).toStdString().c_str(), npyArray ); // sanity check if ( status != 0 ) return false; command.append( QString("import numpy as np\n")); //command.append( QString("if '%1' in globals():\n").arg(varName)); //command.append( QString(" del %1\n").arg(varName)); command.append( QString("%1_array_tmp=%1_numpy_array.copy()\n").arg(varName)); command.append( QString("%1_array_tmp=%1_array_tmp.reshape(%2,%3,%4)\n").arg( varName, QString::number(imgDim[1]), QString::number(imgDim[0]), QString::number(pixelType.GetNumberOfComponents()))); command.append( QString("%1 = %1_array_tmp[:,...,::-1]\n").arg(varName)); command.append( QString("del %1_numpy_array\n").arg(varName) ); command.append( QString("del %1_array_tmp").arg(varName) ); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + MITK_DEBUG("QtPythonService") << "Issuing python command " << command.toStdString(); this->Execute( command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); return true; } -mitk::Image::Pointer mitk::PythonService::CopyCvImageFromPython( const std::string& stdvarName ) +mitk::Image::Pointer mitk::QtPythonService::CopyCvImageFromPython( const std::string& stdvarName ) { // access python module PyObject *pyMod = PyImport_AddModule((char*)"__main__"); // global dictionarry PyObject *pyDict = PyModule_GetDict(pyMod); mitk::Image::Pointer mitkImage = mitk::Image::New(); QString command; QString varName = QString::fromStdString( stdvarName ); command.append( QString("import numpy as np\n")); command.append( QString("%1_dtype=%1.dtype.name\n").arg(varName) ); command.append( QString("%1_shape=np.asarray(%1.shape)\n").arg(varName) ); command.append( QString("%1_np_array=%1[:,...,::-1]\n").arg(varName)); command.append( QString("%1_np_array=np.reshape(%1_np_array,%1.shape[0] * %1.shape[1] * %1.shape[2])").arg(varName) ); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + MITK_DEBUG("QtPythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); PyObject* py_dtype = PyDict_GetItemString(pyDict,QString("%1_dtype").arg(varName).toStdString().c_str() ); std::string dtype = PyString_AsString(py_dtype); PyArrayObject* py_data = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_np_array").arg(varName).toStdString().c_str() ); PyArrayObject* shape = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_shape").arg(varName).toStdString().c_str() ); size_t* d = reinterpret_cast(PyArray_DATA(shape)); unsigned int dimensions[3]; dimensions[0] = d[1]; dimensions[1] = d[0]; dimensions[2] = d[2]; unsigned int nr_dimensions = 2; // get number of components unsigned int nr_Components = (unsigned int) d[2]; auto pixelType = DeterminePixelType(dtype, nr_Components, nr_dimensions); mitkImage->Initialize(pixelType, nr_dimensions, dimensions); //mitkImage->SetChannel(py_data->data); { mitk::ImageWriteAccessor ra(mitkImage); char* data = (char*)(ra.GetData()); memcpy(data, PyArray_DATA(py_data), dimensions[0] * dimensions[1] * pixelType.GetSize()); } command.clear(); command.append( QString("del %1_shape\n").arg(varName) ); command.append( QString("del %1_dtype\n").arg(varName) ); command.append( QString("del %1_np_array").arg(varName)); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + MITK_DEBUG("QtPythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); return mitkImage; } -ctkAbstractPythonManager *mitk::PythonService::GetPythonManager() +ctkAbstractPythonManager *mitk::QtPythonService::GetPythonManager() { - return &m_PythonManager; + return m_PythonManager; } -mitk::Surface::Pointer mitk::PythonService::CopyVtkPolyDataFromPython( const std::string& stdvarName ) +mitk::Surface::Pointer mitk::QtPythonService::CopyVtkPolyDataFromPython( const std::string& stdvarName ) { // access python module PyObject *pyMod = PyImport_AddModule((char*)"__main__"); // global dictionarry PyObject *pyDict = PyModule_GetDict(pyMod); // python memory address PyObject *pyAddr = nullptr; // cpp address size_t addr = 0; mitk::Surface::Pointer surface = mitk::Surface::New(); QString command; QString varName = QString::fromStdString( stdvarName ); command.append( QString("%1_addr_str = %1.GetAddressAsString(\"vtkPolyData\")\n").arg(varName) ); // remove 0x from the address command.append( QString("%1_addr = int(%1_addr_str[5:],16)").arg(varName) ); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + MITK_DEBUG("QtPythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); // get address of the object pyAddr = PyDict_GetItemString(pyDict,QString("%1_addr").arg(varName).toStdString().c_str()); // convert to long addr = PyInt_AsLong(pyAddr); MITK_DEBUG << "Python object address: " << addr; // get the object vtkPolyData* poly = (vtkPolyData*)((void*)addr); surface->SetVtkPolyData(poly); // delete helper variables from python stack command = ""; command.append( QString("del %1_addr_str\n").arg(varName) ); command.append( QString("del %1_addr").arg(varName) ); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + MITK_DEBUG("QtPythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); return surface; } -bool mitk::PythonService::CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& stdvarName ) +bool mitk::QtPythonService::CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& stdvarName ) { QString varName = QString::fromStdString( stdvarName ); std::ostringstream oss; std::string addr = ""; QString command; QString address; oss << (void*) ( surface->GetVtkPolyData() ); // get the address addr = oss.str(); // remove "0x" address = QString::fromStdString(addr.substr(2)); command.append( QString("%1 = vtk.vtkPolyData(\"%2\")\n").arg(varName).arg(address) ); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); + MITK_DEBUG("QtPythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); return true; } -bool mitk::PythonService::IsSimpleItkPythonWrappingAvailable() +bool mitk::QtPythonService::IsSimpleItkPythonWrappingAvailable() { this->Execute( "import SimpleITK as sitk\n", IPythonService::SINGLE_LINE_COMMAND ); // directly access cpp lib this->Execute( "import SimpleITK._SimpleITK as _SimpleITK\n", IPythonService::SINGLE_LINE_COMMAND ); m_ItkWrappingAvailable = !this->PythonErrorOccured(); // check for numpy this->Execute( "import numpy\n", IPythonService::SINGLE_LINE_COMMAND ); if ( this->PythonErrorOccured() ) MITK_ERROR << "Numpy not found."; m_ItkWrappingAvailable = !this->PythonErrorOccured(); return m_ItkWrappingAvailable; } -bool mitk::PythonService::IsOpenCvPythonWrappingAvailable() +bool mitk::QtPythonService::IsOpenCvPythonWrappingAvailable() { this->Execute( "import cv2\n", IPythonService::SINGLE_LINE_COMMAND ); m_OpenCVWrappingAvailable = !this->PythonErrorOccured(); return m_OpenCVWrappingAvailable; } -bool mitk::PythonService::IsVtkPythonWrappingAvailable() +bool mitk::QtPythonService::IsVtkPythonWrappingAvailable() { this->Execute( "import vtk", IPythonService::SINGLE_LINE_COMMAND ); //this->Execute( "print \"Using VTK version \" + vtk.vtkVersion.GetVTKVersion()\n", IPythonService::SINGLE_LINE_COMMAND ); m_VtkWrappingAvailable = !this->PythonErrorOccured(); return m_VtkWrappingAvailable; } -bool mitk::PythonService::PythonErrorOccured() const +bool mitk::QtPythonService::PythonErrorOccured() const { return m_ErrorOccured; } - diff --git a/Modules/Python/autoload/PythonService/mitkPythonService.h b/Modules/QtPythonService/mitkQtPythonService.h similarity index 67% rename from Modules/Python/autoload/PythonService/mitkPythonService.h rename to Modules/QtPythonService/mitkQtPythonService.h index 31338dd8e1..09feb38cd2 100644 --- a/Modules/Python/autoload/PythonService/mitkPythonService.h +++ b/Modules/QtPythonService/mitkQtPythonService.h @@ -1,107 +1,122 @@ /*============================================================================ 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 mitkPythonService_h -#define mitkPythonService_h +#ifndef mitkQtPythonService_h +#define mitkQtPythonService_h #include #include "mitkIPythonService.h" #include #include "mitkSurface.h" namespace mitk { /// /// implementation of the IPythonService using ctkabstractpythonmanager /// \see IPythonService - class PythonService: public itk::LightObject, public mitk::IPythonService + class QtPythonService: public itk::LightObject, public mitk::IPythonService { public: - /// /// instantiate python manager here - PythonService(); + QtPythonService(); /// /// empty implementation... - ~PythonService() override; + ~QtPythonService() override; /// /// \see IPythonService::Execute() - std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ) override; + std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND) override; /// /// \see IPythonService::ExecuteScript() void ExecuteScript(const std::string &pathToPythonScript) override; /// /// \see IPythonService::PythonErrorOccured() bool PythonErrorOccured() const override; /// /// \see IPythonService::GetVariableStack() - std::vector GetVariableStack() const override; + std::vector GetVariableStack() override; /// /// \see IPythonService::DoesVariableExist() - bool DoesVariableExist(const std::string& name) const override; + bool DoesVariableExist(const std::string& name) override; /// /// \see IPythonService::GetVariable() - std::string GetVariable(const std::string& name) const override; + std::string GetVariable(const std::string& name) override; /// /// \see IPythonService::AddPythonCommandObserver() void AddPythonCommandObserver( PythonCommandObserver* observer ) override; /// /// \see IPythonService::RemovePythonCommandObserver() void RemovePythonCommandObserver( PythonCommandObserver* observer ) override; /// /// \see IPythonService::NotifyObserver() void NotifyObserver( const std::string& command ) override; /// + /// \see IPythonService::GetNumberOfObserver() + int GetNumberOfObserver() override; + /// /// \see IPythonService::IsItkPythonWrappingAvailable() bool IsSimpleItkPythonWrappingAvailable() override; /// /// \see IPythonService::CopyToPythonAsItkImage() - bool CopyToPythonAsSimpleItkImage( mitk::Image* image, const std::string& varName ) override; + bool CopyToPythonAsSimpleItkImage( mitk::Image::Pointer image, const std::string& varName ) override; /// /// \see IPythonService::CopyItkImageFromPython() mitk::Image::Pointer CopySimpleItkImageFromPython( const std::string& varName ) override; /// + /// \see IPythonService::CopyMITKImageToPython() + /// \throws MITK exception since this function is not implemented (only implementation in mitkPythonService) + bool CopyMITKImageToPython(mitk::Image::Pointer &image, const std::string &varName) override; + /// + /// \see IPythonService::CopyMITKImageFromPython() + /// \throws MITK exception since this function is not implemented (only implementation in mitkPythonService) + mitk::Image::Pointer CopyMITKImageFromPython(const std::string &varName) override; + /// + /// \see IPythonService::CopyListOfMITKImagesFromPython() + /// \throws MITK exception since this function is not implemented (only implementation in mitkPythonService) + std::vector CopyListOfMITKImagesFromPython(const std::string &listVarName) override; + /// /// \see IPythonService::IsOpenCvPythonWrappingAvailable() bool IsOpenCvPythonWrappingAvailable() override; /// /// \see IPythonService::CopyToPythonAsCvImage() bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ) override; /// /// \see IPythonService::CopyCvImageFromPython() mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ) override; /// /// \see IPythonService::IsVtkPythonWrappingAvailable() bool IsVtkPythonWrappingAvailable() override; /// /// \see IPythonService::CopyToPythonAsVtkPolyData() bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ) override; /// /// \see IPythonService::CopyVtkPolyDataFromPython() mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ) override; /// /// \return the ctk abstract python manager instance - ctkAbstractPythonManager* GetPythonManager() override; + ctkAbstractPythonManager* GetPythonManager() /*override*/; void AddRelativeSearchDirs(std::vector< std::string > dirs) override; void AddAbsoluteSearchDirs(std::vector< std::string > dirs) override; + protected: private: QList m_Observer; - ctkAbstractPythonManager m_PythonManager; + ctkAbstractPythonManager* m_PythonManager; bool m_ItkWrappingAvailable; bool m_OpenCVWrappingAvailable; bool m_VtkWrappingAvailable; bool m_ErrorOccured; }; } #endif diff --git a/Modules/QtPythonService/test/CMakeLists.txt b/Modules/QtPythonService/test/CMakeLists.txt new file mode 100644 index 0000000000..153cd81e2e --- /dev/null +++ b/Modules/QtPythonService/test/CMakeLists.txt @@ -0,0 +1 @@ +MITK_CREATE_MODULE_TESTS() diff --git a/Modules/QtPythonService/test/files.cmake b/Modules/QtPythonService/test/files.cmake new file mode 100644 index 0000000000..36a44ec352 --- /dev/null +++ b/Modules/QtPythonService/test/files.cmake @@ -0,0 +1,3 @@ +set(MODULE_TESTS + mitkQtPythonTest.cpp +) \ No newline at end of file diff --git a/Modules/QtPythonService/test/mitkQtPythonTest.cpp b/Modules/QtPythonService/test/mitkQtPythonTest.cpp new file mode 100644 index 0000000000..7d54ae267e --- /dev/null +++ b/Modules/QtPythonService/test/mitkQtPythonTest.cpp @@ -0,0 +1,47 @@ +/*============================================================================ + +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 + +class mitkQtPythonTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkQtPythonTestSuite); + MITK_TEST(TestPython); + CPPUNIT_TEST_SUITE_END(); + +public: + + void TestPython() + { + std::string result = ""; + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=QtPythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(/*filter*/); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + mitk::IPythonService::ForceLoadModule(); + + result = m_PythonService->Execute("5+5", mitk::IPythonService::EVAL_COMMAND); + } + + MITK_TEST_CONDITION(result == "10", "Testing if running python code 5+5 results in 10"); + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkQtPython) diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 0d16bd73bc..70f68ac508 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,97 +1,98 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.mitkworkbench.intro:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.mxnmultiwidgeteditor:OFF org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.chartExample:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.datastorageviewertest:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicombrowser:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.lasercontrol:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.deformableclippingplane:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.semanticrelations:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.photoacoustics.pausviewer:OFF org.mitk.gui.qt.photoacoustics.pausmotioncompensation:OFF org.mitk.gui.qt.photoacoustics.imageprocessing:OFF org.mitk.gui.qt.photoacoustics.simulation:OFF org.mitk.gui.qt.photoacoustics.spectralunmixing:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.gui.qt.multilabelsegmentation:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF org.mitk.gui.qt.preprocessing.resampling:OFF org.mitk.gui.qt.radiomics:OFF org.mitk.gui.qt.cest:OFF org.mitk.gui.qt.fit.demo:OFF org.mitk.gui.qt.fit.inspector:OFF org.mitk.gui.qt.fit.genericfitting:OFF org.mitk.gui.qt.pharmacokinetics.mri:OFF org.mitk.gui.qt.pharmacokinetics.pet:OFF org.mitk.gui.qt.pharmacokinetics.simulation:OFF org.mitk.gui.qt.pharmacokinetics.curvedescriptor:OFF org.mitk.gui.qt.pharmacokinetics.concentration.mri:OFF org.mitk.gui.qt.flowapplication:OFF org.mitk.gui.qt.flow.segmentation:OFF + org.mitk.gui.qt.deeplearningsegmentation:ON ) diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/CMakeLists.txt b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/CMakeLists.txt new file mode 100644 index 0000000000..0e7c04fba0 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_deeplearningsegmentation) + +mitk_create_plugin( + EXPORT_DIRECTIVE DEEPLEARNINGSEGMENTATION_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkDeepLearningSegmentation +) diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/files.cmake b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/files.cmake new file mode 100644 index 0000000000..b7252cd0f4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/files.cmake @@ -0,0 +1,42 @@ +set(INTERNAL_CPP_FILES + org_mitk_gui_qt_deeplearningsegmentation_Activator.cpp + DeepLearningSegmentationGUI.cpp + SegmentationWorker.cpp + SegmentationResultHandler.cpp +) + +set(UI_FILES + src/internal/DeepLearningSegmentationGUI.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_gui_qt_deeplearningsegmentation_Activator.h + src/internal/DeepLearningSegmentationGUI.h + src/internal/SegmentationWorker.h + src/internal/SegmentationResultHandler.h +) + +# list of resource files which can be used by the plug-in +# system without loading the plug-ins shared library, +# for example the icon used in the menu and tabs for the +# plug-in views in the workbench +set(CACHED_RESOURCE_FILES + resources/icon.xpm + plugin.xml +) + +# list of Qt .qrc files which contain additional resources +# specific to this plugin +set(QRC_FILES + +) + +set(CPP_FILES ) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/manifest_headers.cmake new file mode 100644 index 0000000000..901746905f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/manifest_headers.cmake @@ -0,0 +1,7 @@ +set(Plugin-Name "DeepLearningsegmentation") +set(Plugin-Version "0.1") +set(Plugin-Vendor "German Cancer Research Center (DKFZ)") +set(Plugin-ContactAddress "") +set(Require-Plugin org.mitk.gui.qt.common) +set(Plugin-ActivationPolicy "eager") + diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/plugin.xml b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/plugin.xml new file mode 100644 index 0000000000..11a2b181d1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/plugin.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/resources/icon.xpm b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/resources/icon.xpm new file mode 100644 index 0000000000..9057c20bc6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/resources/icon.xpm @@ -0,0 +1,21 @@ +/* XPM */ +static const char * icon_xpm[] = { +"16 16 2 1", +" c #FF0000", +". c #000000", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.cpp b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.cpp new file mode 100644 index 0000000000..a3f097f99e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.cpp @@ -0,0 +1,123 @@ +/*============================================================================ + +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 "DeepLearningSegmentationGUI.h" +#include +#include +#include"SegmentationResultHandler.h" + +DeepLearningSegmentationGUI::DeepLearningSegmentationGUI() + : m_Ui(new Ui::DeepLearningSegmentationGUI) +{ + //register Meta types which is necessary for the qt signals/slots with those classes as parameter + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType>(); + + qRegisterMetaType>(); + + //set up the ui + m_Ui->setupUi(this); + + //connect the UI elements in signals/slots + connect(m_Ui->buttonPerformImageProcessing, &QPushButton::clicked, this, &DeepLearningSegmentationGUI::OnDoSegmentation); + connect(m_Ui->buttonLoadTrainedNetwork, &QPushButton::clicked, this, &DeepLearningSegmentationGUI::DoLoadTrainedNet); + m_Ui->buttonPerformImageProcessing->setEnabled(false); + + //create a new worker thread to execute some functions in a seperate thread + m_SegmentationThread = new QThread; + m_Worker = new SegmentationWorker; + m_Worker->moveToThread(m_SegmentationThread); + + // Signal/Slot connects between worker thread and GUI + connect(this, &DeepLearningSegmentationGUI::Operate, m_Worker, &SegmentationWorker::DoWork); + connect(this, &DeepLearningSegmentationGUI::Wait, m_Worker, &SegmentationWorker::WaitForSegmentationToFinish); + connect(m_Worker, &SegmentationWorker::Finished, this, &DeepLearningSegmentationGUI::DoSegmentationProcessFinished); + connect(m_Worker, &SegmentationWorker::FinishedMultilabel, this, &DeepLearningSegmentationGUI::DoSegmentationProcessFinished); + connect(m_Worker, &SegmentationWorker::Failed, this, &DeepLearningSegmentationGUI::DoSegmentationProcessFinished); + connect(m_Worker, &SegmentationWorker::PreviousSegmentationFinished, this, &DeepLearningSegmentationGUI::DoSegmentationProcessFinished); + + connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(OnNewToolAssociated(mitk::Tool *))); + connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(SetUpUI())); +} + +DeepLearningSegmentationGUI::~DeepLearningSegmentationGUI() { +} + +void DeepLearningSegmentationGUI::SetUpUI() +{ + // Disable buttons if a segmentation is already running + if (m_SegTool->IsSegmentationRunning()) + { + this->SegmentationRunning(); + m_SegmentationThread->start(); + emit Wait(m_SegTool); + } +} + +void DeepLearningSegmentationGUI::DoLoadTrainedNet() +{ + //Open a file dialog to select a trained network + QString tempPath = QString::fromStdString(mitk::IOUtil::GetTempPathA()); + QString pretrainedNetResourcesPath = + QFileDialog::getOpenFileName(nullptr, tr("Open File"), tempPath, tr("Images (*.pth.tar)")); + + //set the trained network + m_TrainedNet = pretrainedNetResourcesPath; + + //enable segmentation + if (m_TrainedNet != "") + { + m_Ui->labelWarning->setVisible(false); + m_Ui->buttonPerformImageProcessing->setEnabled(true); + } +} + +void DeepLearningSegmentationGUI::OnDoSegmentation() +{ + MITK_INFO << "[Start] Segmentation"; + //adapt gui to show that segmentation is running + this->SegmentationRunning(); + + SegmentationResultHandler *resultSetter = new SegmentationResultHandler; + if (!m_SegmentationThread->isRunning()) + { + m_SegmentationThread->start(); + } + //start segmentation in worker thread + emit Operate(m_SegTool, resultSetter, m_TrainedNet); +} + +void DeepLearningSegmentationGUI::SegmentationRunning() +{ + m_Ui->labelWarning->setText("Segmentation running. This might take a while."); + m_Ui->labelWarning->setVisible(true); + m_Ui->buttonLoadTrainedNetwork->setEnabled(false); + m_Ui->buttonPerformImageProcessing->setEnabled(false); +} + +void DeepLearningSegmentationGUI::DoSegmentationProcessFinished() +{ + m_Ui->buttonLoadTrainedNetwork->setEnabled(true); + if (m_TrainedNet == "") + { + m_Ui->labelWarning->setText("Please load a network!"); + m_Ui->labelWarning->setVisible(true); + m_Ui->buttonPerformImageProcessing->setEnabled(false); + } + else + { + m_Ui->labelWarning->setVisible(false); + m_Ui->buttonPerformImageProcessing->setEnabled(true); + } +} + diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.h b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.h new file mode 100644 index 0000000000..a7e1800dc2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.h @@ -0,0 +1,103 @@ +/*============================================================================ + +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 DeepLearningSegmentationGUI_h +#define DeepLearningSegmentationGUI_h + +#include +#include "ui_DeepLearningSegmentationGUI.h" +#include +#include "DeepLearningSegmentationTool.h" +#include +#include"SegmentationWorker.h" + +namespace Ui { +class DeepLearningSegmentationGUI; +} + +/** + * @class DeepLearningSegmentationGUI + * @brief This is the base class for all GUIs of Deep Learning Based Segmentations + */ +class DEEPLEARNINGSEGMENTATION_EXPORT DeepLearningSegmentationGUI : public QmitkToolGUI +{ + Q_OBJECT + +public: + /** + * @brief Constructor. Mainly for setting UI up and connect some signals and slots + * icon resource. + */ + DeepLearningSegmentationGUI(); + ~DeepLearningSegmentationGUI() override; + + /** + * @brief Adapt the gui (e.g. deactivate buttons) if a segmentation is running. + */ + void SegmentationRunning(); + +signals: + + /** + * @brief signal for starting the segmentation which is caught by a worker thread. + * + * @param tool the Segmentation Tool for running the segmentation + * @param guiSetter the result handler which displays the result in the UI after the segmentation + * @param networkPath the path to the trained network which is needed for the segmentation + */ + void Operate(mitk::DeepLearningSegmentationTool* tool, SegmentationResultHandler* guiSetter, QString networkPath); + /** + * @brief if a segmentation is executed when the tool is started, emit a signal for waiting in the worker thread. + * + * @param tool the Segmentation Tool to check in worker, if the segmentation is still running. + */ + void Wait(mitk::DeepLearningSegmentationTool *tool); + + protected slots: + /** + * @brief set up the UI depending on whether a segmentation is running + */ + virtual void SetUpUI(); + /** + * @brief start the segmentation by emitting a operate signal which is caught by a worker thread. + * Called when the "Run Segmentation" button is pressed. + */ + virtual void OnDoSegmentation(); + /** + * @brief set m_TrainedNetwork after a File Dialog is appearing to select a trained network. + * Called when the "Load trained network" button is pressed. + */ + void DoLoadTrainedNet(); + /** + * @brief Set the segmentation method m_SegTool. + * This method has to be overwritten by every individual segmentation method to set the correct segmentation tool. + */ + virtual void OnNewToolAssociated(mitk::Tool *) = 0; + /** + * @brief set up the UI if a segmentation is finished + */ + void DoSegmentationProcessFinished(); + + protected: + mitk::DeepLearningSegmentationTool* m_SegTool; + QScopedPointer m_Ui; + QString m_TrainedNet; + + private: + + QThread *m_SegmentationThread; + SegmentationWorker *m_Worker; + +}; + +#endif // DeepLearningSegmentationGUI_h diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.ui b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.ui new file mode 100644 index 0000000000..69964a1f52 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.ui @@ -0,0 +1,55 @@ + + + DeepLearningSegmentationGUI + + + + 0 + 0 + 222 + 96 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + QLabel { color: rgb(255, 0, 0) } + + + Please load a network! + + + + + + + Load network + + + + + + + Do image processing + + + Run Segmentation + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationResultHandler.cpp b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationResultHandler.cpp new file mode 100644 index 0000000000..d235090bbf --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationResultHandler.cpp @@ -0,0 +1,68 @@ +/*============================================================================ + +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"SegmentationResultHandler.h" +#include + +SegmentationResultHandler::SegmentationResultHandler() { +} + +SegmentationResultHandler::~SegmentationResultHandler(){ +} + +void SegmentationResultHandler::SetResult(mitk::LabelSetImage::Pointer resultSegmentation, + mitk::DeepLearningSegmentationTool *segTool) +{ + try + { + //create new data node with the segmentation output as data + mitk::DataNode::Pointer outputNode = mitk::DataNode::New(); + outputNode->SetName(segTool->GetName()); + outputNode->SetData(resultSegmentation); + //add data node to data storage and update GUI + segTool->GetDataStorage()->Add(outputNode, segTool->GetReferenceData()); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + catch (const mitk::Exception &e) + { + MITK_INFO << e.GetDescription(); + } +} + +void SegmentationResultHandler::SetMultilabelResult(std::vector resultSegmentation, + mitk::DeepLearningSegmentationTool *segTool) +{ + try + { + for (int i = 0; iGetName()+std::to_string(i); + outputNode->SetName(name); + outputNode->SetData(resultSegmentation[i]); + // add data node to data storage and update GUI + segTool->GetDataStorage()->Add(outputNode, segTool->GetReferenceData()); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + } + catch (const mitk::Exception &e) + { + MITK_INFO << e.GetDescription(); + } +} + +void SegmentationResultHandler::SegmentationProcessFailed() +{ + QMessageBox::warning(nullptr, + "Error in segmentation", + "There was an error in the segmentation process. No resulting segmentation can be loaded."); +} diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationResultHandler.h b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationResultHandler.h new file mode 100644 index 0000000000..4bb839e526 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationResultHandler.h @@ -0,0 +1,52 @@ +/*============================================================================ + +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 SegmentationResultHandler_h +#define SegmentationResultHandler_h + +#include +#include + +/** +* @class SegmentationResultHandler +* @brief Class which sets the result in the UI after a deep learning method is finished +*/ +class SegmentationResultHandler : public QObject +{ + Q_OBJECT +public: + SegmentationResultHandler(); + ~SegmentationResultHandler(); +public slots: + /** + * @brief display the result of the segmentation if the segmentation process was successful + * + * @param resultSegmentation the resulting segmentation from the segmentation process to display + * @param segTool the Segmentation Tool for running the segmentation + */ + void SetResult(mitk::LabelSetImage::Pointer resultSegmentation, mitk::DeepLearningSegmentationTool *segTool); + /** + * @brief display the result of the segmentation if the segmentation process was successful + * + * @param resultSegmentation the resulting segmentation from the segmentation process to display + * @param segTool the Segmentation Tool for running the segmentation + */ + void SetMultilabelResult(std::vector resultSegmentation, mitk::DeepLearningSegmentationTool *segTool); + /** + * @brief display a warning for the user if segmentation process failed + */ + void SegmentationProcessFailed(); + +signals: + +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationWorker.cpp b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationWorker.cpp new file mode 100644 index 0000000000..fda8c10be4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationWorker.cpp @@ -0,0 +1,67 @@ +/*============================================================================ + +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"SegmentationWorker.h" + +SegmentationWorker::SegmentationWorker() +{ +} +void SegmentationWorker::DoWork(mitk::DeepLearningSegmentationTool* segTool, + SegmentationResultHandler *resultSetter, + QString networkPath) +{ + //connect signals/slots with the result setter which sets the result in the main thread afterwards + connect(this, &SegmentationWorker::Finished, resultSetter, &SegmentationResultHandler::SetResult); + connect(this, &SegmentationWorker::FinishedMultilabel, resultSetter, &SegmentationResultHandler::SetMultilabelResult); + connect(this, &SegmentationWorker::Failed, resultSetter, &SegmentationResultHandler::SegmentationProcessFailed); + + try + { + bool multilabel = segTool->IsMultilabelSegmentation(); + //execute segmentation with segmentation tool + if (!multilabel) + { + mitk::LabelSetImage::Pointer result = segTool->DoSegmentation(networkPath.toStdString()); + MITK_INFO << "Back in Worker"; + emit Finished(result, segTool); + } + else + { + std::vector result = segTool->DoMultilabelSegmentation(networkPath.toStdString()); + MITK_INFO << "Back in Worker"; + emit FinishedMultilabel(result, segTool); + } + //disconnect from result setter. Otherwise, the result is set twice after second execution, + //three times after third execution,... + disconnect(this, &SegmentationWorker::Finished, resultSetter, &SegmentationResultHandler::SetResult); + disconnect(this, &SegmentationWorker::FinishedMultilabel, resultSetter, &SegmentationResultHandler::SetMultilabelResult); + disconnect(this, &SegmentationWorker::Failed, resultSetter, &SegmentationResultHandler::SegmentationProcessFailed); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + emit Failed(); + // disconnect from result setter. Otherwise, the result is set twice after second execution, + // three times after third execution,... + disconnect(this, &SegmentationWorker::Finished, resultSetter, &SegmentationResultHandler::SetResult); + disconnect(this, &SegmentationWorker::FinishedMultilabel, resultSetter, &SegmentationResultHandler::SetMultilabelResult); + disconnect(this, &SegmentationWorker::Failed, resultSetter, &SegmentationResultHandler::SegmentationProcessFailed); + } +} + +void SegmentationWorker::WaitForSegmentationToFinish(mitk::DeepLearningSegmentationTool *segTool) +{ + while (segTool->IsSegmentationRunning()) + { + //Wait + } + emit PreviousSegmentationFinished(); +} diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationWorker.h b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationWorker.h new file mode 100644 index 0000000000..b6c5c2c104 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/SegmentationWorker.h @@ -0,0 +1,76 @@ +/*============================================================================ + +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 SegmentationWorker_h +#define SegmentationWorker_h + +#include +#include +#include"SegmentationResultHandler.h" + +Q_DECLARE_METATYPE(mitk::DeepLearningSegmentationTool*) +Q_DECLARE_METATYPE(mitk::LabelSetImage::Pointer) +Q_DECLARE_METATYPE(std::vector) + +/** + * @class SegmentationWorker + * @brief Class to execute some functions (mainly segmentation) from the Segmentation Plugin in a seperate thread + */ +class SegmentationWorker : public QObject +{ + Q_OBJECT +public: + SegmentationWorker(); +public slots: + /** + * @brief execute segmentation with the correct segmentation tool + * + * @param segTool the Segmentation Tool for running the segmentation + * @param resultSetter the SegmentationResultHandler which sets the result in the GUI after the segmentation + * @param networkPath the path to the trained network which is needed for the segmentation + */ + void DoWork(mitk::DeepLearningSegmentationTool* segTool, + SegmentationResultHandler *resultSetter, + QString networkPath); + /** + * @brief if a segmentation is executed when the tool is started, + * wait for the segmentation to finish and emit a signal (PreviouesSegmentationFinished) afterwards. + * + * @param tool the Segmentation Tool to check, if the segmentation is still running. + */ + void WaitForSegmentationToFinish(mitk::DeepLearningSegmentationTool *segTool); + +signals: + /** + * @brief the signal emitted when a segmentation process finished successful + * + * @param result the resulting segmentation + * @param segTool the Segmentation Tool for running the segmentation + */ + void Finished(mitk::LabelSetImage::Pointer result, mitk::DeepLearningSegmentationTool* segTool); + /** + * @brief the signal emitted when a multilabel segmentation process finished successful + * + * @param result the resulting segmentation + * @param segTool the Segmentation Tool for running the segmentation + */ + void FinishedMultilabel(std::vector result, mitk::DeepLearningSegmentationTool *segTool); + /** + * @brief the signal emitted when a segmentation process failed + */ + void Failed(); + /** + * @brief the signal emitted when a segmentation, which ran when the tool was started, finished + */ + void PreviousSegmentationFinished(); +}; + +#endif diff --git a/Modules/Python/mitkIPythonService.cpp b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/org_mitk_gui_qt_deeplearningsegmentation_Activator.cpp similarity index 57% copy from Modules/Python/mitkIPythonService.cpp copy to Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/org_mitk_gui_qt_deeplearningsegmentation_Activator.cpp index e52b7bb25e..db9f7d2093 100644 --- a/Modules/Python/mitkIPythonService.cpp +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/org_mitk_gui_qt_deeplearningsegmentation_Activator.cpp @@ -1,25 +1,23 @@ /*============================================================================ 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 "mitkIPythonService.h" -mitk::IPythonService::~IPythonService() -{ -} +#include "org_mitk_gui_qt_deeplearningsegmentation_Activator.h" -std::string mitk::IPythonService::ForceLoadModule() +namespace mitk { - std::string ret = "Load python module"; - MITK_INFO << ret; - return ret; -} + void org_mitk_gui_qt_deeplearningsegmentation_Activator::start(ctkPluginContext *context) + { + } + void org_mitk_gui_qt_deeplearningsegmentation_Activator::stop(ctkPluginContext *context) { Q_UNUSED(context) } +} diff --git a/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/org_mitk_gui_qt_deeplearningsegmentation_Activator.h b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/org_mitk_gui_qt_deeplearningsegmentation_Activator.h new file mode 100644 index 0000000000..f64060cf8e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.deeplearningsegmentation/src/internal/org_mitk_gui_qt_deeplearningsegmentation_Activator.h @@ -0,0 +1,34 @@ +/*============================================================================ + +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 org_mitk_gui_qt_deeplearningsegmentation_Activator_h +#define org_mitk_gui_qt_deeplearningsegmentation_Activator_h + +#include + +namespace mitk +{ + class org_mitk_gui_qt_deeplearningsegmentation_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_deeplearningsegmentation") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext *context); + void stop(ctkPluginContext *context); + + }; // org_mitk_gui_qt_deeplearningsegmentation_Activator +} + +#endif // org_mitk_gui_qt_deeplearningsegmentation_Activator_h