diff --git a/Modules/Python/Testing/mitkPythonWrappingTest.cpp b/Modules/Python/Testing/mitkPythonWrappingTest.cpp index 5e71b2015e..5ca5df6192 100644 --- a/Modules/Python/Testing/mitkPythonWrappingTest.cpp +++ b/Modules/Python/Testing/mitkPythonWrappingTest.cpp @@ -1,380 +1,253 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include +#include #include // vtk cone sample snippet #include // vtk decimate pro snippet #include -#include namespace sitk = itk::simple; namespace mitk { static bool Equal ( mitk::Image* img1, mitk::Image* img2 ); static bool Equal ( mitk::Surface* s1, Surface *s2 ); - static sitk::Image MitkToSimpleItkImage(mitk::Image* image); - static Image::Pointer SimpleItkToMitkImage(sitk::Image& sitkImage); } bool mitk::Equal ( mitk::Image* img1, mitk::Image* img2 ) { mitk::ImageReadAccessor ra1(img1); mitk::ImageReadAccessor ra2(img2); const unsigned int* img1Dims = img1->GetDimensions(); if ( img1->GetDimension() != img2->GetDimension() ) return false; if( img1Dims[0] != img2->GetDimensions()[0] || img1Dims[1] != img2->GetDimensions()[1] || img1Dims[2] != img2->GetDimensions()[2] ) return false; if ( img1->GetPixelType().GetPixelType() != img2->GetPixelType().GetPixelType()) return false; if ( img1->GetGeometry()->GetSpacing()[0] != img2->GetGeometry()->GetSpacing()[0] || img1->GetGeometry()->GetSpacing()[1] != img2->GetGeometry()->GetSpacing()[1] || img1->GetGeometry()->GetSpacing()[2] != img2->GetGeometry()->GetSpacing()[2] ) return false; if ( img1->GetGeometry()->GetOrigin()[0] != img2->GetGeometry()->GetOrigin()[0] || img1->GetGeometry()->GetOrigin()[1] != img2->GetGeometry()->GetOrigin()[1] || img1->GetGeometry()->GetOrigin()[2] != img2->GetGeometry()->GetOrigin()[2] ) return false; size_t size = img1Dims[0] * img1Dims[1] * img1Dims[2] * img1->GetPixelType().GetSize(); // bytewise compare the image for ( size_t i = 0; i < size; ++i ) { if ( ((char*)ra1.GetData())[i] != ((char*)ra2.GetData())[i] ) return false; } return true; } bool mitk::Equal( mitk::Surface* s1, mitk::Surface* s2 ) { vtkPolyData* poly1 = s1->GetVtkPolyData(); vtkPolyData* poly2 = s2->GetVtkPolyData(); double p1[3] = { 0.0,0.0,0.0 }; double p2[3] = { 0.0,0.0,0.0 }; if ( poly1->GetNumberOfPoints() != poly2->GetNumberOfPoints() ) { MITK_WARN << "Size does not match : s1 = " << poly1->GetNumberOfPoints() << ", s2 = " << poly2->GetNumberOfPoints(); return false; } for ( vtkIdType i = 0; i < poly1->GetNumberOfPoints(); ++i ) { poly1->GetPoint(i,p1); poly2->GetPoint(i,p2); if ( !mitk::Equal(p1[0],p2[0]) || !mitk::Equal(p1[1],p2[1]) || !mitk::Equal(p1[2],p2[2]) ) { MITK_WARN << "Points do not match: i: "<< i << "p1(" << p1[0] << "," << p1[1] << "," << p1[2] << "), p2(" << p2[0] << "," << p2[1] << "," << p2[2] << ")" ; return false; } } return true; } -sitk::Image mitk::MitkToSimpleItkImage(mitk::Image* image) -{ - const mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); - mitk::Point3D origin = image->GetGeometry()->GetOrigin(); - mitk::PixelType pixelType = image->GetPixelType(); - mitk::ImageReadAccessor ra(image); - void* buffer = (void*) ra.GetData(); - sitk::ImportImageFilter importer; - - std::vector sitkSpacing; - sitkSpacing.push_back(spacing[0]); - sitkSpacing.push_back(spacing[1]); - sitkSpacing.push_back(spacing[2]); - std::vector sitkOrigin; - sitkOrigin.push_back(origin[0]); - sitkOrigin.push_back(origin[1]); - sitkOrigin.push_back(origin[2]); - std::vector sitkSize; - - for ( unsigned int i = 0; i < image->GetDimension(); ++i ) - sitkSize.push_back(image->GetDimensions()[i]); - - importer.SetSpacing(sitkSpacing); - importer.SetSize(sitkSize); - importer.SetOrigin(sitkOrigin); - - if( pixelType.GetComponentType() == itk::ImageIOBase::DOUBLE ) { - importer.SetBufferAsDouble((double*) buffer); - } else if( pixelType.GetComponentType() == itk::ImageIOBase::FLOAT ) { - importer.SetBufferAsFloat((float*) buffer); - } else if( pixelType.GetComponentType() == itk::ImageIOBase::SHORT) { - importer.SetBufferAsInt16((int16_t*) buffer); - } else if( pixelType.GetComponentType() == itk::ImageIOBase::CHAR ) { - importer.SetBufferAsInt8((int8_t*) buffer); - } else if( pixelType.GetComponentType() == itk::ImageIOBase::INT ) { - importer.SetBufferAsInt32((int32_t*) buffer); - } else if( pixelType.GetComponentType() == itk::ImageIOBase::LONG ) { - importer.SetBufferAsInt64((int64_t*) buffer); - } else if( pixelType.GetComponentType() == itk::ImageIOBase::UCHAR ) { - importer.SetBufferAsUInt8((uint8_t*) buffer); - } else if( pixelType.GetComponentType() == itk::ImageIOBase::UINT ) { - importer.SetBufferAsUInt32((uint32_t*) buffer); - } else if( pixelType.GetComponentType() == itk::ImageIOBase::ULONG ) { - importer.SetBufferAsUInt64((uint64_t*) buffer); - } else if( pixelType.GetComponentType() == itk::ImageIOBase::USHORT ) { - importer.SetBufferAsUInt16((uint16_t*) buffer); - } - - return importer.Execute(); -} - -mitk::Image::Pointer mitk::SimpleItkToMitkImage(sitk::Image& sitkImage) -{ - mitk::Image::Pointer image = mitk::Image::New(); - void* buffer = NULL; - mitk::PixelType pixelType = MakeScalarPixelType(); - std::vector sitkSpacing = sitkImage.GetSpacing(); - double spacing[3] = { sitkSpacing[0], sitkSpacing[1], sitkSpacing[2] }; - std::vector sitkOrigin = sitkImage.GetOrigin(); - double origin[3] = { sitkOrigin[0], sitkOrigin[1], sitkOrigin[2] }; - std::vector sitkSize = sitkImage.GetSize(); - unsigned int dimensions[4] = { 1,1,1,1}; - - for ( size_t i = 0; i < sitkSize.size(); ++i ) - dimensions[i] = sitkSize[i]; - - size_t size = 0; - if ( sitkImage.GetPixelIDValue() == sitk::sitkInt8 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsInt8(); - size = sizeof(char); - } else if( sitkImage.GetPixelIDValue() == sitk::sitkInt16 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsInt16(); - size = sizeof(short); - } else if( sitkImage.GetPixelIDValue() == sitk::sitkInt32 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsInt32(); - size = sizeof(int); - } else if( sitkImage.GetPixelIDValue() == sitk::sitkInt64 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsInt64(); - size = sizeof(long); - } else if( sitkImage.GetPixelIDValue() == sitk::sitkUInt8 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsUInt8(); - size = sizeof(unsigned char); - } else if( sitkImage.GetPixelIDValue() == sitk::sitkUInt16 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsUInt16(); - size = sizeof(unsigned short); - } else if( sitkImage.GetPixelIDValue() == sitk::sitkUInt32 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsUInt32(); - size = sizeof(unsigned int); - } else if( sitkImage.GetPixelIDValue() == sitk::sitkUInt64 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsUInt64(); - size = sizeof(unsigned long); - } else if( sitkImage.GetPixelIDValue() == sitk::sitkFloat32 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsFloat(); - size = sizeof(float); - } else if( sitkImage.GetPixelIDValue() == sitk::sitkFloat64 ) { - pixelType = MakeScalarPixelType(); - buffer = (void*) sitkImage.GetBufferAsDouble(); - size = sizeof(double); - } - - image->Initialize(pixelType,sitkImage.GetDimension(),dimensions); - image->SetSpacing(spacing); - image->SetOrigin(origin); - - for(size_t i = 0; i < sitkSize.size(); ++i ) - size *= sitkSize[i]; - - mitk::ImageWriteAccessor wa(image); - - memcpy(wa.GetData(),buffer, size); - - return image; -} - class mitkPythonWrappingTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPythonWrappingTestSuite); MITK_TEST(testImageTransfer); MITK_TEST(testSurfaceTransfer); MITK_TEST(testVtkCreateConePythonSnippet); MITK_TEST(testVtkDecimateProPythonSnippet); MITK_TEST(testSimpleITKMedianFilterSnippet); CPPUNIT_TEST_SUITE_END(); private: mitk::PythonService* m_PythonService; mitk::Image::Pointer m_Image; mitk::Surface::Pointer m_Surface; QMap m_Snippets; public: void setUp() { //get the context of the python module us::Module* module = us::ModuleRegistry::GetModule("MitkPython"); us::ModuleContext* context = module->GetModuleContext(); //get the service which is generated in the PythonModuleActivator us::ServiceReference serviceRef = context->GetServiceReference(); m_PythonService = dynamic_cast( context->GetService(serviceRef) ); m_Image = mitk::IOUtil::LoadImage(GetTestDataFilePath("Pic3D.nrrd")); m_Surface = mitk::IOUtil::LoadSurface(GetTestDataFilePath("binary.stl")); QmitkPythonSnippets::LoadStringMap(QmitkPythonSnippets::DEFAULT_SNIPPET_FILE,m_Snippets); } void tearDown() { m_Image = NULL; m_Surface = NULL; } void testImageTransfer() { std::string varName("mitkImage"); CPPUNIT_ASSERT_MESSAGE ( "Is SimpleITK Python Wrapping available?", m_PythonService->IsSimpleItkPythonWrappingAvailable() == true ); CPPUNIT_ASSERT_MESSAGE( "Valid image copied to python import should return true.", m_PythonService->CopyToPythonAsSimpleItkImage( m_Image, varName) == true ); mitk::Image::Pointer pythonImage = m_PythonService->CopySimpleItkImageFromPython(varName); CPPUNIT_ASSERT_MESSAGE( "Compare if images are equal after transfer.", mitk::Equal(pythonImage,m_Image) ); } void testSurfaceTransfer() { std::string varName("mitkSurface"); CPPUNIT_ASSERT_MESSAGE ( "Is VTK Python Wrapping available?", m_PythonService->IsVtkPythonWrappingAvailable() == true ); CPPUNIT_ASSERT_MESSAGE( "Valid surface copied to python import should return true.", m_PythonService->CopyToPythonAsVtkPolyData( m_Surface, varName) == true ); mitk::Surface::Pointer pythonSurface = m_PythonService->CopyVtkPolyDataFromPython(varName); CPPUNIT_ASSERT_MESSAGE( "Compare if surfaces are equal after transfer.", mitk::Equal(pythonSurface,m_Surface) ); } void testVtkCreateConePythonSnippet() { // cone in cpp mitk::Surface::Pointer mitkSurface = mitk::Surface::New(); vtkSmartPointer coneSrc = vtkSmartPointer::New(); coneSrc->SetResolution(60); coneSrc->SetCenter(-2,0,0); coneSrc->Update(); mitkSurface->SetVtkPolyData(coneSrc->GetOutput()); // run python code CPPUNIT_ASSERT_MESSAGE ( "Is VTK Python Wrapping available?", m_PythonService->IsVtkPythonWrappingAvailable() == true ); m_PythonService->Execute( m_Snippets["vtk: create cone"].toStdString(), mitk::IPythonService::MULTI_LINE_COMMAND ); mitk::Surface::Pointer pythonSurface = m_PythonService->CopyVtkPolyDataFromPython("cone"); CPPUNIT_ASSERT_MESSAGE( "Compare if cones are equal.", mitk::Equal(pythonSurface, mitkSurface) ); } void testVtkDecimateProPythonSnippet() { // decimate pro in cpp mitk::Surface::Pointer mitkSurface = mitk::Surface::New(); vtkSmartPointer deci = vtkSmartPointer::New(); deci->SetInputData(m_Surface->GetVtkPolyData()); deci->SetTargetReduction(0.9); deci->PreserveTopologyOn(); deci->Update(); mitkSurface->SetVtkPolyData(deci->GetOutput()); // decimate pro in python CPPUNIT_ASSERT_MESSAGE ( "Is VTK Python Wrapping available?", m_PythonService->IsVtkPythonWrappingAvailable() == true ); CPPUNIT_ASSERT_MESSAGE( "Valid surface copied to python import should return true.", m_PythonService->CopyToPythonAsVtkPolyData( m_Surface, "mitkSurface") == true ); m_PythonService->Execute( m_Snippets["vtk.vtkDecimatePro"].toStdString(), mitk::IPythonService::MULTI_LINE_COMMAND ); mitk::Surface::Pointer pythonSurface = m_PythonService->CopyVtkPolyDataFromPython("mitkSurface_new"); CPPUNIT_ASSERT_MESSAGE( "Compare if surfaces are equal.", mitk::Equal(pythonSurface, mitkSurface) ); } void testSimpleITKMedianFilterSnippet() { // simple itk median filter in cpp sitk::MedianImageFilter medianFilter; medianFilter.SetRadius(1); - sitk::Image sitkImage = medianFilter.Execute(mitk::MitkToSimpleItkImage(m_Image)); - mitk::Image::Pointer mitkImage = mitk::SimpleItkToMitkImage(sitkImage); + sitk::Image sitkImage = medianFilter.Execute(mitk::SimpleItkImageImport::MitkToSimpleItkImage(m_Image)); + mitk::Image::Pointer mitkImage = mitk::SimpleItkImageImport::SimpleItkToMitkImage(sitkImage); // simple itk median filter in python CPPUNIT_ASSERT_MESSAGE ( "Is SimpleItk Python Wrapping available?", m_PythonService->IsSimpleItkPythonWrappingAvailable() == true ); CPPUNIT_ASSERT_MESSAGE( "Valid image copied to python import should return true.", m_PythonService->CopyToPythonAsSimpleItkImage(m_Image, "mitkImage") == true ); m_PythonService->Execute( m_Snippets["medianfilter"].toStdString(), mitk::IPythonService::MULTI_LINE_COMMAND ); mitk::Image::Pointer pythonImage = m_PythonService->CopySimpleItkImageFromPython("mitkImage_new"); - CPPUNIT_ASSERT_MESSAGE( "Compare if surfaces are equal.", mitk::Equal(pythonImage, mitkImage) ); + CPPUNIT_ASSERT_MESSAGE( "Compare if images are equal.", mitk::Equal(pythonImage, mitkImage) ); } - //TODO opencv median filter }; MITK_TEST_SUITE_REGISTRATION(mitkPythonWrapping) diff --git a/Modules/Python/files.cmake b/Modules/Python/files.cmake index 66fb3a3ce7..2e49e2d5b5 100644 --- a/Modules/Python/files.cmake +++ b/Modules/Python/files.cmake @@ -1,28 +1,29 @@ SET(CPP_FILES mitkIPythonService.cpp mitkPythonActivator.cpp mitkPythonService.cpp + mitkSimpleItkImageImport.cpp QmitkCtkPythonShell.cpp QmitkPythonVariableStackTableModel.cpp QmitkPythonVariableStackTableView.cpp QmitkPythonScriptEditorHighlighter.cpp QmitkPythonTextEditor.cpp QmitkPythonSnippets.cpp ) #SET(UI_FILES # QmitkPythonSnippets.ui #) SET(MOC_H_FILES QmitkCtkPythonShell.h QmitkPythonVariableStackTableModel.h QmitkPythonVariableStackTableView.h QmitkPythonScriptEditorHighlighter.h QmitkPythonTextEditor.h QmitkPythonSnippets.h ) set(QRC_FILES resources/mitkPython.qrc ) diff --git a/Modules/Python/mitkPythonService.cpp b/Modules/Python/mitkPythonService.cpp index 60d9953bf0..c30afb389f 100644 --- a/Modules/Python/mitkPythonService.cpp +++ b/Modules/Python/mitkPythonService.cpp @@ -1,639 +1,639 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPythonService.h" #include #include #include #include #include #include "PythonPath.h" #include #include #include #include #include #ifndef WIN32 #include #endif const QString mitk::PythonService::m_TmpDataFileName("temp_mitk_data_file"); #ifdef USE_MITK_BUILTIN_PYTHON static char* pHome = NULL; #endif mitk::PythonService::PythonService() : m_ItkWrappingAvailable( true ), m_OpenCVWrappingAvailable( true ), m_VtkWrappingAvailable( true ), m_ErrorOccured( false ) { { MITK_DEBUG << "will init python if necessary"; } bool pythonInitialized = static_cast( Py_IsInitialized() ); //m_PythonManager.isPythonInitialized() ); { MITK_DEBUG << "pythonInitialized " << pythonInitialized; MITK_DEBUG << "m_PythonManager.isPythonInitialized() " << 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( !m_PythonManager.isPythonInitialized() ) { try { #ifndef WIN32 dlopen(PYTHON_LIBRARY_NAME, RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL); #endif std::string programPath = mitk::IOUtil::GetProgramPath(); QDir programmDir( QString( programPath.c_str() ).append("/Python") ); QString pythonCommand; // Set the pythonpath variable depending if // we have an installer or development environment if ( programmDir.exists() ) { // runtime directory used in installers pythonCommand.append( QString("import sys\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/Python')\n").arg(programPath.c_str()) ); pythonCommand.append( QString("sys.path.append('%1/Python/SimpleITK')").arg(programPath.c_str()) ); // set python home if own runtime is deployed } else { pythonCommand.append(PYTHONPATH_COMMAND); } if( pythonInitialized ) m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut|PythonQt::PythonAlreadyInitialized); else m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut); // set python home if own runtime is used #ifdef USE_MITK_BUILTIN_PYTHON QString pythonHome; if ( programmDir.exists() ) pythonHome.append(QString("%1/Python").arg(programPath.c_str())); else pythonHome.append(PYTHONHOME); if(pHome) delete[] pHome; pHome = new char[pythonHome.toStdString().length() + 1]; strcpy(pHome,pythonHome.toStdString().c_str()); Py_SetPythonHome(pHome); MITK_DEBUG("PythonService") << "PythonHome: " << pHome; #endif MITK_DEBUG("PythonService") << "initalizing python"; m_PythonManager.initialize(); #ifdef USE_MITK_BUILTIN_PYTHON PyObject* dict = PyDict_New(); // Import builtin modules if (PyDict_GetItemString(dict, "__builtins__") == NULL) { PyObject* builtinMod = PyImport_ImportModule("__builtin__"); if (builtinMod == NULL || PyDict_SetItemString(dict, "__builtins__", builtinMod) != 0) { Py_DECREF(dict); Py_XDECREF(dict); return; } Py_DECREF(builtinMod); } #endif MITK_DEBUG("PythonService")<< "Python Search paths: " << Py_GetPath(); MITK_DEBUG("PythonService") << "python initalized"; MITK_DEBUG("PythonService") << "registering python paths" << PYTHONPATH_COMMAND; m_PythonManager.executeString( pythonCommand, ctkAbstractPythonManager::FileInput ); } catch (...) { MITK_DEBUG("PythonService") << "exception initalizing python"; } } } mitk::PythonService::~PythonService() { MITK_DEBUG("mitk::PythonService") << "destructing PythonService"; #ifdef USE_MITK_BUILTIN_PYTHON if(pHome) delete[] pHome; #endif } std::string mitk::PythonService::Execute(const std::string &stdpythonCommand, int commandType) { QString pythonCommand = QString::fromStdString(stdpythonCommand); { MITK_DEBUG("mitk::PythonService") << "pythonCommand = " << pythonCommand.toStdString(); MITK_DEBUG("mitk::PythonService") << "commandType = " << commandType; } QVariant result; bool commandIssued = true; if(commandType == IPythonService::SINGLE_LINE_COMMAND ) result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::SingleInput ); else if(commandType == IPythonService::MULTI_LINE_COMMAND ) result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::FileInput ); else if(commandType == IPythonService::EVAL_COMMAND ) 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 ) { m_PythonManager.executeFile(QString::fromStdString(pythonScript)); } std::vector mitk::PythonService::GetVariableStack() const { std::vector list; PyObject* dict = PyImport_GetModuleDict(); PyObject* object = PyDict_GetItemString(dict, "__main__"); PyObject* dirMain = PyObject_Dir(object); PyObject* tempObject = 0; PyObject* strTempObject = 0; if(dirMain) { std::string name, attrValue, attrType; for(int i = 0; iob_type->tp_name; strTempObject = PyObject_Repr(tempObject); if(strTempObject && ( PyUnicode_Check(strTempObject) || PyString_Check(strTempObject) ) ) attrValue = PyString_AsString(strTempObject); else attrValue = ""; mitk::PythonVariable var; var.m_Name = name; var.m_Value = attrValue; var.m_Type = attrType; list.push_back(var); } } return list; } bool mitk::PythonService::DoesVariableExist(const std::string& name) const { 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) { if(!m_Observer.contains(observer)) m_Observer.append(observer); } void mitk::PythonService::RemovePythonCommandObserver(mitk::PythonCommandObserver *observer) { m_Observer.removeOne(observer); } void mitk::PythonService::NotifyObserver(const std::string &command) { MITK_DEBUG("mitk::PythonService") << "number of observer " << m_Observer.size(); for( int i=0; i< m_Observer.size(); ++i ) { m_Observer.at(i)->CommandExecuted(command); } } QString mitk::PythonService::GetTempDataFileName(const std::string& ext) const { QString tmpFolder = QDir::tempPath(); QString fileName = tmpFolder + QDir::separator() + m_TmpDataFileName + QString::fromStdString(ext); return fileName; } bool mitk::PythonService::CopyToPythonAsSimpleItkImage(mitk::Image *image, const std::string &stdvarName) { QString varName = QString::fromStdString( stdvarName ); QString command; unsigned int* imgDim = image->GetDimensions(); int npy_nd = 1; npy_intp* npy_dims = new npy_intp[1]; npy_dims[0] = imgDim[0] * imgDim[1] * imgDim[2]; // access python module PyObject *pyMod = PyImport_AddModule((char*)"__main__"); // global dictionarry 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 = NULL; mitk::ImageReadAccessor racc(image); void* array = (void*) racc.GetData(); // 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 { MITK_WARN << "not a scalar 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,%3,%4,sitk.%5)\n").arg(varName) .arg(QString::number(imgDim[0])) .arg(QString::number(imgDim[1])) .arg(QString::number(imgDim[2])) .arg(QString(sitk_type.c_str())) ); 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("sitk._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(); this->Execute( command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); return true; } mitk::Image::Pointer mitk::PythonService::CopySimpleItkImageFromPython(const std::string &stdvarName) { double*ds = NULL; // access python module PyObject *pyMod = PyImport_AddModule((char*)"__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").arg(varName) ); MITK_DEBUG("PythonService") << "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() ); size_t sz = sizeof(short); mitk::PixelType pixelType = MakeScalarPixelType(); if( dtype.compare("float64") == 0 ) { pixelType = MakeScalarPixelType(); sz = sizeof(double); } else if( dtype.compare("float32") == 0 ) { pixelType = MakeScalarPixelType(); sz = sizeof(float); } else if( dtype.compare("int16") == 0) { pixelType = MakeScalarPixelType(); sz = sizeof(short); } else if( dtype.compare("int8") == 0 ) { pixelType = MakeScalarPixelType(); sz = sizeof(char); } else if( dtype.compare("int32") == 0 ) { pixelType = MakeScalarPixelType(); sz = sizeof(int); } else if( dtype.compare("int64") == 0 ) { pixelType = MakeScalarPixelType(); sz = sizeof(long); } else if( dtype.compare("uint8") == 0 ) { pixelType = MakeScalarPixelType(); sz = sizeof(unsigned char); } else if( dtype.compare("uint32") == 0 ) { pixelType = MakeScalarPixelType(); sz = sizeof(unsigned int); } else if( dtype.compare("uint64") == 0 ) { pixelType = MakeScalarPixelType(); sz = sizeof(unsigned long); } else if( dtype.compare("uint16") == 0 ) { pixelType = MakeScalarPixelType(); sz = sizeof(unsigned short); } unsigned int* dimensions = new unsigned int[py_data->nd]; // fill backwards , nd data saves dimensions in opposite direction for( int i = 0; i < py_data->nd; ++i ) { dimensions[i] = py_data->dimensions[py_data->nd - 1 - i]; sz *= dimensions[i]; } mitkImage->Initialize(pixelType, py_data->nd, dimensions); // copy data mitk::ImageWriteAccessor iwa(mitkImage); memcpy( iwa.GetData(), py_data->data, sz); ds = (double*)py_spacing->data; spacing[0] = ds[0]; spacing[1] = ds[1]; spacing[2] = ds[2]; mitkImage->GetGeometry()->SetSpacing(spacing); ds = (double*)py_origin->data; origin[0] = ds[0]; - origin[0] = ds[0]; - origin[0] = ds[0]; + origin[1] = ds[1]; + origin[2] = ds[2]; mitkImage->GetGeometry()->SetOrigin(origin); // 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").arg(varName) ); MITK_DEBUG("PythonService") << "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 ) { QString varName = QString::fromStdString( stdvarName ); bool convert = false; if(image->GetDimension() != 2) { MITK_ERROR << "Only 2D images allowed for OpenCV images"; return convert; } // try to save mitk image QString fileName = this->GetTempDataFileName( ".bmp" ); fileName = QDir::fromNativeSeparators( fileName ); MITK_DEBUG("PythonService") << "Saving temporary file " << fileName.toStdString(); if( !mitk::IOUtil::SaveImage(image, fileName.toStdString()) ) { MITK_ERROR << "Temporary file " << fileName.toStdString() << " could not be created."; return convert; } QString command; command.append( QString("%1 = cv2.imread(\"%2\")\n") .arg( varName ).arg( fileName ) ); MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); MITK_DEBUG("PythonService") << "Removing file " << fileName.toStdString(); QFile file(fileName); file.remove(); convert = true; return convert; } mitk::Image::Pointer mitk::PythonService::CopyCvImageFromPython( const std::string& stdvarName ) { QString varName = QString::fromStdString( stdvarName ); mitk::Image::Pointer mitkImage; QString command; QString fileName = GetTempDataFileName( ".bmp" ); fileName = QDir::fromNativeSeparators( fileName ); MITK_DEBUG("PythonService") << "run python command to save image with opencv to " << fileName.toStdString(); command.append( QString( "cv2.imwrite(\"%1\", %2)\n").arg( fileName ).arg( varName ) ); MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); try { MITK_DEBUG("PythonService") << "Loading temporary file " << fileName.toStdString() << " as MITK image"; mitkImage = mitk::IOUtil::LoadImage( fileName.toStdString() ); } catch(std::exception& e) { MITK_ERROR << e.what(); } QFile file(fileName); if( file.exists() ) { MITK_DEBUG("PythonService") << "Removing temporary file " << fileName.toStdString(); file.remove(); } return mitkImage; } ctkAbstractPythonManager *mitk::PythonService::GetPythonManager() { return &m_PythonManager; } mitk::Surface::Pointer mitk::PythonService::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 = NULL; // 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(); 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(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); return surface; } bool mitk::PythonService::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(); this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); return true; } bool mitk::PythonService::IsSimpleItkPythonWrappingAvailable() { this->Execute( "import SimpleITK as sitk\n", IPythonService::SINGLE_LINE_COMMAND ); //this->Execute( "import itk\n", IPythonService::SINGLE_LINE_COMMAND ); //this->Execute( "print \"Using ITK version \" + itk.Version.GetITKVersion()\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() { this->Execute( "import cv2\n", IPythonService::SINGLE_LINE_COMMAND ); m_OpenCVWrappingAvailable = !this->PythonErrorOccured(); return m_OpenCVWrappingAvailable; } bool mitk::PythonService::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 { return m_ErrorOccured; } diff --git a/Modules/Python/mitkSimpleItkImageImport.cpp b/Modules/Python/mitkSimpleItkImageImport.cpp new file mode 100644 index 0000000000..52e25fd20d --- /dev/null +++ b/Modules/Python/mitkSimpleItkImageImport.cpp @@ -0,0 +1,147 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +#include "mitkSimpleItkImageImport.h" +#include +#include +#include + +namespace sitk = itk::simple; + +sitk::Image mitk::SimpleItkImageImport::MitkToSimpleItkImage( mitk::Image* image ) +{ + const mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); + mitk::Point3D origin = image->GetGeometry()->GetOrigin(); + mitk::PixelType pixelType = image->GetPixelType(); + mitk::ImageReadAccessor ra(image); + void* buffer = (void*) ra.GetData(); + sitk::ImportImageFilter importer; + + std::vector sitkSpacing; + sitkSpacing.push_back(spacing[0]); + sitkSpacing.push_back(spacing[1]); + sitkSpacing.push_back(spacing[2]); + std::vector sitkOrigin; + sitkOrigin.push_back(origin[0]); + sitkOrigin.push_back(origin[1]); + sitkOrigin.push_back(origin[2]); + std::vector sitkSize; + + for ( unsigned int i = 0; i < image->GetDimension(); ++i ) + sitkSize.push_back(image->GetDimensions()[i]); + + importer.SetSpacing(sitkSpacing); + importer.SetSize(sitkSize); + importer.SetOrigin(sitkOrigin); + + if( pixelType.GetComponentType() == itk::ImageIOBase::DOUBLE ) { + importer.SetBufferAsDouble((double*) buffer); + } else if( pixelType.GetComponentType() == itk::ImageIOBase::FLOAT ) { + importer.SetBufferAsFloat((float*) buffer); + } else if( pixelType.GetComponentType() == itk::ImageIOBase::SHORT) { + importer.SetBufferAsInt16((int16_t*) buffer); + } else if( pixelType.GetComponentType() == itk::ImageIOBase::CHAR ) { + importer.SetBufferAsInt8((int8_t*) buffer); + } else if( pixelType.GetComponentType() == itk::ImageIOBase::INT ) { + importer.SetBufferAsInt32((int32_t*) buffer); + } else if( pixelType.GetComponentType() == itk::ImageIOBase::LONG ) { + importer.SetBufferAsInt64((int64_t*) buffer); + } else if( pixelType.GetComponentType() == itk::ImageIOBase::UCHAR ) { + importer.SetBufferAsUInt8((uint8_t*) buffer); + } else if( pixelType.GetComponentType() == itk::ImageIOBase::UINT ) { + importer.SetBufferAsUInt32((uint32_t*) buffer); + } else if( pixelType.GetComponentType() == itk::ImageIOBase::ULONG ) { + importer.SetBufferAsUInt64((uint64_t*) buffer); + } else if( pixelType.GetComponentType() == itk::ImageIOBase::USHORT ) { + importer.SetBufferAsUInt16((uint16_t*) buffer); + } + + return importer.Execute(); +} + +mitk::Image::Pointer mitk::SimpleItkImageImport::SimpleItkToMitkImage( sitk::Image& sitkImage ) +{ + mitk::Image::Pointer image = mitk::Image::New(); + void* buffer = NULL; + mitk::PixelType pixelType = MakeScalarPixelType(); + std::vector sitkSpacing = sitkImage.GetSpacing(); + double spacing[3] = { sitkSpacing[0], sitkSpacing[1], sitkSpacing[2] }; + std::vector sitkOrigin = sitkImage.GetOrigin(); + double origin[3] = { sitkOrigin[0], sitkOrigin[1], sitkOrigin[2] }; + std::vector sitkSize = sitkImage.GetSize(); + unsigned int dimensions[4] = { 1,1,1,1}; + + for ( size_t i = 0; i < sitkSize.size(); ++i ) + dimensions[i] = sitkSize[i]; + + size_t size = 0; + if ( sitkImage.GetPixelIDValue() == sitk::sitkInt8 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsInt8(); + size = sizeof(char); + } else if( sitkImage.GetPixelIDValue() == sitk::sitkInt16 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsInt16(); + size = sizeof(short); + } else if( sitkImage.GetPixelIDValue() == sitk::sitkInt32 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsInt32(); + size = sizeof(int); + } else if( sitkImage.GetPixelIDValue() == sitk::sitkInt64 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsInt64(); + size = sizeof(long); + } else if( sitkImage.GetPixelIDValue() == sitk::sitkUInt8 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsUInt8(); + size = sizeof(unsigned char); + } else if( sitkImage.GetPixelIDValue() == sitk::sitkUInt16 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsUInt16(); + size = sizeof(unsigned short); + } else if( sitkImage.GetPixelIDValue() == sitk::sitkUInt32 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsUInt32(); + size = sizeof(unsigned int); + } else if( sitkImage.GetPixelIDValue() == sitk::sitkUInt64 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsUInt64(); + size = sizeof(unsigned long); + } else if( sitkImage.GetPixelIDValue() == sitk::sitkFloat32 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsFloat(); + size = sizeof(float); + } else if( sitkImage.GetPixelIDValue() == sitk::sitkFloat64 ) { + pixelType = MakeScalarPixelType(); + buffer = (void*) sitkImage.GetBufferAsDouble(); + size = sizeof(double); + } + + image->Initialize(pixelType,sitkImage.GetDimension(),dimensions); + image->SetSpacing(spacing); + image->SetOrigin(origin); + + for(size_t i = 0; i < sitkSize.size(); ++i ) + size *= sitkSize[i]; + + mitk::ImageWriteAccessor wa(image); + + memcpy(wa.GetData(),buffer, size); + + return image; +} diff --git a/Modules/Python/mitkSimpleItkImageImport.h b/Modules/Python/mitkSimpleItkImageImport.h new file mode 100644 index 0000000000..1c01f743f8 --- /dev/null +++ b/Modules/Python/mitkSimpleItkImageImport.h @@ -0,0 +1,56 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __MITKSIMPLEITKIMAGEIMPORT_H +#define __MITKSIMPLEITKIMAGEIMPORT_H + +#include +#include + +// Export macro +#include + +namespace mitk +{ + +class Image; + +/** @brief Class that provides methods to copy a SimpleITK image to an MITK image + * and vice versa. + */ +class MITK_PYTHON_EXPORT SimpleItkImageImport +{ + +public: + + /** + * Copy the content of a MITK image into an SimpleITK image. + * @param The source MITK image. + * @returns A copy of the MITK image as SimpleITK image. + */ + static itk::simple::Image MitkToSimpleItkImage(mitk::Image* image); + + /** + * This method deep copies an SimpleITK image into a MITK image and return it. + * @param The source image + * @returns A copy as MITK image. + */ + static itk::SmartPointer SimpleItkToMitkImage(itk::simple::Image& sitkImage); +}; + +} + +#endif