diff --git a/Wrapping/Common/mitk_swig_common.i b/Wrapping/Common/mitk_swig_common.i index 9574fdca48..53d701c85a 100644 --- a/Wrapping/Common/mitk_swig_common.i +++ b/Wrapping/Common/mitk_swig_common.i @@ -1,31 +1,35 @@ // Ignore common warnings: // 302 : Redefinition of Macro, usually not a problem // 362 : Operator= is ignored. Can't help it. // 503 : Can't wrap operator of type "*" unless renamed to a valid identifier, no problem as operator not needed. // 509 : Overloaded function ignored. Usually not a problem, as overloaded functions shouldn't give different results. // 511 : Can't use keyword arguments with overloaded functions #pragma SWIG nowarn=302,362,503,509,511 // Splitted the information about the addition files into sub-files: +%naturalvar; + +// Includes of STD-Files goes in here +%include // Include c++ code in this file. It is basically a c++-header wrapped in the commands so it is included in the std-file %include // SWIG-Macro definition goes in here, for example SWIG_ADD_MITK_CLASS %include -// Includes of STD-Files goes in here -%include // information about classes that are going to be wrapped are in here: %include // // How to wrap a new class: // ------------------------------------ // 1. Add the c++ include file to mitk_swig_cpp_include.i // If the class is in a new module, make sure that this module is added as dependency in cmake // 2. Add the class definition in mitk_swig_classes.i // If the definition of the class needs new macros, for example because it is not in the core // and has a new Export-Macro, be sure to define this macro first. // If the class inherit from mitk::BaseData use the SWIG_ADD_MITK_CLASS macro, as it defines // some redundante code. -// \ No newline at end of file +// + +std::vector mitk::GetImageSize(mitk::Image::Pointer image); \ No newline at end of file diff --git a/Wrapping/Common/mitk_swig_cpp_include.i b/Wrapping/Common/mitk_swig_cpp_include.i index 975a2bdc01..e0151493c6 100644 --- a/Wrapping/Common/mitk_swig_cpp_include.i +++ b/Wrapping/Common/mitk_swig_cpp_include.i @@ -1,15 +1,107 @@ %{ #include #include #include #include #include #include #include // SWIG Doesn't wrap namespaces. This leads to some problems, if the namespaces are not used. using namespace mitk; using namespace itk; -%} \ No newline at end of file + +std::vector GetImageSize(mitk::Image::Pointer image) +{ + std::vector< unsigned int > size; + unsigned int dimension = image->GetDimension(); + for (int i = 0; i < dimension; ++i) + { + size.push_back(image->GetDimension(i)); + } + return size; +} + +std::vector GetImageSize(mitk::Image* image) +{ + std::vector< unsigned int > size; + unsigned int dimension = image->GetDimension(); + for (int i = 0; i < dimension; ++i) + { + size.push_back(image->GetDimension(i)); + } + return size; +} + +struct TypeDefinitions +{ + static const int ComponentTypeUInt8 = mitk::MapPixelType::value>::IOComponentType; + static const int ComponentTypeInt8 = mitk::MapPixelType::value>::IOComponentType; + static const int ComponentTypeUInt16 = mitk::MapPixelType::value>::IOComponentType; + static const int ComponentTypeInt16 = mitk::MapPixelType::value>::IOComponentType; + static const int ComponentTypeUInt32 = mitk::MapPixelType::value>::IOComponentType; + static const int ComponentTypeInt32 = mitk::MapPixelType::value>::IOComponentType; + static const int ComponentTypeFloat = mitk::MapPixelType::value>::IOComponentType; + static const int ComponentTypeDouble = mitk::MapPixelType::value>::IOComponentType; +}; + +mitk::PixelType MakePixelTypeFromTypeID(int componentTypeID, int numberOfComponents) +{ + switch (componentTypeID) + { + case TypeDefinitions::ComponentTypeUInt8 : + return mitk::MakePixelType(numberOfComponents); + case TypeDefinitions::ComponentTypeInt8 : + return mitk::MakePixelType(numberOfComponents); + case TypeDefinitions::ComponentTypeUInt16 : + return mitk::MakePixelType(numberOfComponents); + case TypeDefinitions::ComponentTypeInt16 : + return mitk::MakePixelType(numberOfComponents); + case TypeDefinitions::ComponentTypeUInt32 : + return mitk::MakePixelType(numberOfComponents); + case TypeDefinitions::ComponentTypeInt32 : + return mitk::MakePixelType(numberOfComponents); + case TypeDefinitions::ComponentTypeFloat : + return mitk::MakePixelType(numberOfComponents); + case TypeDefinitions::ComponentTypeDouble : + return mitk::MakePixelType(numberOfComponents); + default: + return mitk::MakePixelType(numberOfComponents); + } +} + +mitk::Image::Pointer MakeImage(mitk::PixelType pixelType, std::vector shape) +{ + mitk::Image::Pointer image = mitk::Image::New(); + image->Initialize(pixelType, shape.size(), shape.data()); + return image; +} + +template +typename T::Pointer ConvertTo(mitk::BaseData::Pointer base) +{ + typename T::Pointer erg = dynamic_cast(base.GetPointer()); + return erg; +} + +%} + +std::vector GetImageSize(mitk::Image::Pointer image); +std::vector GetImageSize(mitk::Image* image); +mitk::PixelType MakePixelTypeFromTypeID(int componentTypeID, int numberOfComponents); +mitk::Image::Pointer MakeImage(mitk::PixelType pixelType, std::vector shape); + +%constant int ComponentTypeUInt8 = TypeDefinitions::ComponentTypeUInt8; +%constant int ComponentTypeInt8 = TypeDefinitions::ComponentTypeInt8; +%constant int ComponentTypeUInt16 = TypeDefinitions::ComponentTypeUInt16; +%constant int ComponentTypeInt16 = TypeDefinitions::ComponentTypeInt16; +%constant int ComponentTypeUInt32 = TypeDefinitions::ComponentTypeUInt32; +%constant int ComponentTypeInt32 = TypeDefinitions::ComponentTypeInt32; +%constant int ComponentTypeFloat = TypeDefinitions::ComponentTypeFloat; +%constant int ComponentTypeDouble = TypeDefinitions::ComponentTypeDouble; + +template +typename T::Pointer ConvertTo(mitk::BaseData::Pointer base); + diff --git a/Wrapping/Common/mitk_swig_macros.i b/Wrapping/Common/mitk_swig_macros.i index 98a7bb977a..29c0103d46 100644 --- a/Wrapping/Common/mitk_swig_macros.i +++ b/Wrapping/Common/mitk_swig_macros.i @@ -1,28 +1,78 @@ // // This file contains macros for swig. // // // SWIG_ADD_MITK_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_MITK_CLASS(classname, classinclude) // Declaring that this class is a smart-pointer class, in order to handle // online upcasting where necessary (for example python) %feature("smartptr", noblock=1) mitk:: ## classname { itk::SmartPointer } // Include the given header, where the class definition is found %include - + typedef mitk:: ## classname classname ## ; // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. - %template(Vector ## classname ## Pointer) std::vector< itk::SmartPointer >; + %template(Vector ## classname ## Pointer) std::vector< mitk:: ## classname ## ::Pointer >; + //%template(Vector ## classname ## Pointer) std::vector< mitk:: ## classname ## ::Pointer >; + //%template(Vector ## classname ## Pointer) std::vector< itk::SmartPointer >; %template(Vector ## classname) std::vector< mitk:: ## classname ## ::Self *>; // Defining the Smartpointer, allows easy access in target language %template(classname ## Pointer) itk::SmartPointer; + + // Define a conversion method to convert from and to types + %template(ConvertTo ## classname) ConvertTo; + + + // This extend is necessary to have the automatic cast methods available +%extend itk::SmartPointer { + %pythoncode %{ + def _GetListOfValidItems(self): + return [str(k) for k in self.GetClassHierarchy() if k in convertion_list.keys() ] + %} + %pythoncode %{ + def __getattr__(self, item): + if type(item)==str: + if (len(item) > 9) and ('ConvertTo' in item): + searchString=item[9:] + if searchString in self._GetListOfValidItems(): + def func_t(): + return convertion_list[searchString](self) + return func_t + %} + %pythoncode %{ + def __dir__(self): + return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] + %} +} + +%extend classname { + %pythoncode %{ + def _GetListOfValidItems(self): + return [str(k) for k in self.GetClassHierarchy() if k in convertion_list.keys() ] + %} + %pythoncode %{ + def __getattr__(self, item): + if type(item)==str: + if (len(item) > 9) and ('ConvertTo' in item): + searchString=item[9:] + if searchString in self._GetListOfValidItems(): + def func_t(): + return convertion_list[searchString](self) + return func_t + %} + %pythoncode %{ + def __dir__(self): + return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] + %} +} + %enddef \ No newline at end of file diff --git a/Wrapping/Python/CMakeLists.txt b/Wrapping/Python/CMakeLists.txt index 96630c936c..524678ad82 100644 --- a/Wrapping/Python/CMakeLists.txt +++ b/Wrapping/Python/CMakeLists.txt @@ -1,77 +1,77 @@ # Version 2.8.1 is the minium requirement for this script. # this is lower than the general minimum requirement. #cmake_minimum_required ( VERSION 2.8.1 FATAL_ERROR ) include(mitkTargetLinkLibrariesWithDynamicLookup) project( MITK_Python ) set(CMAKE_SHARED_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) set(CMAKE_MODULE_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) mitk_check_dynamic_lookup(MODULE SHARED MITK_UNDEFINED_SYMBOLS_ALLOWED ) # # Find the necessary libraries etc.. # if ( MITK_UNDEFINED_SYMBOLS_ALLOWED ) set( _QUIET_LIBRARY "QUIET" ) else() set( _QUIET_LIBRARY "REQUIRED" ) endif() find_package ( PythonInterp REQUIRED ) find_package ( PythonLibs ${_QUIET_LIBRARY} ) - +include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ) # # Options # option ( MITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) mark_as_advanced( MITK_PYTHON_THREADS ) option ( MITK_PYTHON_EGG "Add building of python eggs to the dist target." OFF ) mark_as_advanced( MITK_PYTHON_EGG ) option ( MITK_PYTHON_WHEEL "Add building of python wheels to the dist target." ON ) mark_as_advanced( MITK_PYTHON_WHEEL ) # Prepare the SWIG-File, i.e. especially add necessary include folders mitkSwigPrepareFiles(MITK.i "MitkCore") # Add additional SWIG Parameters # These parameters depend on the target language set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_GLOBAL_FLAGS} -features autodoc=1 -keyword ) if( MITK_PYTHON_THREADS ) set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} -threads) endif() set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}) # Create the actual SWIG project swig_add_module(PythonMITK python MITK.i ) mitkSwigAddLibraryDependencies(PythonMITK "MitkCore") mitk_target_link_libraries_with_dynamic_lookup(${SWIG_MODULE_PythonMITK_REAL_NAME} ${PYTHON_LIBRARIES}) if(DEFINED SKBUILD) message(WARNING "SKBuild exists") # Currently this installation install(FILES ${CMAKE_CURRENT_BINARY_DIR}/PythonMITK.py ${CMAKE_CURRENT_SOURCE_DIR}/Packaging/__init__.py # ${SimpleITK_DOC_FILES} DESTINATION PythonMITK COMPONENT Runtime ) install(TARGETS ${SWIG_MODULE_PythonMITK_REAL_NAME} RUNTIME DESTINATION PythonMITK LIBRARY DESTINATION PythonMITK COMPONENT Runtime ) else() message(WARNING "SKBuild missing") include(LegacyPackaging.cmake) endif() diff --git a/Wrapping/Python/MITK.i b/Wrapping/Python/MITK.i index 536ae52089..1b29b9178d 100644 --- a/Wrapping/Python/MITK.i +++ b/Wrapping/Python/MITK.i @@ -1,4 +1,172 @@ %module PythonMITK %include +%{ +#include "mitkNumpyArrayConversion.cxx" +%} + +// Numpy array conversion support +%native(_GetMemoryViewFromImage) PyObject *mitk_GetMemoryViewFromImage( PyObject *self, PyObject *args ); +%native(_SetImageFromArray) PyObject *mitk_SetImageFromArray( PyObject *(self), PyObject *args ); + + +%pythoncode %{ + +HAVE_NUMPY = True +try: + import numpy +except ImportError: + HAVE_NUMPY = False + + +def _get_numpy_dtype( mitkImage ): + """Given a MITK image, returns the numpy.dtype which describes the data""" + + if not HAVE_NUMPY: + raise ImportError('Numpy not available.') + + # this is a mapping from MITK's pixel id to numpy's dtype + _mitk_np = {ComponentTypeUInt8:numpy.uint8, + ComponentTypeUInt16:numpy.uint16, + ComponentTypeUInt32:numpy.uint32, + ComponentTypeInt8:numpy.int8, + ComponentTypeInt16:numpy.int16, + ComponentTypeInt32:numpy.int32, + ComponentTypeFloat:numpy.float32, + ComponentTypeDouble:numpy.float64, + } + + return _mitk_np[ mitkImage.GetPixelType().GetComponentType() ] + + + +def _get_mitk_pixelid(numpy_array_type): + """Returns a SimpleITK PixelID given a numpy array.""" + + if not HAVE_NUMPY: + raise ImportError('Numpy not available.') + + # This is a Mapping from numpy array types to sitks pixel types. + _np_mitk = {numpy.character:ComponentTypeUInt8, + numpy.uint8:ComponentTypeUInt8, + numpy.uint16:ComponentTypeUInt16, + numpy.uint32:ComponentTypeUInt32, + numpy.int8:ComponentTypeInt8, + numpy.int16:ComponentTypeInt16, + numpy.int32:ComponentTypeInt32, + numpy.float32:ComponentTypeFloat, + numpy.float64:ComponentTypeDouble, + } + + try: + return _np_mitk[numpy_array_type.dtype] + except KeyError: + for key in _np_mitk: + if numpy.issubdtype(numpy_array_type.dtype, key): + return _np_mitk[key] + raise TypeError('dtype: {0} is not supported.'.format(numpy_array_type.dtype)) + +def _get_sitk_vector_pixelid(numpy_array_type): + """Returns a SimpleITK vecotr PixelID given a numpy array.""" + + if not HAVE_NUMPY: + raise ImportError('Numpy not available.') + + # This is a Mapping from numpy array types to sitks pixel types. + _np_sitk = {numpy.character:sitkVectorUInt8, + numpy.uint8:sitkVectorUInt8, + numpy.uint16:sitkVectorUInt16, + numpy.uint32:sitkVectorUInt32, + numpy.uint64:sitkVectorUInt64, + numpy.int8:sitkVectorInt8, + numpy.int16:sitkVectorInt16, + numpy.int32:sitkVectorInt32, + numpy.int64:sitkVectorInt64, + numpy.float32:sitkVectorFloat32, + numpy.float64:sitkVectorFloat64, + } + + try: + return _np_sitk[numpy_array_type.dtype] + except KeyError: + for key in _np_sitk: + if numpy.issubdtype(numpy_array_type.dtype, key): + return _np_sitk[key] + raise TypeError('dtype: {0} is not supported.'.format(numpy_array_type.dtype)) + + +# SimplyITK <-> Numpy Array conversion support. +#http://www.nickdarnell.com/swig-casting-revisited/ +def GetArrayViewFromImage(image): + """Get a NumPy ndarray view of a SimpleITK Image. + + Returns a Numpy ndarray object as a "view" of the SimpleITK's Image buffer. This reduces pixel buffer copies, but requires that the SimpleITK image object is kept around while the buffer is being used. + + + """ + + if not HAVE_NUMPY: + raise ImportError('NumPy not available.') + + dtype = _get_numpy_dtype( image ) + + shape = GetImageSize(image); + if image.GetPixelType().GetNumberOfComponents() > 1: + shape = ( image.GetPixelType().GetNumberOfComponents(), ) + shape + + imageMemoryView = _PythonMITK._GetMemoryViewFromImage(image) + arrayView = numpy.asarray(imageMemoryView).view(dtype = dtype) + arrayView.shape = shape[::-1] + + return arrayView + +def GetArrayFromImage(image): + """Get a NumPy ndarray from a SimpleITK Image. + + This is a deep copy of the image buffer and is completely safe and without potential side effects. + """ + + # TODO: If the image is already not unique then a second copy may be made before the numpy copy is done. + arrayView = GetArrayViewFromImage(image) + + # perform deep copy of the image buffer + return numpy.array(arrayView, copy=True) + +def GetImageFromArray( arr, isVector=False): + """Get a SimpleITK Image from a numpy array. If isVector is True, then a 3D array will be treated as a 2D vector image, otherwise it will be treated as a 3D image""" + + if not HAVE_NUMPY: + raise ImportError('Numpy not available.') + + z = numpy.asarray( arr ) + + assert z.ndim in ( 2, 3, 4 ), \ + "Only arrays of 2, 3 or 4 dimensions are supported." + + id = _get_mitk_pixelid( z ) + #img = Image_New() + + if ( z.ndim == 3 and isVector ) or (z.ndim == 4): + pixelType=MakePixelTypeFromTypeID(id, z.shape[-1]) + newShape=VectorUInt32(z.shape[-2::-1]) + img = MakeImage(pixelType, newShape) + #img.Initialize(pixelType, z.ndim - 1, z.shape[-2::-1]) + elif z.ndim in ( 2, 3 ): + pixelType=MakePixelTypeFromTypeID(id, 1) + newShape=VectorUInt32(z.shape[::-1]) + img = MakeImage(pixelType, newShape) + #img.Initialize(pixelType, z.ndim, z.shape[::-1]) + + _PythonMITK._SetImageFromArray( z.tostring(), img ) + + return img + +convertion_list = {'Image':ConvertToImage, + 'SlicedData':ConvertToSlicedData, + 'BaseData':ConvertToBaseData} + +%} + + + diff --git a/Wrapping/Python/mitkNumpyArrayConversion.cxx b/Wrapping/Python/mitkNumpyArrayConversion.cxx new file mode 100644 index 0000000000..ce45d5e2fd --- /dev/null +++ b/Wrapping/Python/mitkNumpyArrayConversion.cxx @@ -0,0 +1,234 @@ +/*========================================================================= +* +* Copyright Insight Software Consortium +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*=========================================================================*/ + +#include +#include + +#include +#include + +#include "mitkImage.h" + + +// Python is written in C +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** An internal function that returns a memoryview object to the + * SimpleITK Image's buffer (shallow). The correct copy and writing + * policies need to be done by the end-user method. + */ +static PyObject * +mitk_GetMemoryViewFromImage( PyObject *SWIGUNUSEDPARM(self), PyObject *args ) +{ + const void * mitkBufferPtr; + Py_ssize_t len; + std::vector< unsigned int > size; + size_t pixelSize = 1; + + unsigned int dimension; + + /* Cast over to a sitk Image. */ + PyObject * pyImage; + void * voidImage; + mitk::Image * mitkImage; + int res = 0; + + PyObject * memoryView = NULL; + Py_buffer pyBuffer; + memset(&pyBuffer, 0, sizeof(Py_buffer)); + + + if( !PyArg_ParseTuple( args, "O", &pyImage ) ) + { + SWIG_fail; // SWIG_fail is a macro that says goto: fail (return NULL) + } + res = SWIG_ConvertPtr( pyImage, &voidImage, SWIGTYPE_p_mitk__Image, 0 ); + if (!SWIG_IsOK(res)) + { + mitk::Image::Pointer tmpImage; + res = SWIG_ConvertPtr(pyImage, &voidImage, SWIGTYPE_p_itk__SmartPointerT_mitk__Image_t, 0); + if (!SWIG_IsOK(res)) + { + SWIG_exception_fail(SWIG_ArgError(res), "in method 'GetByteArrayFromImage', argument needs to be of type 'sitk::Image *'"); + } + tmpImage = *(reinterpret_cast(voidImage)); + voidImage = reinterpret_cast(tmpImage.GetPointer()); + } + mitkImage = reinterpret_cast< mitk::Image * >( voidImage ); + + mitkBufferPtr = mitkImage->GetData(); + pixelSize = mitkImage->GetPixelType().GetBitsPerComponent() / 8; + + dimension = mitkImage->GetDimension(); + for (int i = 0; i < dimension; ++i) + { + size.push_back(mitkImage->GetDimension(i)); + } + + // if the image is a vector just treat is as another dimension + if ( mitkImage->GetPixelType().GetNumberOfComponents() > 1 ) + { + size.push_back( mitkImage->GetPixelType().GetNumberOfComponents() ); + } + + len = std::accumulate( size.begin(), size.end(), unsigned int(1), std::multiplies() ); + len *= pixelSize; + + if (PyBuffer_FillInfo(&pyBuffer, NULL, (void*)mitkBufferPtr, len, true, PyBUF_CONTIG_RO)!=0) + { + SWIG_fail; + } + memoryView = PyMemoryView_FromBuffer(&pyBuffer); + + PyBuffer_Release(&pyBuffer); + return memoryView; + +fail: + Py_XDECREF( memoryView ); + return NULL; +} + +/** An internal function that performs a deep copy of the image buffer + * into a python byte array. The byte array can later be converted + * into a numpy array with the frombuffer method. + */ +static PyObject* +mitk_SetImageFromArray( PyObject *SWIGUNUSEDPARM(self), PyObject *args ) +{ + PyObject * pyImage = NULL; + + const void *buffer; + Py_ssize_t buffer_len; + Py_buffer pyBuffer; + memset(&pyBuffer, 0, sizeof(Py_buffer)); + + mitk::Image * mitkImage = NULL; + void * mitkBufferPtr = NULL; + size_t pixelSize = 1; + + unsigned int dimension = 0; + std::vector< unsigned int > size; + size_t len = 1; + + // We wish to support both the new PEP3118 buffer interface and the + // older. So we first try to parse the arguments with the new buffer + // protocol, then the old. + if (!PyArg_ParseTuple( args, "s*O", &pyBuffer, &pyImage ) ) + { + PyErr_Clear(); + +#ifdef PY_SSIZE_T_CLEAN + typedef Py_ssize_t bufSizeType; +#else + typedef int bufSizeType; +#endif + + bufSizeType _len; + // This function takes 2 arguments from python, the first is an + // python object which support the old "ReadBuffer" interface + if( !PyArg_ParseTuple( args, "s#O", &buffer, &_len, &pyImage ) ) + { + return NULL; + } + buffer_len = _len; + } + else + { + if ( PyBuffer_IsContiguous( &pyBuffer, 'C' ) != 1 ) + { + PyBuffer_Release( &pyBuffer ); + PyErr_SetString( PyExc_TypeError, "A C Contiguous buffer object is required." ); + return NULL; + } + buffer_len = pyBuffer.len; + buffer = pyBuffer.buf; + } + + /* Cast over to a sitk Image. */ + { + void * voidImage; + int res = 0; + res = SWIG_ConvertPtr( pyImage, &voidImage, SWIGTYPE_p_mitk__Image, 0 ); + if (!SWIG_IsOK(res)) + { + mitk::Image::Pointer tmpImage; + res = SWIG_ConvertPtr(pyImage, &voidImage, SWIGTYPE_p_itk__SmartPointerT_mitk__Image_t, 0); + if (!SWIG_IsOK(res)) + { + SWIG_exception_fail(SWIG_ArgError(res), "in method 'GetByteArrayFromImage', argument needs to be of type 'sitk::Image *'"); + } + tmpImage = *(reinterpret_cast(voidImage)); + voidImage = reinterpret_cast(tmpImage.GetPointer()); + } + mitkImage = reinterpret_cast< mitk::Image * >(voidImage); + } + + try + { + mitkBufferPtr = mitkImage->GetData(); + pixelSize= mitkImage->GetPixelType().GetBitsPerComponent() / 8; + } + catch( const std::exception &e ) + { + std::string msg = "Exception thrown in SimpleITK new Image: "; + msg += e.what(); + PyErr_SetString( PyExc_RuntimeError, msg.c_str() ); + goto fail; + } + + dimension = mitkImage->GetDimension(); + for (int i = 0; i < dimension; ++i) + { + size.push_back(mitkImage->GetDimension(i)); + } + + // if the image is a vector just treat is as another dimension + if (mitkImage->GetPixelType().GetNumberOfComponents() > 1) + { + size.push_back(mitkImage->GetPixelType().GetNumberOfComponents()); + } + + len = std::accumulate(size.begin(), size.end(), unsigned int(1), std::multiplies()); + len *= pixelSize; + + if ( buffer_len != len ) + { + PyErr_SetString( PyExc_RuntimeError, "Size mismatch of image and Buffer." ); + goto fail; + } + + memcpy( (void *)mitkBufferPtr, buffer, len ); + + + PyBuffer_Release( &pyBuffer ); + Py_RETURN_NONE; + +fail: + PyBuffer_Release( &pyBuffer ); + return NULL; +} + + + +#ifdef __cplusplus +} // end extern "C" +#endif