module_opencv4.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 
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 #if CV_MAJOR_VERSION == 3
94 protected:
95  typedef int AccessFlag;
96 #endif
97 
98 public:
99  NumpyAllocator() { stdAllocator = Mat::getStdAllocator(); }
101 
102  UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const
103  {
104  UMatData* u = new UMatData(this);
105  u->data = u->origdata = (uchar*)PyArray_DATA((PyArrayObject*) o);
106  npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o);
107  for( int i = 0; i < dims - 1; i++ )
108  step[i] = (size_t)_strides[i];
109  step[dims-1] = CV_ELEM_SIZE(type);
110  u->size = sizes[0]*step[0];
111  u->userdata = o;
112  return u;
113  }
114 
115  UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, AccessFlag flags, UMatUsageFlags usageFlags) const
116  {
117  if( data != 0 )
118  {
119  CV_Error(Error::StsAssert, "The data should normally be NULL!");
120  // probably this is safe to do in such extreme case
121  return stdAllocator->allocate(dims0, sizes, type, data, step, flags, usageFlags);
122  }
123  PyEnsureGIL gil;
124 
125  int depth = CV_MAT_DEPTH(type);
126  int cn = CV_MAT_CN(type);
127  const int f = (int)(sizeof(size_t)/8);
128  int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
129  depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
130  depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
131  depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
132  int i, dims = dims0;
133  cv::AutoBuffer<npy_intp> _sizes(dims + 1);
134  for( i = 0; i < dims; i++ )
135  _sizes[i] = sizes[i];
136  if( cn > 1 )
137  _sizes[dims++] = cn;
138  PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum);
139  if(!o)
140  CV_Error_(Error::StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
141  return allocate(o, dims0, sizes, type, step);
142  }
143 
144  bool allocate(UMatData* u, AccessFlag accessFlags, UMatUsageFlags usageFlags) const
145  {
146  return stdAllocator->allocate(u, accessFlags, usageFlags);
147  }
148 
149  void deallocate(UMatData* u) const
150  {
151  if(u)
152  {
153  PyEnsureGIL gil;
154  PyObject* o = (PyObject*)u->userdata;
155  Py_XDECREF(o);
156  delete u;
157  }
158  }
159 
160  const MatAllocator* stdAllocator;
161 };
162 
164 
165 
166 template<typename T> static
167 bool pyopencv_to(PyObject* obj, T& p, const char* name = "<unknown>");
168 
169 template<typename T> static
170 PyObject* pyopencv_from(const T& src);
171 
172 enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 };
173 
174 // special case, when the convertor needs full ArgInfo structure
175 static bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo info)
176 {
177  // to avoid PyArray_Check() to crash even with valid array
178  do_numpy_import( );
179 
180 
181  bool allowND = true;
182  if(!o || o == Py_None)
183  {
184  if( !m.data )
185  m.allocator = &g_numpyAllocator;
186  return true;
187  }
188 
189  if( PyInt_Check(o) )
190  {
191  double v[] = {(double)PyInt_AsLong((PyObject*)o), 0., 0., 0.};
192  m = Mat(4, 1, CV_64F, v).clone();
193  return true;
194  }
195  if( PyFloat_Check(o) )
196  {
197  double v[] = {PyFloat_AsDouble((PyObject*)o), 0., 0., 0.};
198  m = Mat(4, 1, CV_64F, v).clone();
199  return true;
200  }
201  if( PyTuple_Check(o) )
202  {
203  int i, sz = (int)PyTuple_Size((PyObject*)o);
204  m = Mat(sz, 1, CV_64F);
205  for( i = 0; i < sz; i++ )
206  {
207  PyObject* oi = PyTuple_GET_ITEM(o, i);
208  if( PyInt_Check(oi) )
209  m.at<double>(i) = (double)PyInt_AsLong(oi);
210  else if( PyFloat_Check(oi) )
211  m.at<double>(i) = (double)PyFloat_AsDouble(oi);
212  else
213  {
214  failmsg("%s is not a numerical tuple", info.name);
215  m.release();
216  return false;
217  }
218  }
219  return true;
220  }
221 
222  if( !PyArray_Check(o) )
223  {
224  failmsg("%s is not a numpy array, neither a scalar", info.name);
225  return false;
226  }
227 
228  PyArrayObject* oarr = (PyArrayObject*) o;
229 
230  bool needcopy = false, needcast = false;
231  int typenum = PyArray_TYPE(oarr), new_typenum = typenum;
232  int type = typenum == NPY_UBYTE ? CV_8U :
233  typenum == NPY_BYTE ? CV_8S :
234  typenum == NPY_USHORT ? CV_16U :
235  typenum == NPY_SHORT ? CV_16S :
236  typenum == NPY_INT ? CV_32S :
237  typenum == NPY_INT32 ? CV_32S :
238  typenum == NPY_FLOAT ? CV_32F :
239  typenum == NPY_DOUBLE ? CV_64F : -1;
240 
241  if( type < 0 )
242  {
243  if( typenum == NPY_INT64 || typenum == NPY_UINT64 || type == NPY_LONG )
244  {
245  needcopy = needcast = true;
246  new_typenum = NPY_INT;
247  type = CV_32S;
248  }
249  else
250  {
251  failmsg("%s data type = %d is not supported", info.name, typenum);
252  return false;
253  }
254  }
255 
256 #ifndef CV_MAX_DIM
257  const int CV_MAX_DIM = 32;
258 #endif
259 
260  int ndims = PyArray_NDIM(oarr);
261  if(ndims >= CV_MAX_DIM)
262  {
263  failmsg("%s dimensionality (=%d) is too high", info.name, ndims);
264  return false;
265  }
266 
267  int size[CV_MAX_DIM+1];
268  size_t step[CV_MAX_DIM+1];
269  size_t elemsize = CV_ELEM_SIZE1(type);
270  const npy_intp* _sizes = PyArray_DIMS(oarr);
271  const npy_intp* _strides = PyArray_STRIDES(oarr);
272  bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX;
273 
274  for( int i = ndims-1; i >= 0 && !needcopy; i-- )
275  {
276  // these checks handle cases of
277  // a) multi-dimensional (ndims > 2) arrays, as well as simpler 1- and 2-dimensional cases
278  // b) transposed arrays, where _strides[] elements go in non-descending order
279  // c) flipped arrays, where some of _strides[] elements are negative
280  if( (i == ndims-1 && (size_t)_strides[i] != elemsize) ||
281  (i < ndims-1 && _strides[i] < _strides[i+1]) )
282  needcopy = true;
283  }
284 
285  if( ismultichannel && _strides[1] != (npy_intp)elemsize*_sizes[2] )
286  needcopy = true;
287 
288  if (needcopy)
289  {
290  if (info.outputarg)
291  {
292  failmsg("Layout of the output array %s is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)", info.name);
293  return false;
294  }
295 
296  if( needcast ) {
297  o = PyArray_Cast(oarr, new_typenum);
298  oarr = (PyArrayObject*) o;
299  }
300  else {
301  oarr = PyArray_GETCONTIGUOUS(oarr);
302  o = (PyObject*) oarr;
303  }
304 
305  _strides = PyArray_STRIDES(oarr);
306  }
307 
308  for(int i = 0; i < ndims; i++)
309  {
310  size[i] = (int)_sizes[i];
311  step[i] = (size_t)_strides[i];
312  }
313 
314  // handle degenerate case
315  if( ndims == 0) {
316  size[ndims] = 1;
317  step[ndims] = elemsize;
318  ndims++;
319  }
320 
321  if( ismultichannel )
322  {
323  ndims--;
324  type |= CV_MAKETYPE(0, size[2]);
325  }
326 
327  if( ndims > 2 && !allowND )
328  {
329  failmsg("%s has more than 2 dimensions", info.name);
330  return false;
331  }
332 
333  m = Mat(ndims, size, type, PyArray_DATA(oarr), step);
334  m.u = g_numpyAllocator.allocate(o, ndims, size, type, step);
335  m.addref();
336 
337  if( !needcopy )
338  {
339  Py_INCREF(o);
340  }
341  m.allocator = &g_numpyAllocator;
342 
343  return true;
344 }
345 
346 template<>
347 bool pyopencv_to(PyObject* o, Mat& m, const char* name)
348 {
349  return pyopencv_to(o, m, ArgInfo(name, 0));
350 }
351 
352 PyObject* pyopencv_from(const Mat& m)
353 {
354  if( !m.data )
355  Py_RETURN_NONE;
356  Mat temp, *p = (Mat*)&m;
357  if(!p->u || p->allocator != &g_numpyAllocator)
358  {
359  temp.allocator = &g_numpyAllocator;
360  ERRWRAP2(m.copyTo(temp));
361  p = &temp;
362  }
363  PyObject* o = (PyObject*)p->u->userdata;
364  Py_INCREF(o);
365  return o;
366 }
367 
368 int convert_to_CvMat2(const PyObject* o, cv::Mat& m)
369 {
370  pyopencv_to(const_cast<PyObject*>(o), m, "unknown");
371  return 0;
372 }
NumpyAllocator::allocate
UMatData * allocate(PyObject *o, int dims, const int *sizes, int type, size_t *step) const
Definition: module_opencv4.cpp:102
NumpyAllocator::deallocate
void deallocate(UMatData *u) const
Definition: module_opencv4.cpp:149
PyAllowThreads::PyAllowThreads
PyAllowThreads()
Definition: module_opencv4.cpp:43
ArgInfo::ArgInfo
ArgInfo(const char *name_, bool outputarg_)
Definition: module_opencv4.cpp:32
NumpyAllocator::allocate
bool allocate(UMatData *u, AccessFlag accessFlags, UMatUsageFlags usageFlags) const
Definition: module_opencv4.cpp:144
convert_to_CvMat2
int convert_to_CvMat2(const PyObject *o, cv::Mat &m)
Definition: module_opencv4.cpp:368
NumpyAllocator::stdAllocator
const MatAllocator * stdAllocator
Definition: module_opencv4.cpp:160
PyAllowThreads
Definition: module_opencv4.cpp:40
PyAllowThreads::_state
PyThreadState * _state
Definition: module_opencv4.cpp:49
NumpyAllocator::~NumpyAllocator
~NumpyAllocator()
Definition: module_opencv4.cpp:100
pyopencv_from
static PyObject * pyopencv_from(const T &src)
f
f
opencv_error
static PyObject * opencv_error
Definition: module_opencv4.cpp:11
pyopencv_to
static bool pyopencv_to(PyObject *obj, T &p, const char *name="<unknown>")
g_numpyAllocator
NumpyAllocator g_numpyAllocator
Definition: module_opencv4.cpp:163
ARG_MAT
@ ARG_MAT
Definition: module_opencv4.cpp:172
PyEnsureGIL::_state
PyGILState_STATE _state
Definition: module_opencv4.cpp:61
ARG_NONE
@ ARG_NONE
Definition: module_opencv4.cpp:172
PyAllowThreads::~PyAllowThreads
~PyAllowThreads()
Definition: module_opencv4.cpp:44
NumpyAllocator
Definition: module_opencv4.cpp:91
failmsg
static int failmsg(const char *fmt,...)
Definition: module_opencv4.cpp:13
ArgInfo::name
const char * name
Definition: module_opencv4.cpp:28
ERRWRAP2
#define ERRWRAP2(expr)
Definition: module_opencv4.cpp:64
failmsgp
static PyObject * failmsgp(const char *fmt,...)
Definition: module_opencv4.cpp:78
ArgInfo
Definition: module_opencv4.cpp:26
PyEnsureGIL::PyEnsureGIL
PyEnsureGIL()
Definition: module_opencv4.cpp:55
NumpyAllocator::NumpyAllocator
NumpyAllocator()
Definition: module_opencv4.cpp:99
PyEnsureGIL::~PyEnsureGIL
~PyEnsureGIL()
Definition: module_opencv4.cpp:56
NumpyAllocator::allocate
UMatData * allocate(int dims0, const int *sizes, int type, void *data, size_t *step, AccessFlag flags, UMatUsageFlags usageFlags) const
Definition: module_opencv4.cpp:115
ArgInfo::outputarg
bool outputarg
Definition: module_opencv4.cpp:29
ARG_SCALAR
@ ARG_SCALAR
Definition: module_opencv4.cpp:172
PyEnsureGIL
Definition: module_opencv4.cpp:52


cv_bridge
Author(s): Patrick Mihelich, James Bowman
autogenerated on Mon Oct 3 2022 02:45:56