45#define NO_IMPORT_ARRAY
46#define PY_ARRAY_UNIQUE_SYMBOL pbcvt_ARRAY_API
52 PyObject * opencv_error =
nullptr;
56 int failmsg(
const char *fmt, ...) {
60 vsnprintf(str,
sizeof(str), fmt, ap);
62 PyErr_SetString(PyExc_TypeError, str);
67 class PyAllowThreads {
69 PyAllowThreads() : _state(PyEval_SaveThread())
72 { PyEval_RestoreThread(_state); }
74 PyThreadState* _state;
79 PyEnsureGIL() : _state(PyGILState_Ensure())
82 { PyGILState_Release(_state); }
84 PyGILState_STATE _state;
87 enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 };
89 class NumpyAllocator :
public MatAllocator
93 { stdAllocator = Mat::getStdAllocator(); }
97 UMatData* allocate(PyObject*
o,
int dims,
const int* sizes,
int type,
size_t* step)
const
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++) step[i] = (
size_t) _strides[i];
103 step[dims - 1] = CV_ELEM_SIZE(type);
104 u->size = sizes[0] * step[0];
109 UMatData* allocate(
int dims0,
const int* sizes,
int type,
void* data,
110 size_t* step, cv::AccessFlag flags, cv::UMatUsageFlags usageFlags)
const
114 CV_Error(Error::StsAssert,
"The data should normally be NULL!");
116 return stdAllocator->allocate(dims0, sizes, type, data, step, flags, usageFlags);
120 int depth = CV_MAT_DEPTH(type);
121 int cn = CV_MAT_CN(type);
122 const int f = (int) (
sizeof(
size_t) / 8);
124 depth == CV_8U ? NPY_UBYTE :
125 depth == CV_8S ? NPY_BYTE :
126 depth == CV_16U ? NPY_USHORT :
127 depth == CV_16S ? NPY_SHORT :
128 depth == CV_32S ? NPY_INT :
129 depth == CV_32F ? NPY_FLOAT :
130 depth == CV_64F ? NPY_DOUBLE :
131 f * NPY_ULONGLONG + (f ^ 1) * NPY_UINT;
133 cv::AutoBuffer<npy_intp> _sizes(dims + 1);
134 for (i = 0; i < dims; i++) _sizes[i] = sizes[i];
135 if (cn > 1) _sizes[dims++] = cn;
136 PyObject*
o = PyArray_SimpleNew(dims, _sizes, typenum);
137 if (!
o) CV_Error_(Error::StsError,
138 (
"The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
139 return allocate(
o, dims0, sizes, type, step);
142 bool allocate(UMatData* u, cv::AccessFlag accessFlags, cv::UMatUsageFlags usageFlags)
const
143 {
return stdAllocator->allocate(u, accessFlags, usageFlags); }
145 void deallocate(UMatData* u)
const
150 PyObject*
o = (PyObject*) u->userdata;
156 const MatAllocator* stdAllocator;
160 NumpyAllocator g_numpyAllocator;
164 PyObject* fromMatToNDArray(
const Mat& m)
166 if (!m.data) Py_RETURN_NONE;
167 Mat temp, *p = (Mat*) &m;
168 if (!p->u || p->allocator != &g_numpyAllocator)
170 temp.allocator = &g_numpyAllocator;
174 PyObject*
o = (PyObject*) p->u->userdata;
179 Mat fromNDArrayToMat(PyObject*
o)
183 if (!PyArray_Check(
o))
185 failmsg(
"argument is not a numpy array");
186 if (!m.data) m.allocator = &g_numpyAllocator;
190 PyArrayObject* oarr = (PyArrayObject*)
o;
192 bool needcopy =
false, needcast =
false;
193 int typenum = PyArray_TYPE(oarr), new_typenum = typenum;
194 int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S :
195 typenum == NPY_USHORT ? CV_16U :
196 typenum == NPY_SHORT ? CV_16S :
197 typenum == NPY_INT ? CV_32S :
198 typenum == NPY_INT32 ? CV_32S :
199 typenum == NPY_FLOAT ? CV_32F :
200 typenum == NPY_DOUBLE ? CV_64F : -1;
203 if (typenum == NPY_INT64 || typenum == NPY_UINT64 || type == NPY_LONG) {
204 needcopy = needcast =
true;
205 new_typenum = NPY_INT;
208 failmsg(
"Argument data type is not supported");
209 m.allocator = &g_numpyAllocator;
215 const int CV_MAX_DIM = 32;
218 int ndims = PyArray_NDIM(oarr);
219 if (ndims >= CV_MAX_DIM) {
220 failmsg(
"Dimensionality of argument is too high");
221 if (!m.data) m.allocator = &g_numpyAllocator;
225 int size[CV_MAX_DIM + 1];
226 size_t step[CV_MAX_DIM + 1];
227 size_t elemsize = CV_ELEM_SIZE1(type);
228 const npy_intp* _sizes = PyArray_DIMS(oarr);
229 const npy_intp* _strides = PyArray_STRIDES(oarr);
230 bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX;
232 for (
int i = ndims - 1; i >= 0 && !needcopy; i--)
238 if ((i == ndims - 1 && (
size_t) _strides[i] != elemsize) || (i < ndims - 1 && _strides[i] < _strides[i + 1]))
242 if (ismultichannel && _strides[1] != (npy_intp) elemsize * _sizes[2]) needcopy =
true;
248 o = PyArray_Cast(oarr, new_typenum);
249 oarr = (PyArrayObject*)
o;
253 oarr = PyArray_GETCONTIGUOUS(oarr);
254 o = (PyObject*) oarr;
257 _strides = PyArray_STRIDES(oarr);
260 for (
int i = 0; i < ndims; i++) { size[i] = (int) _sizes[i]; step[i] = (size_t) _strides[i]; }
263 if (ndims == 0) { size[ndims] = 1; step[ndims] = elemsize; ndims++; }
265 if (ismultichannel) { ndims--; type |= CV_MAKETYPE(0, size[2]); }
267 if (ndims > 2 && !allowND) {
268 failmsg(
"%s has more than 2 dimensions");
270 m = Mat(ndims, size, type, PyArray_DATA(oarr), step);
271 m.u = g_numpyAllocator.allocate(
o, ndims, size, type, step);
278 m.allocator = &g_numpyAllocator;
284 PyObject* matToNDArrayBoostConverter::convert(Mat
const& m) {
289 if (!p->u || p->allocator != &g_numpyAllocator)
291 temp.allocator = &g_numpyAllocator;
295 PyObject*
o = (PyObject*) p->u->userdata;
300 matFromNDArrayBoostConverter::matFromNDArrayBoostConverter()
302 boost::python::converter::registry::push_back(convertible, construct, boost::python::type_id<Mat>());
306 void* matFromNDArrayBoostConverter::convertible(PyObject*
object)
308 if (!PyArray_Check(
object)) {
312 const int CV_MAX_DIM = 32;
314 PyArrayObject* oarr = (PyArrayObject*)
object;
316 int typenum = PyArray_TYPE(oarr);
317 if (typenum != NPY_INT64 && typenum != NPY_UINT64 && typenum != NPY_LONG
318 && typenum != NPY_UBYTE && typenum != NPY_BYTE
319 && typenum != NPY_USHORT && typenum != NPY_SHORT
320 && typenum != NPY_INT && typenum != NPY_INT32
321 && typenum != NPY_FLOAT && typenum != NPY_DOUBLE) {
324 int ndims = PyArray_NDIM(oarr);
326 if (ndims >= CV_MAX_DIM) {
333 void matFromNDArrayBoostConverter::construct(PyObject*
object,
334 boost::python::converter::rvalue_from_python_stage1_data* data) {
335 namespace python = boost::python;
337 python::handle<> handle(python::borrowed(
object));
340 typedef python::converter::rvalue_from_python_storage<Mat> storage_type;
341 void* storage =
reinterpret_cast<storage_type*
>(data)->storage.bytes;
346 PyArrayObject* oarr = (PyArrayObject*)
object;
348 bool needcopy =
false, needcast =
false;
349 int typenum = PyArray_TYPE(oarr), new_typenum = typenum;
350 int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S :
351 typenum == NPY_USHORT ? CV_16U :
352 typenum == NPY_SHORT ? CV_16S :
353 typenum == NPY_INT ? CV_32S :
354 typenum == NPY_INT32 ? CV_32S :
355 typenum == NPY_FLOAT ? CV_32F :
356 typenum == NPY_DOUBLE ? CV_64F : -1;
359 needcopy = needcast =
true;
360 new_typenum = NPY_INT;
365 const int CV_MAX_DIM = 32;
367 int ndims = PyArray_NDIM(oarr);
369 int size[CV_MAX_DIM + 1];
370 size_t step[CV_MAX_DIM + 1];
371 size_t elemsize = CV_ELEM_SIZE1(type);
372 const npy_intp* _sizes = PyArray_DIMS(oarr);
373 const npy_intp* _strides = PyArray_STRIDES(oarr);
374 bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX;
376 for (
int i = ndims - 1; i >= 0 && !needcopy; i--) {
381 if ((i == ndims - 1 && (
size_t) _strides[i] != elemsize)
382 || (i < ndims - 1 && _strides[i] < _strides[i + 1]))
386 if (ismultichannel && _strides[1] != (npy_intp) elemsize * _sizes[2])
392 object = PyArray_Cast(oarr, new_typenum);
393 oarr = (PyArrayObject*)
object;
395 oarr = PyArray_GETCONTIGUOUS(oarr);
396 object = (PyObject*) oarr;
399 _strides = PyArray_STRIDES(oarr);
402 for (
int i = 0; i < ndims; i++) {
403 size[i] = (int) _sizes[i];
404 step[i] = (size_t) _strides[i];
410 step[ndims] = elemsize;
414 if (ismultichannel) {
416 type |= CV_MAKETYPE(0, size[2]);
422 cv::Mat* m =
new (storage) cv::Mat(ndims, size, type, PyArray_DATA(oarr), step);
423 m->u = g_numpyAllocator.allocate(
object, ndims, size, type, step);
424 m->allocator = &g_numpyAllocator;
426 data->convertible = storage;