module_opencv3.cpp
Go to the documentation of this file.
1 // Taken from opencv/modules/python/src2/cv2.cpp
2 
3 #include "module.hpp"
4 
5 #include "opencv2/core/types_c.h"
6 
7 #include "opencv2/opencv_modules.hpp"
8 
9 #include "pycompat.hpp"
10 
11 static PyObject* opencv_error = 0;
12 
13 static int failmsg(const char *fmt, ...)
14 {
15  char str[1000];
16 
17  va_list ap;
18  va_start(ap, fmt);
19  vsnprintf(str, sizeof(str), fmt, ap);
20  va_end(ap);
21 
22  PyErr_SetString(PyExc_TypeError, str);
23  return 0;
24 }
25 
26 struct ArgInfo
27 {
28  const char * name;
29  bool outputarg;
30  // more fields may be added if necessary
31 
32  ArgInfo(const char * name_, bool outputarg_)
33  : name(name_)
34  , outputarg(outputarg_) {}
35 
36  // to match with older pyopencv_to function signature
37  operator const char *() const { return name; }
38 };
39 
40 class PyAllowThreads
41 {
42 public:
43  PyAllowThreads() : _state(PyEval_SaveThread()) {}
45  {
46  PyEval_RestoreThread(_state);
47  }
48 private:
49  PyThreadState* _state;
50 };
51 
53 {
54 public:
55  PyEnsureGIL() : _state(PyGILState_Ensure()) {}
57  {
58  PyGILState_Release(_state);
59  }
60 private:
61  PyGILState_STATE _state;
62 };
63 
64 #define ERRWRAP2(expr) \
65 try \
66 { \
67  PyAllowThreads allowThreads; \
68  expr; \
69 } \
70 catch (const cv::Exception &e) \
71 { \
72  PyErr_SetString(opencv_error, e.what()); \
73  return 0; \
74 }
75 
76 using namespace cv;
77 
78 static PyObject* failmsgp(const char *fmt, ...)
79 {
80  char str[1000];
81 
82  va_list ap;
83  va_start(ap, fmt);
84  vsnprintf(str, sizeof(str), fmt, ap);
85  va_end(ap);
86 
87  PyErr_SetString(PyExc_TypeError, str);
88  return 0;
89 }
90 
91 class NumpyAllocator : public MatAllocator
92 {
93 public:
94  NumpyAllocator() { stdAllocator = Mat::getStdAllocator(); }
96 
97  UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const
98  {
99  UMatData* u = new UMatData(this);
100  u->data = u->origdata = (uchar*)PyArray_DATA((PyArrayObject*) o);
101  npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o);
102  for( int i = 0; i < dims - 1; i++ )
103  step[i] = (size_t)_strides[i];
104  step[dims-1] = CV_ELEM_SIZE(type);
105  u->size = sizes[0]*step[0];
106  u->userdata = o;
107  return u;
108  }
109 
110  UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, int flags, UMatUsageFlags usageFlags) const
111  {
112  if( data != 0 )
113  {
114  CV_Error(Error::StsAssert, "The data should normally be NULL!");
115  // probably this is safe to do in such extreme case
116  return stdAllocator->allocate(dims0, sizes, type, data, step, flags, usageFlags);
117  }
118  PyEnsureGIL gil;
119 
120  int depth = CV_MAT_DEPTH(type);
121  int cn = CV_MAT_CN(type);
122  const int f = (int)(sizeof(size_t)/8);
123  int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
124  depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
125  depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
126  depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
127  int i, dims = dims0;
128  cv::AutoBuffer<npy_intp> _sizes(dims + 1);
129  for( i = 0; i < dims; i++ )
130  _sizes[i] = sizes[i];
131  if( cn > 1 )
132  _sizes[dims++] = cn;
133  PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum);
134  if(!o)
135  CV_Error_(Error::StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
136  return allocate(o, dims0, sizes, type, step);
137  }
138 
139  bool allocate(UMatData* u, int accessFlags, UMatUsageFlags usageFlags) const
140  {
141  return stdAllocator->allocate(u, accessFlags, usageFlags);
142  }
143 
144  void deallocate(UMatData* u) const
145  {
146  if(u)
147  {
148  PyEnsureGIL gil;
149  PyObject* o = (PyObject*)u->userdata;
150  Py_XDECREF(o);
151  delete u;
152  }
153  }
154 
155  const MatAllocator* stdAllocator;
156 };
157 
159 
160 
161 template<typename T> static
162 bool pyopencv_to(PyObject* obj, T& p, const char* name = "<unknown>");
163 
164 template<typename T> static
165 PyObject* pyopencv_from(const T& src);
166 
167 enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 };
168 
169 // special case, when the convertor needs full ArgInfo structure
170 static bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo info)
171 {
172  // to avoid PyArray_Check() to crash even with valid array
173  do_numpy_import( );
174 
175 
176  bool allowND = true;
177  if(!o || o == Py_None)
178  {
179  if( !m.data )
180  m.allocator = &g_numpyAllocator;
181  return true;
182  }
183 
184  if( PyInt_Check(o) )
185  {
186  double v[] = {(double)PyInt_AsLong((PyObject*)o), 0., 0., 0.};
187  m = Mat(4, 1, CV_64F, v).clone();
188  return true;
189  }
190  if( PyFloat_Check(o) )
191  {
192  double v[] = {PyFloat_AsDouble((PyObject*)o), 0., 0., 0.};
193  m = Mat(4, 1, CV_64F, v).clone();
194  return true;
195  }
196  if( PyTuple_Check(o) )
197  {
198  int i, sz = (int)PyTuple_Size((PyObject*)o);
199  m = Mat(sz, 1, CV_64F);
200  for( i = 0; i < sz; i++ )
201  {
202  PyObject* oi = PyTuple_GET_ITEM(o, i);
203  if( PyInt_Check(oi) )
204  m.at<double>(i) = (double)PyInt_AsLong(oi);
205  else if( PyFloat_Check(oi) )
206  m.at<double>(i) = (double)PyFloat_AsDouble(oi);
207  else
208  {
209  failmsg("%s is not a numerical tuple", info.name);
210  m.release();
211  return false;
212  }
213  }
214  return true;
215  }
216 
217  if( !PyArray_Check(o) )
218  {
219  failmsg("%s is not a numpy array, neither a scalar", info.name);
220  return false;
221  }
222 
223  PyArrayObject* oarr = (PyArrayObject*) o;
224 
225  bool needcopy = false, needcast = false;
226  int typenum = PyArray_TYPE(oarr), new_typenum = typenum;
227  int type = typenum == NPY_UBYTE ? CV_8U :
228  typenum == NPY_BYTE ? CV_8S :
229  typenum == NPY_USHORT ? CV_16U :
230  typenum == NPY_SHORT ? CV_16S :
231  typenum == NPY_INT ? CV_32S :
232  typenum == NPY_INT32 ? CV_32S :
233  typenum == NPY_FLOAT ? CV_32F :
234  typenum == NPY_DOUBLE ? CV_64F : -1;
235 
236  if( type < 0 )
237  {
238  if( typenum == NPY_INT64 || typenum == NPY_UINT64 || type == NPY_LONG )
239  {
240  needcopy = needcast = true;
241  new_typenum = NPY_INT;
242  type = CV_32S;
243  }
244  else
245  {
246  failmsg("%s data type = %d is not supported", info.name, typenum);
247  return false;
248  }
249  }
250 
251 #ifndef CV_MAX_DIM
252  const int CV_MAX_DIM = 32;
253 #endif
254 
255  int ndims = PyArray_NDIM(oarr);
256  if(ndims >= CV_MAX_DIM)
257  {
258  failmsg("%s dimensionality (=%d) is too high", info.name, ndims);
259  return false;
260  }
261 
262  int size[CV_MAX_DIM+1];
263  size_t step[CV_MAX_DIM+1];
264  size_t elemsize = CV_ELEM_SIZE1(type);
265  const npy_intp* _sizes = PyArray_DIMS(oarr);
266  const npy_intp* _strides = PyArray_STRIDES(oarr);
267  bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX;
268 
269  for( int i = ndims-1; i >= 0 && !needcopy; i-- )
270  {
271  // these checks handle cases of
272  // a) multi-dimensional (ndims > 2) arrays, as well as simpler 1- and 2-dimensional cases
273  // b) transposed arrays, where _strides[] elements go in non-descending order
274  // c) flipped arrays, where some of _strides[] elements are negative
275  if( (i == ndims-1 && (size_t)_strides[i] != elemsize) ||
276  (i < ndims-1 && _strides[i] < _strides[i+1]) )
277  needcopy = true;
278  }
279 
280  if( ismultichannel && _strides[1] != (npy_intp)elemsize*_sizes[2] )
281  needcopy = true;
282 
283  if (needcopy)
284  {
285  if (info.outputarg)
286  {
287  failmsg("Layout of the output array %s is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)", info.name);
288  return false;
289  }
290 
291  if( needcast ) {
292  o = PyArray_Cast(oarr, new_typenum);
293  oarr = (PyArrayObject*) o;
294  }
295  else {
296  oarr = PyArray_GETCONTIGUOUS(oarr);
297  o = (PyObject*) oarr;
298  }
299 
300  _strides = PyArray_STRIDES(oarr);
301  }
302 
303  for(int i = 0; i < ndims; i++)
304  {
305  size[i] = (int)_sizes[i];
306  step[i] = (size_t)_strides[i];
307  }
308 
309  // handle degenerate case
310  if( ndims == 0) {
311  size[ndims] = 1;
312  step[ndims] = elemsize;
313  ndims++;
314  }
315 
316  if( ismultichannel )
317  {
318  ndims--;
319  type |= CV_MAKETYPE(0, size[2]);
320  }
321 
322  if( ndims > 2 && !allowND )
323  {
324  failmsg("%s has more than 2 dimensions", info.name);
325  return false;
326  }
327 
328  m = Mat(ndims, size, type, PyArray_DATA(oarr), step);
329  m.u = g_numpyAllocator.allocate(o, ndims, size, type, step);
330  m.addref();
331 
332  if( !needcopy )
333  {
334  Py_INCREF(o);
335  }
336  m.allocator = &g_numpyAllocator;
337 
338  return true;
339 }
340 
341 template<>
342 bool pyopencv_to(PyObject* o, Mat& m, const char* name)
343 {
344  return pyopencv_to(o, m, ArgInfo(name, 0));
345 }
346 
347 PyObject* pyopencv_from(const Mat& m)
348 {
349  if( !m.data )
350  Py_RETURN_NONE;
351  Mat temp, *p = (Mat*)&m;
352  if(!p->u || p->allocator != &g_numpyAllocator)
353  {
354  temp.allocator = &g_numpyAllocator;
355  ERRWRAP2(m.copyTo(temp));
356  p = &temp;
357  }
358  PyObject* o = (PyObject*)p->u->userdata;
359  Py_INCREF(o);
360  return o;
361 }
362 
363 int convert_to_CvMat2(const PyObject* o, cv::Mat& m)
364 {
365  pyopencv_to(const_cast<PyObject*>(o), m, "unknown");
366  return 0;
367 }
NumpyAllocator g_numpyAllocator
static PyObject * opencv_error
#define ERRWRAP2(expr)
UMatData * allocate(int dims0, const int *sizes, int type, void *data, size_t *step, int flags, UMatUsageFlags usageFlags) const
void deallocate(UMatData *u) const
int convert_to_CvMat2(const PyObject *o, cv::Mat &m)
f
const MatAllocator * stdAllocator
bool allocate(UMatData *u, int accessFlags, UMatUsageFlags usageFlags) const
PyGILState_STATE _state
bool outputarg
static bool pyopencv_to(PyObject *obj, T &p, const char *name="<unknown>")
static int failmsg(const char *fmt,...)
UMatData * allocate(PyObject *o, int dims, const int *sizes, int type, size_t *step) const
ArgInfo(const char *name_, bool outputarg_)
void allocate(int dims, const int *sizes, int type, int *&refcount, uchar *&datastart, uchar *&data, size_t *step)
const char * name
static PyObject * pyopencv_from(const T &src)
static PyObject * failmsgp(const char *fmt,...)


cv_bridge
Author(s): Patrick Mihelich, James Bowman
autogenerated on Tue Oct 4 2022 02:19:03