Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkNumpyArrayConversion.cxx
Go to the documentation of this file.
1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18 
19 #include <stdint.h>
20 #include <string.h>
21 
22 #include <numeric>
23 #include <functional>
24 
25 #include "mitkImage.h"
26 
27 
28 // Python is written in C
29 #ifdef __cplusplus
30 extern "C"
31 {
32 #endif
33 
34 
39 static PyObject *
40 mitk_GetMemoryViewFromImage( PyObject *SWIGUNUSEDPARM(self), PyObject *args )
41 {
42  const void * mitkBufferPtr;
43  Py_ssize_t len;
44  std::vector< unsigned int > size;
45  size_t pixelSize = 1;
46 
47  unsigned int dimension;
48 
49  /* Cast over to a sitk Image. */
50  PyObject * pyImage;
51  void * voidImage;
52  mitk::Image * mitkImage;
53  int res = 0;
54 
55  PyObject * memoryView = NULL;
56  Py_buffer pyBuffer;
57  memset(&pyBuffer, 0, sizeof(Py_buffer));
58 
59  unsigned int accumulatorValue = 1;
60 
61  if( !PyArg_ParseTuple( args, "O", &pyImage ) )
62  {
63  SWIG_fail; // SWIG_fail is a macro that says goto: fail (return NULL)
64  }
65  res = SWIG_ConvertPtr( pyImage, &voidImage, SWIGTYPE_p_mitk__Image, 0 );
66  if (!SWIG_IsOK(res))
67  {
68  mitk::Image::Pointer tmpImage;
69  res = SWIG_ConvertPtr(pyImage, &voidImage, SWIGTYPE_p_itk__SmartPointerT_mitk__Image_t, 0);
70  if (!SWIG_IsOK(res))
71  {
72  SWIG_exception_fail(SWIG_ArgError(res), "in method 'GetByteArrayFromImage', argument needs to be of type 'sitk::Image *'");
73  }
74  tmpImage = *(reinterpret_cast<mitk::Image::Pointer *>(voidImage));
75  voidImage = reinterpret_cast<void*>(tmpImage.GetPointer());
76  }
77  mitkImage = reinterpret_cast< mitk::Image * >( voidImage );
78 
79  mitkBufferPtr = mitkImage->GetData();
80  pixelSize = mitkImage->GetPixelType().GetBitsPerComponent() / 8;
81 
82  dimension = mitkImage->GetDimension();
83  for (int i = 0; i < dimension; ++i)
84  {
85  size.push_back(mitkImage->GetDimension(i));
86  }
87 
88  // if the image is a vector just treat is as another dimension
89  if ( mitkImage->GetPixelType().GetNumberOfComponents() > 1 )
90  {
91  size.push_back( mitkImage->GetPixelType().GetNumberOfComponents() );
92  }
93 
94  len = std::accumulate( size.begin(), size.end(), accumulatorValue, std::multiplies<unsigned int>() );
95  len *= pixelSize;
96 
97  if (PyBuffer_FillInfo(&pyBuffer, NULL, (void*)mitkBufferPtr, len, true, PyBUF_CONTIG_RO)!=0)
98  {
99  SWIG_fail;
100  }
101  memoryView = PyMemoryView_FromBuffer(&pyBuffer);
102 
103  PyBuffer_Release(&pyBuffer);
104  return memoryView;
105 
106 fail:
107  Py_XDECREF( memoryView );
108  return NULL;
109 }
110 
115 static PyObject*
116 mitk_SetImageFromArray( PyObject *SWIGUNUSEDPARM(self), PyObject *args )
117 {
118  PyObject * pyImage = NULL;
119 
120  const void *buffer;
121  Py_ssize_t buffer_len;
122  Py_buffer pyBuffer;
123  memset(&pyBuffer, 0, sizeof(Py_buffer));
124 
125  mitk::Image * mitkImage = NULL;
126  void * mitkBufferPtr = NULL;
127  size_t pixelSize = 1;
128 
129  unsigned int dimension = 0;
130  std::vector< unsigned int > size;
131  size_t len = 1;
132 
133  unsigned int accuValue = 1;
134 
135  // We wish to support both the new PEP3118 buffer interface and the
136  // older. So we first try to parse the arguments with the new buffer
137  // protocol, then the old.
138  if (!PyArg_ParseTuple( args, "s*O", &pyBuffer, &pyImage ) )
139  {
140  PyErr_Clear();
141 
142 #ifdef PY_SSIZE_T_CLEAN
143  typedef Py_ssize_t bufSizeType;
144 #else
145  typedef int bufSizeType;
146 #endif
147 
148  bufSizeType _len;
149  // This function takes 2 arguments from python, the first is an
150  // python object which support the old "ReadBuffer" interface
151  if( !PyArg_ParseTuple( args, "s#O", &buffer, &_len, &pyImage ) )
152  {
153  return NULL;
154  }
155  buffer_len = _len;
156  }
157  else
158  {
159  if ( PyBuffer_IsContiguous( &pyBuffer, 'C' ) != 1 )
160  {
161  PyBuffer_Release( &pyBuffer );
162  PyErr_SetString( PyExc_TypeError, "A C Contiguous buffer object is required." );
163  return NULL;
164  }
165  buffer_len = pyBuffer.len;
166  buffer = pyBuffer.buf;
167  }
168 
169  /* Cast over to a sitk Image. */
170  {
171  void * voidImage;
172  int res = 0;
173  res = SWIG_ConvertPtr( pyImage, &voidImage, SWIGTYPE_p_mitk__Image, 0 );
174  if (!SWIG_IsOK(res))
175  {
176  mitk::Image::Pointer tmpImage;
177  res = SWIG_ConvertPtr(pyImage, &voidImage, SWIGTYPE_p_itk__SmartPointerT_mitk__Image_t, 0);
178  if (!SWIG_IsOK(res))
179  {
180  SWIG_exception_fail(SWIG_ArgError(res), "in method 'GetByteArrayFromImage', argument needs to be of type 'sitk::Image *'");
181  }
182  tmpImage = *(reinterpret_cast<mitk::Image::Pointer *>(voidImage));
183  voidImage = reinterpret_cast<void*>(tmpImage.GetPointer());
184  }
185  mitkImage = reinterpret_cast< mitk::Image * >(voidImage);
186  }
187 
188  try
189  {
190  mitkBufferPtr = mitkImage->GetData();
191  pixelSize= mitkImage->GetPixelType().GetBitsPerComponent() / 8;
192  }
193  catch( const std::exception &e )
194  {
195  std::string msg = "Exception thrown in MITK new Image: ";
196  msg += e.what();
197  PyErr_SetString( PyExc_RuntimeError, msg.c_str() );
198  goto fail;
199  }
200 
201  dimension = mitkImage->GetDimension();
202  for (int i = 0; i < dimension; ++i)
203  {
204  size.push_back(mitkImage->GetDimension(i));
205  }
206 
207  // if the image is a vector just treat is as another dimension
208  if (mitkImage->GetPixelType().GetNumberOfComponents() > 1)
209  {
210  size.push_back(mitkImage->GetPixelType().GetNumberOfComponents());
211  }
212 
213  len = std::accumulate(size.begin(), size.end(), accuValue, std::multiplies<unsigned int>());
214  len *= pixelSize;
215 
216  if ( buffer_len != len )
217  {
218  PyErr_SetString( PyExc_RuntimeError, "Size mismatch of image and Buffer." );
219  goto fail;
220  }
221 
222  memcpy( (void *)mitkBufferPtr, buffer, len );
223 
224 
225  PyBuffer_Release( &pyBuffer );
226  Py_RETURN_NONE;
227 
228 fail:
229  PyBuffer_Release( &pyBuffer );
230  return NULL;
231 }
232 
233 
234 
235 #ifdef __cplusplus
236 } // end extern "C"
237 #endif
vcl_size_t GetBitsPerComponent() const
Get the number of bits per components.
const mitk::PixelType GetPixelType(int n=0) const
Returns the PixelType of channel n.
Definition: mitkImage.cpp:101
vcl_size_t GetNumberOfComponents() const
Get the number of components of which each element consists.
static PyObject * mitk_GetMemoryViewFromImage(PyObject *SWIGUNUSEDPARM(self), PyObject *args)
static PyObject * mitk_SetImageFromArray(PyObject *SWIGUNUSEDPARM(self), PyObject *args)
unsigned int GetDimension() const
Get dimension of the image.
Definition: mitkImage.cpp:106
Image class for storing images.
Definition: mitkImage.h:72
virtual void * GetData()
Get the data vector of the complete image, i.e., of all channels linked together. ...
Definition: mitkImage.cpp:118