LArOpenCV  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
NDArrayConverter.cxx
Go to the documentation of this file.
1 // Original Code author: Sudeep Pillai (spillai@csail.mit.edu)
2 // Modified for OpenCV 3.0: Kazuhiro Terao (kazuhiro@nevis.columbia.edu)
3 // Note: Stripped from Opencv (opencv/modules/python/src2/cv2.cpp)
4 
5 # include "NDArrayConverter.h"
6 /*
7  * The following conversion functions are taken/adapted from OpenCV's cv2.cpp file
8  * inside modules/python/src2 folder.
9  */
10 
11 // Change for OpenCV 2
12 #define OPENCV_3 1
13 
14 namespace larcv {
15  namespace convert {
16 
17  /*
18  static void init()
19  {
20  import_array();
21  }
22  */
23 
24  static int failmsg(const char *fmt, ...)
25  {
26  char str[1000];
27 
28  va_list ap;
29  va_start(ap, fmt);
30  vsnprintf(str, sizeof(str), fmt, ap);
31  va_end(ap);
32 
33  PyErr_SetString(PyExc_TypeError, str);
34  return 0;
35  }
36 
37  class PyAllowThreads
38  {
39  public:
40  PyAllowThreads() : _state(PyEval_SaveThread()) {}
41  ~PyAllowThreads()
42  {
43  PyEval_RestoreThread(_state);
44  }
45  private:
46  PyThreadState* _state;
47  };
48 
49  class PyEnsureGIL
50  {
51  public:
52  PyEnsureGIL() : _state(PyGILState_Ensure()) {}
53  ~PyEnsureGIL()
54  {
55  PyGILState_Release(_state);
56  }
57  private:
58  PyGILState_STATE _state;
59  };
60 
61  /*
62  static PyObject* failmsgp(const char *fmt, ...)
63  {
64  char str[1000];
65 
66  va_list ap;
67  va_start(ap, fmt);
68  vsnprintf(str, sizeof(str), fmt, ap);
69  va_end(ap);
70 
71  PyErr_SetString(PyExc_TypeError, str);
72  return 0;
73  }
74  */
75 #if OPENCV_3
76  class NumpyAllocator : public ::cv::MatAllocator
77  {
78  public:
79  NumpyAllocator() { stdAllocator = ::cv::Mat::getStdAllocator(); }
80  ~NumpyAllocator() {}
81 
82  ::cv::UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const
83  {
84  ::cv::UMatData* u = new ::cv::UMatData(this);
85  u->data = u->origdata = (uchar*)PyArray_DATA((PyArrayObject*) o);
86  npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o);
87  for( int i = 0; i < dims - 1; i++ )
88  step[i] = (size_t)_strides[i];
89  step[dims-1] = CV_ELEM_SIZE(type);
90  u->size = sizes[0]*step[0];
91  u->userdata = o;
92  return u;
93  }
94 
95  virtual ::cv::UMatData* allocate(int dims0, const int* sizes, int type,
96  void* data, size_t* step, int flags,
97  ::cv::UMatUsageFlags usageFlags) const
98  {
99  if( data != 0 )
100  {
101  CV_Error(::cv::Error::StsAssert, "The data should normally be NULL!");
102  // probably this is safe to do in such extreme case
103  return stdAllocator->allocate(dims0, sizes, type, data, step, flags, usageFlags);
104  }
105  PyEnsureGIL gil;
106 
107  int depth = CV_MAT_DEPTH(type);
108  int cn = CV_MAT_CN(type);
109  const int f = (int)(sizeof(size_t)/8);
110  int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
111  depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
112  depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
113  depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
114  int i, dims = dims0;
115  ::cv::AutoBuffer<npy_intp> _sizes(dims + 1);
116  for( i = 0; i < dims; i++ )
117  _sizes[i] = sizes[i];
118  if( cn > 1 )
119  _sizes[dims++] = cn;
120  PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum);
121  if(!o)
122  CV_Error_(::cv::Error::StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
123  return allocate(o, dims0, sizes, type, step);
124  }
125 
126  bool allocate(::cv::UMatData* u, int accessFlags, ::cv::UMatUsageFlags usageFlags) const
127  {
128  return stdAllocator->allocate(u, accessFlags, usageFlags);
129  }
130 
131  void deallocate(::cv::UMatData* u) const
132  {
133  if(u)
134  {
135  PyEnsureGIL gil;
136  PyObject* o = (PyObject*)u->userdata;
137  Py_XDECREF(o);
138  delete u;
139  }
140  }
141 
142  const ::cv::MatAllocator* stdAllocator;
143  };
144 #else
145  class NumpyAllocator : public ::cv::MatAllocator
146  {
147  public:
148  NumpyAllocator() {}
149  ~NumpyAllocator() {}
150 
151  void allocate(int dims, const int* sizes, int type, int*& refcount,
152  uchar*& datastart, uchar*& data, size_t* step)
153  {
154  PyEnsureGIL gil;
155 
156  int depth = CV_MAT_DEPTH(type);
157  int cn = CV_MAT_CN(type);
158  const int f = (int)(sizeof(size_t)/8);
159  int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
160  depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
161  depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
162  depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
163  int i;
164  npy_intp _sizes[CV_MAX_DIM+1];
165  for( i = 0; i < dims; i++ )
166  _sizes[i] = sizes[i];
167  if( cn > 1 )
168  {
169  /*if( _sizes[dims-1] == 1 )
170  _sizes[dims-1] = cn;
171  else*/
172  _sizes[dims++] = cn;
173  }
174  PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum);
175  if(!o)
176  CV_Error_(CV_StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
177  refcount = refcountFromPyObject(o);
178  npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o);
179  for( i = 0; i < dims - (cn > 1); i++ )
180  step[i] = (size_t)_strides[i];
181  datastart = data = (uchar*)PyArray_DATA((PyArrayObject*) o);
182  }
183 
184  void deallocate(int* refcount, uchar*, uchar*)
185  {
186  PyEnsureGIL gil;
187  if( !refcount )
188  return;
189  PyObject* o = pyObjectFromRefcount(refcount);
190  Py_INCREF(o);
191  Py_DECREF(o);
192  }
193  };
194 #endif
195 
196 
197 
198  NumpyAllocator g_numpyAllocator;
199 
201 
203  {
204  import_array();
205  }
206 
207  ::cv::Mat NDArrayConverter::toMat(const PyObject *o)
208  {
209  ::cv::Mat m;
210 
211  if(!o || o == Py_None)
212  {
213  if( !m.data )
214  m.allocator = &g_numpyAllocator;
215  }
216 
217  if( !PyArray_Check(o) )
218  {
219  failmsg("toMat: Object is not a numpy array");
220  }
221 
222  int typenum = PyArray_TYPE(o);
223  int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S :
224  typenum == NPY_USHORT ? CV_16U : typenum == NPY_SHORT ? CV_16S :
225  typenum == NPY_INT || typenum == NPY_LONG ? CV_32S :
226  typenum == NPY_FLOAT ? CV_32F :
227  typenum == NPY_DOUBLE ? CV_64F : -1;
228 
229  if( type < 0 )
230  {
231  failmsg("toMat: Data type = %d is not supported", typenum);
232  }
233 
234  int ndims = PyArray_NDIM(o);
235 
236  if(ndims >= CV_MAX_DIM)
237  {
238  failmsg("toMat: Dimensionality (=%d) is too high", ndims);
239  }
240 
241  int size[CV_MAX_DIM+1];
242  size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type);
243  const npy_intp* _sizes = PyArray_DIMS(o);
244  const npy_intp* _strides = PyArray_STRIDES(o);
245  bool transposed = false;
246 
247  for(int i = 0; i < ndims; i++)
248  {
249  size[i] = (int)_sizes[i];
250  step[i] = (size_t)_strides[i];
251  }
252 
253  if( ndims == 0 || step[ndims-1] > elemsize ) {
254  size[ndims] = 1;
255  step[ndims] = elemsize;
256  ndims++;
257  }
258 
259  if( ndims >= 2 && step[0] < step[1] )
260  {
261  std::swap(size[0], size[1]);
262  std::swap(step[0], step[1]);
263  transposed = true;
264  }
265 
266  // std::cerr << " ndims: " << ndims
267  // << " size: " << size
268  // << " type: " << type
269  // << " step: " << step
270  // << " size: " << size[2] << std::endl;
271 
272  // TODO: Possible bug in multi-dimensional matrices
273 #if 0
274  if( ndims == 3 && size[2] <= CV_CN_MAX && step[1] == elemsize*size[2] )
275  {
276  ndims--;
277  type |= CV_MAKETYPE(0, size[2]);
278  }
279 #endif
280 
281  if( ndims > 2)
282  {
283  failmsg("toMat: Object has more than 2 dimensions");
284  }
285 
286  m = ::cv::Mat(ndims, size, type, PyArray_DATA(o), step);
287  // m.u = g_numpyAllocator.allocate(o, ndims, size, type, step);
288 
289  if( m.data )
290  {
291 #if OPENCV_3
292  m.addref();
293  Py_INCREF(o);
294 #else
295  m.refcount = refcountFromPyObject(o);
296  m.addref(); // protect the original numpy array from deallocation
297  // (since Mat destructor will decrement the reference counter)
298 #endif
299  };
300  m.allocator = &g_numpyAllocator;
301 
302  if( transposed )
303  {
304  ::cv::Mat tmp;
305  tmp.allocator = &g_numpyAllocator;
306  transpose(m, tmp);
307  m = tmp;
308  }
309  return m;
310  }
311 
313  {
314 #if OPENCV_3
315  if( !m.data )
316  Py_RETURN_NONE;
317  ::cv::Mat temp, *p = (::cv::Mat*)&m;
318  if(!p->u || p->allocator != &g_numpyAllocator)
319  {
320  temp.allocator = &g_numpyAllocator;
321  m.copyTo(temp);
322  p = &temp;
323  }
324  PyObject* o = (PyObject*)p->u->userdata;
325  Py_INCREF(o);
326  // p->addref();
327  // pyObjectFromRefcount(p->refcount);
328  return o;
329 #else
330  if( !m.data )
331  Py_RETURN_NONE;
332  ::cv::Mat temp, *p = (::cv::Mat*)&m;
333  if(!p->refcount || p->allocator != &g_numpyAllocator)
334  {
335  temp.allocator = &g_numpyAllocator;
336  ERRWRAP2(m.copyTo(temp));
337  p = &temp;
338  }
339  p->addref();
340  return pyObjectFromRefcount(p->refcount);
341 #endif
342  }
343 
345  {
346  return nullptr;
347  }
348  PyObject* NDArrayConverter::toNDArray(const ::larcv::Point2DArray& pt_v)
349  {
350  int* dim_data = new int[2];
351  dim_data[0] = 2;
352  dim_data[1] = (int)(pt_v.size());
353 
354  return PyArray_FromDimsAndData( 2, dim_data, NPY_DOUBLE, (char*) &(pt_v._data[0]) );
355  }
356  } // namespace convert
357 } // namespace imutil